Budowa i generowanie planszy

Podobne dokumenty
Podstawy programowania, Poniedziałek , 8-10 Projekt, część 1

Podstawy programowania, Poniedziałek , 8-10 Projekt, część 3

Zajęcia nr 2 Programowanie strukturalne. dr inż. Łukasz Graczykowski mgr inż. Leszek Kosarzewski Wydział Fizyki Politechniki Warszawskiej

4. Funkcje. Przykłady

Pętla for. Wynik działania programu:

lekcja 8a Gry komputerowe MasterMind

Podstawy Programowania Podstawowa składnia języka C++

void Pobierz(Student &a); void Wypisz(Student a); void Ustaw_zaliczenia(Student t[],int r); void Wypisz_najlepszych(Student t[],int r, float prog);

Informacje wstępne #include <nazwa> - derektywa procesora umożliwiająca włączenie do programu pliku o podanej nazwie. Typy danych: char, signed char

INSTRUKCJE REPETYCYJNE PĘTLE

Proste programy w C++ zadania

Podstawy języka C++ Maciej Trzebiński. Instytut Fizyki Jądrowej Polskiej Akademii Nauk. Praktyki studenckie na LHC IVedycja,2016r.

Podstawy Programowania C++

Programowanie - wykład 4

Ćwiczenie 7 z Podstaw programowania. Język C++, programy pisane w nieobiektowym stylu programowania. Zofia Kruczkiewicz

Układy VLSI Bramki 1.0

1 Podstawy c++ w pigułce.

Deklaracja struktury w C++

Obliczenie pola wieloboku na podstawie współrzędnych wierzchołków

1 Podstawy c++ w pigułce.

Pliki wykład 2. Dorota Pylak

Informatyka I. Wykład 3. Sterowanie wykonaniem programu. Instrukcje warunkowe Instrukcje pętli. Dr inż. Andrzej Czerepicki

1 Wielokrotne powtarzanie tych samych operacji

Instrukcje sterujące mgr Tomasz Xięski, Instytut Informatyki, Uniwersytet Śląski Katowice, 2012

Wstęp do programowania

Podstawy programowania. Wykład: 5. Instrukcje sterujące c.d. Stałe, Typy zmiennych c.d. dr Artur Bartoszewski -Podstawy programowania, sem 1 - WYKŁAD

Konstrukcje warunkowe Pętle

Wstęp do programowania

Program 14. #include <iostream> #include <ctime> using namespace std;

8. Wektory. Przykłady Napisz program, który pobierze od użytkownika 10 liczb, a następnie wypisze je w kolejności odwrotnej niż podana.

Program znajduje największa lub najmniejsza z podanych liczb. Liczby podajemy dopóki nam sie nie znudzi.

Liczby losowe i pętla while w języku Python

7. Pętle for. Przykłady

Projekty zaliczeniowe Podstawy Programowania 2012/2013

Język C++ zajęcia nr 2

Język JAVA podstawy. Wykład 3, część 3. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

W powyższym kodzie utworzono wyliczenie dni tygodnia.

5.9 Modyfikacja gry Kółko i krzyżyk

2.1. Duszek w labiryncie

Podstawy Programowania (PRM) projekt Specyfikacja strukturalna (techniczna)

Języki C i C++ Wykład: 2. Wstęp Instrukcje sterujące. dr Artur Bartoszewski - Języki C i C++, sem. 1I- WYKŁAD

Podstawy programowania. Wykład: 4. Instrukcje sterujące, operatory. dr Artur Bartoszewski -Podstawy programowania, sem 1 - WYKŁAD

Rozwiązanie. #include <cstdlib> #include <iostream> using namespace std;

Laboratorium 1 - Programowanie proceduralne i obiektowe

Blockly Kodowanie pomoc.

> C++ dynamiczna alokacja/rezerwacja/przydział pamięci. Dane: Iwona Polak. Uniwersytet Śląski Instytut Informatyki

*W uproszczeniu: jest dziewięciu sędziów przyznających po dwie noty: za wartość techniczną i artystyczną (skala od 0.0 do 6.0)

do instrukcja while (wyrażenie);

Programowanie komputerowe. Zajęcia 4

Propozycje tematów zadań

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Programowanie gry Smerf w labiryncie

