Komputer gra w sapera

Komputer gra w sapera
PO
  • Rejestracja:prawie 9 lat
  • Ostatnio:ponad 6 lat
  • Postów:10
0

Witam wszystkich,
ostatnio napisałem w C++ projekt - sapera. Wszystko świetnie działa ale chciałem go zmodyfikować tak, aby plansze rozwiązał komputer(zawsze wygrywa). Chciałbym Was prosić o pomoc z wymyśleniem najlepszego schematu takie programu. Plansza jest tablicą dwuwymiarową dynamiczną o ilości min i wielkości podanej przez gracza. Każde pole zawiera informację o tym czy jest zakryte czy nie oraz liczbą min dookoła niego. Myślałem o tym by komputer szedł wierszami aż nie znajdzie pola odkrytego z liczbą inną niż 0 i wtedy rozpatruje obszar wokół niego ale wydaje mi się to żmudne i długie( duża ilość opcji - warunków if). Macie pomysł jak najlepiej się za to zabrać?Czy w ogóle da się za to inaczej zabrać?
Pozdrawiam serdecznie i wszystkie pomysły mile widziane :),
początkujący programista.

J2
Nie da rady by zawsze wygrywał, a co jak w pierwszym ruchu będzie mina?
PO
No dobra, załóżmy, że pierwszy ruch to loteria ale potem już ma możliwość wygrania.
0

Komputer nie wygra za każdym razem ponieważ może trafić przy 1 razie na minę, a 1 kwadrat też mu nic nie da.
Jeśli oczywiście chcesz to zrobić niby uczciwie.(Komputer nie zna wartości pól, niby)
Ja bym to zrobił tak:
-Komputer randomowo odkrywa 3 pola obok siebie - wtedy zdobywa już jakieś pole to manewru.
-funkcja czytająca odkryte pola(i sprawdzająca ile miejsc w pobliżu ma odkrytych, jeżeli zostaje tylko tyle pól nieodkrytych co wartość pola to stawia tam bomby, a jeśli w pobliżu kwadracie o jakiejś tam wartości jest już tyle bomb jaka jest wartość to odkrywa sąsiednie pola tego pola.
Wszystko odświeża się cały czas i cały czas sczytuję obecne wartości pól.
Powinno zadziałać.

PO
No tak, ale co w przypadku gdy ilość pół nieodkrytych jest większa od wartości pola? Wtedy musi na podstawie innych pól w okolicy oszacować które pola może odkryć a które to miny. Jak wstępnie próbowałem to zrobić to wyszło mi strasznie dużo przypadków i możliwości. Może nie da się inaczej tego napisać niż rozpatrując wszystkie możliwości ale za każdy pomysł skracający czas pracy będę wdzięczny :D.
0

Hmm, grałeś kiedyś w sapera? ;p Zagraj troszkę i zobacz jak to działa, bardzo prosto.

No tak, ale co w przypadku gdy ilość pół nieodkrytych jest większa od wartości pola?

funkcja sprawdza wszystkie pola, więc dla któregoś na pewno postawi bombę i znów sprawdza wszystkie(z nowymi wiadomościami jakie posiada) i tak ect.
Rozumiesz? ;p

0

Jeżeli już zacznie działać tak jak opisałem to nie wiem co by musiało się zdarzyć żeby tak robiąc komputer nie miał gdzie postawić bomby, jest to wręcz niemożliwe... naprawdę, pograj troszkę w sapera, przeczytaj to co napisałem i zastanów się nad tym...
Saper to banalna gra, i ktoś to już wie jak działa może przy szczęściu że nie trafi bomby na starcie wygrać bez problemu.
Radzę ci pograć ale przy tym zastanawiaj się jak to działa i ogarniesz o co chodzi ;)

PO
Rzeczywiście, jeszcze raz przeczytałem i to powinno się udać :D. Za pierwszym razem troszkę źle to sobie wyobraziłem :) dzięki za pomoc. Jutro siadam do pisania ;)
katecpp
  • Rejestracja:ponad 9 lat
  • Ostatnio:11 miesięcy
  • Postów:27
