Komputer gra w sapera

Komputer gra w sapera
PO
  • Rejestracja:około 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:około rok
  • 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:około 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 :/

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.