Wskaźnik może wskazywać na jakąś zmienną, strukturę, tablicę a nawet funkcję. Oto podstawowe operatory niezbędne do operowania wskaźnikami:

Podstawy języka C++ Maciej Trzebiński. Praktyki studenckie na LHC IFJ PAN. Instytut Fizyki Jądrowej Polskiej Akademii Nauk. M. Trzebiński C++ 1/16

Kontrola przebiegu programu

Spadające jabłuszka. licencja CC-BY-SA Uznanie autorstwa Na tych samych warunkach 3.0 Polska. Strona 51

Zasady programowania Dokumentacja

Laboratorium Wstawianie skryptu na stroną: 2. Komentarze: 3. Deklaracja zmiennych

Przychodnia 0. Stwórz projekt aplikacja konsolowa lub WPF (przemyśl wybór, bo zmiana może być czasochłonna). 1. Stwórz abstrakcyjną klasę Osoba.

Język ludzki kod maszynowy

C-struktury wykład. Dorota Pylak

Wstęp do informatyki- wykład 12 Funkcje (przekazywanie parametrów przez wartość i zmienną)

Java Podstawy. Michał Bereta

1 Powtórzenie wiadomości

Nazwa implementacji: Nauka języka Python pętla for. Autor: Piotr Fiorek

PROE wykład 2 operacje na wskaźnikach. dr inż. Jacek Naruniec

przedmiot kilka razy, wystarczy kliknąć przycisk Wyczaruj ostatni,

PyGame Gra w Kółko i Krzyżyk

// Potrzebne do memset oraz memcpy, czyli kopiowania bloków

Instrukcje sterujące

Skrypty powłoki Skrypty Najcz ciej u ywane polecenia w skryptach:

Opis: Instrukcja warunkowa Składnia: IF [NOT] warunek [AND [NOT] warunek] [OR [NOT] warunek].

Wprowadzenie do programowania w języku C

Pętle. for, while, do... while, foreach. Materiał pomocniczy do kursu Podstawy programowania Autor: Grzegorz Góralski ggoralski.

Baltie 3. Podręcznik do nauki programowania dla klas IV - VI szkoły podstawowej. Tadeusz Sołtys, Bohumír Soukup

Ćwiczenie: JavaScript Cookies (3x45 minut)

Materiał uzupełniający do ćwiczen z przedmiotu: Programowanie w C ++ - ćwiczenia na wskaźnikach

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Struktury Struktura polami struct struct struct struct

XII. Warunek wielokrotnego wyboru switch... case

Programowanie komputerowe. Zajęcia 1

Program 6. Program wykorzystujący strukturę osoba o polach: imię, nazwisko, wiek. W programie wykorzystane są dwie funkcje:

Opis zagadnieo 1-3. Iteracja, rekurencja i ich realizacja

Program 22. #include <iostream> using namespace std; struct Osoba { string Imie; string Nazwisko; char Plec; int RokUr; };

Podstawy programowania skrót z wykładów:

Skrypty i funkcje Zapisywane są w m-plikach Wywoływane są przez nazwę m-pliku, w którym są zapisane (bez rozszerzenia) M-pliki mogą zawierać

Programowanie komputerowe. Zajęcia 2

Podstawy algorytmiki i programowania - wykład 4 C-struktury

Instrukcja wyboru, pętle. 2 wykład. Podstawy programowania - Paskal

Egzamin z Podstaw informatyki i programowania 2007/2008

Wykład 4: Klasy i Metody

opracował: Patryk Besler

Wstęp do Informatyki

Wstęp do informatyki- wykład 9 Funkcje

Podstawy algorytmiki i programowania - wykład 2 Tablice dwuwymiarowe cd Funkcje rekurencyjne

INFORMATYKA Z MERMIDONEM. Programowanie. Moduł 5 / Notatki

Zmienne i struktury dynamiczne

Wstęp do informatyki- wykład 11 Funkcje

Instrukcje cykliczne (pętle) WHILE...END WHILE

Transkrypt:

Gra Saper została napisana w. Jest dostępna w każdej wersji systemu Windows. Polega na odkrywaniu zaminowanej planszy tak, aby nie trafić na minę. Gra działa na bardzo prostej zasadzie i nie wymaga zaawansowanego trybu graficznego, mimo tego potrafi wciągnąć na wiele godzin. Sapera można łatwo napisać w dowolnym języku np. w C++ na dodatek używając zwykłej konsoli i nie używając żadnych elementów graficznych (obrazków). Budowa i generowanie planszy Planszę do sapera najlepiej potraktować jako tablicę dwuwymiarową. Pozwala nam to w łatwy sposób operować na planszy za pomocą dwóch zagnieżdżonych w sobie pętli, jedna do współrzędnej X a druga do Y. Dużym ułatwieniem jest zastosowanie struktury a następnie utworzenie tablicy z odpowiadającym jej typem. Struktura pozwoli nam przechowywać więcej informacji mając tylko jedną tablicę dwuwymiarową. Struktura będzie oznaczać jedno pole (jeden kwadracik) na planszy. Będzie zawierała zmienne int wartość oraz bool odkryte. Zmienna wartość oznacza wartość pola od 0-. Minę oznaczamy cyfrą, dlatego że maksymalna wartość dla pola bez miny wynosi (wynika to z zasad gry w sapera). Zmienna logiczna odkryte mówi, czy aktualne pole jest odkryte czy zakryte. struct pole int wartosc; bool odkryte; ; pole plansza[][]; Kolejnym krokiem jest wygenerowanie planszy. Najszybciej można zrobić to za pomocą funkcji i dwóch zagnieżdżonych pętli. Jedna pętla to współrzędna X a druga Y. bool genruj_plansze () for (int x = ; x<; x++) for (int y = ; y<; y++) plansza[x][y].wartosc = ; plansza[x][y].odkryte = false; return true; Karol Trybulec p-programowanie.pl

Losowanie i ustawianie min Posiadamy wygenerowaną plansze. Jest to tablica typu struktury pole. Każde z pośród 0 pól na planszy posiada wartość 0. Kolejnym zadaniem do wykonania jest funkcja losująca min. Mina to wartość. Po wylosowaniu współrzędnej miny (x,y) musimy ją otorzyć jedynkami. Każde pole dookoła naszej miny (wartość ) zwiększamy o. Będzie to wyglądać tak: Jeżeli wylosujemy minę w pobliżu już istniejącej miny, funkcja zwiększy jedynki na dwójki. Oznaczać to będzie dwie miny w pobliżu: Ostatnią sytuacją jaką musimy przewidzieć to krawędzie planszy. Jeżeli mina zostanie wylosowana przy krawędzi lub w rogu, nasza funkcja generująca numery wokół miny nie może wyjść poza zakres tablicy (czyli poza planszę). Funkcja losująca pozycję miny, losuje współrzędną X oraz Y z zakresu od 0 do. Następnie sprawdza czy w wylosowanej pozycji (x,y) nie znajduje się już jakaś mina (wartość ). Jeżeli pole jest wolne dodaje mine. 0 void losuj_pozycje () time_t t; int poz_x, poz_y; int ilosc = ; srand((unsigned)time(&t)); while (ilosc>) poz_x = rand()%; poz_y = rand()%; if (plansza[poz_x][poz_y].wartosc!=) ustaw_mine(poz_x,poz_y); ilosc--; Karol Trybulec p-programowanie.pl

Powyższa funkcja wywołuje kolejną funkcję o nazwie ustaw_mine(). Ustawia ona minę w wylosowanej pozycji. Oprócz tego musi zwiększyć otoczenie miny o oraz sprawdzać czy otoczenie miny nie wychodzi poza zakres planszy. Aby otoczyć minę jedynkami można skorzystać z instrukcji if (po jednej dla każdego sąsiadującego pola). Można także zrobić to ładniej poprzez zastosowanie dwóch zagnieżdżonych w sobie pętli (k oraz l), każda z wartością początkową - i kończącą. Wartość pętli k i l będzie dodawana do pozycji miny, dzięki temu pole miny (x, y) zostanie otoczone jedynkami. Należy także dodać warunek sprawdzający czy nie nastąpiło wyjście poza planszę. Działanie pętli k i l przedstawia rysunek: Ostatecznie funkcja ustawiające minę ma postać: bool ustaw_mine (int poz_x, int poz_y) if (plansza[poz_x][poz_y].wartosc!=) plansza[poz_x][poz_y].wartosc = ; //ustawiamy mine for (int k = -; k<; k++) for (int l = -; l<; l++) if ((poz_x+l)< (poz_y+k)< ) continue; //wyjdz bo krawedz if ((poz_x+l)> (poz_y+k)> ) continue; //wyjdz bo krawedz return true; if (plansza[poz_x+l][poz_y+k].wartosc==) continue; //wyjdz bo mina plansza[poz_x+l][poz_y+k].wartosc += ; //zwieksz o Sterowanie Sterowanie w konsoli można zrobić na dwa sposoby. Można poruszać się po planszy za pomocą strzałek, naciskając ENTER aby odkryć dane pole, lub wpisywać na sztywno Karol Trybulec p-programowanie.pl