0

Moim zdaniem w saperze nie powinno być możliwości wybrania bomby na starcie (i tak chyba jest w większości popularnych implementacji? - nie mogę sprawdzić.) W każdym razie - wracając do implementacji samego sapera - można wypełnić planszę bombami dopiero po pierwszym odsłonięciu pola przez użytkownika, z pominięciem tego odsłoniętego pola. Wtedy nie da się przegrać po jednym ruchu.

Zobacz pozostały 1 komentarz
katecpp
Nie zgadzam się, wg mnie plansza jest generowana po pierwszym kliknięciu. Przetestowałam zachowanie na Windows 7 Minesweeper. Przy 67 minach i planszy 9x9 nie udało mi się nigdy trafić w minę za pierwszym razem - co innego kiedy daję "Restart this game", wtedy bomby już są rozmieszczone.
ShookTea
Potwierdzam - na Windzie plansza jest generowana dopiero po kliknięciu, by pierwsze pole było zawsze puste. "Tak czytałem" :P
MarekR22
Ostatni Miniswipera grałem na Win XP, może coś zmienili i dają fory graczowi w pierwszym kliknięciu. 67 min przy 81 polach to troszkę podejrzane. By gra była grywalna min musi być zdecydowanie mniej niż połowa planszy.
katecpp
67/81 to maksymalne zagęszczenie min jakie da się się ustawić na Win7 - co do niegrywalności to nie będę się sprzeczać :).
ShookTea
Chodziło tu o sprawdzenie. Jest ich całkiem sporo, ale nigdy nie trafisz w minę za pierwszym razem.
PO
  • Rejestracja:prawie 9 lat
  • Ostatnio:ponad 6 lat
  • Postów:10
0

Wątpię, (a nawet bardzo wątpię :)) by komuś się chciało to wszystko sprawdzać ale jak ktoś ma ochotę to byłbym bardzo wdzięczny o rzucenie okiem czy w ogóle dobrze się za to zabrałem. Generowanie planszy, ustawianie min itd działa bardzo dobrze, chodzi mi tylko o rozwiązanie planszy przez komputer.Wiem, że kod jest beznadziejny pod względem trudności, wyglądu, sposobu pisania ale zacząłem programować dopiero od niedawana i wciąż się uczę więc za to z góry przepraszam. Parametry kodu:
nowagra1 zawiera tylko informacje o wymiarach tablicy oraz ilości min (podane przez użytkownika).
t- tablica dwuwymiarowa struktur (pole to struktura o informacji odkryte(bool), wartość pola).