współrzędne pola na które typujemy. Ja przedstawię sposób ruszania się za pomocą strzałek. Definiuję kody poszczególnych klawiszy (wszystkie strzałki oraz ENTER). Kody klawiszy można znaleźć w internecie. Następnie sprawdzam czy klawisz nie został naciśnięty funkcją GetKeyState. Jeżeli strzałka w lewo została naciśnięta, zmniejszam współrzędną X o. Analogiczne do pozostałych kierunków. Ważne jest aby sprawdzać czy nie wyszliśmy kursorem poza plansze. Pozycja kursora będzie zapisana w zmiennych globalnych aby łatwo można było się do niej odwołać z poszczególnych funkcji. Kolejną zmienną globalną jest zmienna koniec. Przedstawia ona aktualne stany gry (gra, przegrana, wygrana). Funkcja sterująca może wyglądać tak: 0 0 #define strzalka_lewo 0x #define strzalka_prawo 0x #define strzalka_dol 0x #define strzalka_gora 0x #define enter 0x0D int poz_x =, poz_y =, o_poz_x =, o_poz_y = ; int koniec = ; void sterowanie() if ((GetKeyState(enter) & 0x000)) if (plansza[poz_x][poz_y].wartosc==) //trafiles na mine koniec=; odkryj_plansze(poz_x, poz_y); //odkrywanie pól pokaz_plansze(); // wyswietl plansze if ((GetKeyState(strzalka_prawo) & 0x000) && poz_x<) poz_x++; if ((GetKeyState(strzalka_lewo) & 0x000) && poz_x>) poz_x--; if ((GetKeyState(strzalka_dol) & 0x000) && poz_y<) poz_y++; if ((GetKeyState(strzalka_gora) & 0x000) && poz_y>) poz_y--; if (o_poz_y==poz_y && o_poz_x==poz_x) return; //jeżeli nie ma ruchu wyjdz o_poz_y = poz_y; //zmienne pomocnicza do warunku wyżej o_poz_x = poz_x; pokaz_plansze(); // wyswietl plansze Funkcja będzie wywoływana w pętli. Po naciśnięciu dowolnej strzałki zmienna poz_x i poz_y Karol Trybulec p-programowanie.pl

będzie przechowywać pozycję kursora. Odkrywanie i wyświetlanie planszy Kolejną funkcją do napisania jest funkcja odkrywająca planszę. Jeżeli pole będzie odkryte, funkcja będzie musiała wyświetlić jego wartość od - lub spację w przypadku wartości 0. Jeżeli pole będzie zakryte, funkcja wyświetli np. znak #. Oprócz tego funkcja będzie pokazywać pozycję naszego kursora. 0 0 void pokaz_plansze() system ("cls"); //wyczysc ekran for (int i = ; i<; i++) for (int j = ; j<; j++) if (j==poz_x && i==poz_y) //aktualkna pozycja kursora SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x0); cout << "#"; else SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x0); if (plansza[j][i].odkryte==true) // pole odkryte if (plansza[j][i].wartosc==) //wartosc = 0 cout << " "; //wyswietl spacje else cout << plansza[j][i].wartosc; //wyswietl wartosc - if (plansza[j][i].odkryte==false) //pole nie odkryte cout << "#"; //wyswietl # SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x0 ); cout << endl; cout << "\npozycja kursora:\n"; //aktualkna pozycja kursora cout << "X: " << poz_x << endl; //aktualkna pozycja kursora cout << "Y: " << poz_y << endl; //aktualkna pozycja kursora Karol Trybulec p-programowanie.pl

Nasza gra posiada już większość potrzebnych funkcji. Została do zrobienia jeszcze najważniejsza z nich i w pewnym stopniu najtrudniejsza funkcja odpowiedzialna za odkrywanie pól. Będzie to funkcja rekurencyjna. Będzie odkrywać pole począwszy od współrzędnych wejściowych (x, y), w następnym kroku odkryje wszystkich sąsiadów (x, y). Każdy sąsiad ponownie odkryje wszystkich swoich sąsiadów itd. Gdybyśmy nie ograniczyli funkcji w żaden sposób wtedy po jednym jej wywołaniu odkryta została by cala plansza. Oto jakimi warunkami należy ograniczyć wykonywanie naszej funkcji: Czy nie wychodzi poza plansze, aby nie wyszła poza tablicę (jeżeli x<0 lub x> lub y<0 lub y> wtedy wyjdz) Czy pole już odkryte, aby nie próbowała odkrywać pól dwa razy (jeżeli plansza[x][y].odkryte==true wtedy wyjdz) Czy pole nie jest miną, aby nie odkryła pola zaminowanego (jeżeli plansza[x][y].wartosc== wtedy wyjdz) Jeżeli powyższe trzy warunki nie są spełnione, funkcja odkrywa pole. Po odkryciu pola należy sprawdzić kolejny bardzo ważny warunek. Rekurencyjne odkrywanie planszy ma działać na wszystkich pustych polach (wartość 0) oraz dla jednego sąsiada posiadającego wartość > 0. Oznacza to, że jeżeli funkcja zostanie wywołana dla pola nie pustego (z wartością od do ), wtedy odkrywa to pole ale nie wykonuje się dalej dla pól sąsiednich. Wynika to z zasady gry w sapera. Ostatnim warunkiem jest Czy pole ma wartość 0, aby nie odkryć całej planszy (jeżeli plansza[x][y].wartosc>0 wtedy odkryj ale wyjdz) Graficzne działanie funkcji pokazuje rysunek: Ostateczna postać funkcji: Karol Trybulec p-programowanie.pl

0 void odkryj_plansze(int x, int y) if (x< x>) return; // poza tablicą wyjście if (y< y>) return; // poza tablicą wyjście if (plansza[x][y].odkryte==true) return; // już odkryte wyjście if(plansza[x][y].wartosc!= && plansza[x][y].odkryte==false) plansza[x][y].odkryte=true; // odkryj! if (plansza[x][y].wartosc!=) return; // wartość > 0 wyjście //wywołanie funkcji dla każdego sąsiada odkryj_plansze(x-,y-); odkryj_plansze(x-,y); odkryj_plansze(x-,y+); odkryj_plansze(x+,y-); odkryj_plansze(x+,y); odkryj_plansze(x+,y+); odkryj_plansze(x,y-); odkryj_plansze(x,y); odkryj_plansze(x,y+); Zakończenie Gra została ukończona. Teraz należy połączyć wszystko w całość. Przyda się jeszcze funkcja sprawdzająca czy nie nastąpiła wygrana. Można ją napisać na takiej zasadzie: jeżeli ilość nie odkrytych pól jest taka sama jak ilość wylosowanych min podczas generowania planszy to nastąpiła wygrana. bool sprawdz_czy_wygrana() int miny = ; for (int i = ; i<; i++) for (int j = ; j<; j++) if(plansza[j][i].odkryte==false) miny++; if (miny==) return true; return false; Karol Trybulec p-programowanie.pl

Główna funkcja programu, najpierw generuje plansze i losuje miny. Następnie w pętli odbywa się sterowanie i rysowanie planszy na nowo, pętla wykonuje się do czasu wygranej lub przegranej. 0 int main() genruj_plansze(); // generuje plansze losuj_pozycje(); // losuj miny Sleep(00); while(koniec==) Sleep(0); sterowanie(); if (sprawdz_czy_wygrana()==true) koniec=; if (koniec==) cout << "\ngra zakonczona. Wygrales! :)"; if (koniec==) cout << "\ntrafiles na mine! Koniec gry."; system ("pause >nul"); return ; Kompletne źródło oraz plik *.exe dostępne są do pobrania pod adresem http://www.p-programowanie.pl/pliki/saper.rar Przykład działania gry: Karol Trybulec p-programowanie.pl