Kopiuj
void odkryj_plansze(pola** t, int x, int y, nowagra& nowagra1)
{
    if (x < 0 || x > nowagra1.N - 1)
        return; // poza tablicą wyjście
    if (y < 0 || y > nowagra1.M - 1)
        return; // poza tablicą wyjście
    if (t[x][y].odkryte)
        return; // już odkryte wyjście

    if (t[x][y].wartosc != 9 && t[x][y].odkryte == false)
        t[x][y].odkryte = true; // odkryj!

    if (t[x][y].wartosc != 0)
        return; // wartość > 0 wyjście

    //wywołanie funkcji dla każdego sąsiada
    odkryj_plansze(t, x - 1, y - 1, nowagra1);
    odkryj_plansze(t, x - 1, y, nowagra1);
    odkryj_plansze(t, x - 1, y + 1, nowagra1);
    odkryj_plansze(t, x + 1, y - 1, nowagra1);
    odkryj_plansze(t, x + 1, y, nowagra1);
    odkryj_plansze(t, x + 1, y + 1, nowagra1);
    odkryj_plansze(t, x, y - 1, nowagra1);
    odkryj_plansze(t, x, y, nowagra1);
    odkryj_plansze(t, x, y + 1, nowagra1);
}
bool sprawdzczyzakryte(pola** t, int x, int y, nowagra nowagra1) //sprawdza czy pole jest zakryte
{
    bool sprawdz = true;
    if (x < 0 || x > nowagra1.N - 1)
        return sprawdz; // poza tablicą wyjście
    if (y < 0 || y > nowagra1.M - 1)
        return sprawdz; // poza tablicą wyjście
    if (t[x][y].odkryte)
        sprawdz = true;
    else
        sprawdz = false;
    return sprawdz;
}
int ilepol(pola** t, int x, int y, nowagra nowagra1) //liczy ile pól obok danego pola jest zakrytych
{
    int licza = 0;
    if (!sprawdzczyzakryte(t, x + 1, y, nowagra1))
        licza++;
    if (!sprawdzczyzakryte(t, x - 1, y - 1, nowagra1))
        licza++;
    if (!sprawdzczyzakryte(t, x - 1, y, nowagra1))
        licza++;
    if (!sprawdzczyzakryte(t, x - 1, y + 1, nowagra1))
        licza++;
    if (!sprawdzczyzakryte(t, x + 1, y - 1, nowagra1))
        licza++;
    if (!sprawdzczyzakryte(t, x + 1, y + 1, nowagra1))
        licza++;
    if (!sprawdzczyzakryte(t, x, y - 1, nowagra1))
        licza++;
    if (!sprawdzczyzakryte(t, x - 1, y + 1, nowagra1))
        licza++;
    return licza;
}
bool sprawdzczyminy(pola** t, int x, int y, nowagra nowagra1) //sprawdza czy to mina
{
    bool sprawdz = true;
    if (x < 0 || x > nowagra1.N - 1)
        return sprawdz; // poza tablicą wyjście
    if (y < 0 || y > nowagra1.M - 1)
        return sprawdz; // poza tablicą wyjście
    if (t[x][y].wartosc == 10)
        sprawdz = true;
    else
        sprawdz = false;
    return sprawdz;
}

int ilemin(pola** t, int x, int y, nowagra nowagra1) //liczy ile min jest obok danego pola
{
    int mina = 0;
    if (!sprawdzczyminy(t, x + 1, y, nowagra1))
        mina++;
    if (!sprawdzczyminy(t, x - 1, y - 1, nowagra1))
        mina++;
    if (!sprawdzczyminy(t, x - 1, y, nowagra1))
        mina++;
    if (!sprawdzczyminy(t, x - 1, y + 1, nowagra1))
        mina++;
    if (!sprawdzczyminy(t, x + 1, y - 1, nowagra1))
        mina++;
    if (!sprawdzczyminy(t, x + 1, y + 1, nowagra1))
        mina++;
    if (!sprawdzczyminy(t, x, y - 1, nowagra1))
        mina++;
    if (!sprawdzczyminy(t, x - 1, y + 1, nowagra1))
        mina++;
    return mina;
}

void zaznaczminy(pola** t, int x, int y, nowagra nowagra1) //zaznacza mine
{
    if (x < 0 || x > nowagra1.N - 1)
        return; // poza tablicą wyjście
    if (y < 0 || y > nowagra1.M - 1)
        return; // poza tablicą wyjście
    if (!t[x][y].odkryte) {
        t[x][y].odkryte = true;
        t[x][y].wartosc = 10;
    }
    zaznaczminy(t, x - 1, y - 1, nowagra1);
    zaznaczminy(t, x - 1, y, nowagra1);
    zaznaczminy(t, x - 1, y + 1, nowagra1);
    zaznaczminy(t, x + 1, y - 1, nowagra1);
    zaznaczminy(t, x + 1, y, nowagra1);
    zaznaczminy(t, x + 1, y + 1, nowagra1);
    zaznaczminy(t, x, y - 1, nowagra1);
    zaznaczminy(t, x, y + 1, nowagra1);
}
void zmienwartosc(pola** t, int x, int y, nowagra nowagra1) // zmniejsza wartość pól wokół których zaznaczono mine
{
    if (x < 0 || x > nowagra1.N - 1)
        return; // poza tablicą wyjście
    if (y < 0 || y > nowagra1.M - 1)
        return; // poza tablicą wyjście
    if (t[x][y].odkryte && t[x][y].wartosc != 10 && t[x][y].wartosc != 0) {

        t[x][y].wartosc--;
    }
    zmienwartosc(t, x - 1, y - 1, nowagra1);
    zmienwartosc(t, x - 1, y, nowagra1);
    zmienwartosc(t, x - 1, y + 1, nowagra1);
    zmienwartosc(t, x + 1, y - 1, nowagra1);
    zmienwartosc(t, x + 1, y, nowagra1);
    zmienwartosc(t, x + 1, y + 1, nowagra1);
    zmienwartosc(t, x, y - 1, nowagra1);
    zmienwartosc(t, x, y + 1, nowagra1);
}
void odkryjpola(pola** t, int x, int y, nowagra nowagra1) // odkrywa pola (obszarowo jak w saperze)
{

    odkryj_plansze(t, x - 1, y - 1, nowagra1);
    odkryj_plansze(t, x - 1, y, nowagra1);
    odkryj_plansze(t, x - 1, y + 1, nowagra1);
    odkryj_plansze(t, x + 1, y - 1, nowagra1);
    odkryj_plansze(t, x + 1, y, nowagra1);
    odkryj_plansze(t, x + 1, y + 1, nowagra1);
    odkryj_plansze(t, x, y - 1, nowagra1);
    odkryj_plansze(t, x, y + 1, nowagra1);
}

void komp(pola** t, nowagra nowagra1) // głowna funckja
{

    int miny = 0;
    int liczba = 0;
    odkryj_plansze(t, 0, 0, nowagra1); //odkrywa pierwsze pole (pierwszy ruch)
    liczba = ilepol(t, 0, 0, nowagra1); //liczy ile jest obok niego zasłoniętych
    if (liczba > 1) //jeżeli nie ma przynajmniej dwóch odsłoniętych to odkrywa randomowe obok - jest możliwość wejscia na mine.
    // by tablica się wypełniała po pierwszym kliknieciu ale na razie chce aby przynajmniej tak działo.
    {
        odkryj_plansze(t, 1, 0, nowagra1);
        odkryj_plansze(t, 0, 1, nowagra1);
        liczba = 0;
    }
    else // jezeli 1 ruch odslonil obszar
    {
        liczba = 0;
        bool koniec;
        koniec = false;

        while (!koniec) // aż sie nie skonczy gra
        {

            for (int i = 0; i < nowagra1.N; ++i) //  ustawienie min na całej tablicy - tam gdzie są na pewno.
            {
                for (int j = 0; j < nowagra1.M; ++j) {
                    if (t[i][j].odkryte) {
                        liczba = ilepol(t, i, j, nowagra1); //ile pol zakrytych w sąsiedzwie tego pola
                        if (liczba == t[i][j].wartosc) // jezeli tyle samo co wartosc pola to znaczy ze sa to miny
                        {
                            zaznaczminy(t, i, j, nowagra1);
                            liczba = 0;
                        }
                        miny = ilemin(t, i, j, nowagra1); //jezeli min obok pola jest tyle samo co liczba pola to mozna odslonic reszte pol zakrytych
                        if (t[i][j].wartosc == miny) {
                            odkryjpola(t, i, j, nowagra1);
                            miny = 0;
                        }
                    }
                    else
                        break;
                }
            }
            for (int i = 0; i < nowagra1.N; ++i) // zmniejszenie liczby pol
            {
                for (int j = 0; j < nowagra1.M; ++j) {
                    if (t[i][j].wartosc == 10)
                        zmienwartosc(t, i, j, nowagra1);
                }
            }

            if (czy_wygrana(t, nowagra1))
                koniec = true;
        }
    } 

Jeżeli ktoś ma ochotę i czas to zapraszam do komentowania.

MarekR22
Na szybkiego: napisane tak, by trudno było zrozumieć. Podziel komp na kilka mniejszych funkcji. Liczby magiczne.
PO
Liczba 10 oznacza pole które zostało oznaczone "flagą" jeżeli o to chodzi :).Funkcje komp próbuję przerobić ale wciąż coś nie gra. Kod się kompiluje i kończy ale nie wyświetla efektu czyli -nie działa :/
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)