P016 - Prosta gra logiczna - POLE MINOWE
Programy uruchomiono w środowisku Bloodshed Dev-C++ 4.9.9.2

Uwaga, program p016 wykorzystuje bibliotekę newconio, którą stworzyliśmy na wcześniejszych zajęciach koła. Do projektu należy dołączyć plik newconio.cpp oraz plik nagłówkowy newconio.h. Bez tych plików program nie uruchomi się.

// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------
// Koło informatyczne 2006/7
//--------------------------
// Program: P016-01
//--------------------------

#include "newconio.h"
#include <iostream>

using namespace std;

const int MMAX = 300;    // maksymalna liczba min
const int PX   =  80;    // szerokość pola minowego
const int PY   =  49;    // wysokość pola minowego

char pole[PY][PX];       // pole minowe
int  sx,sy;              // współrzędne sapera

// Wyświetla ekran tytułowy gry
//-----------------------------
void ekran_tytulowy()
{
  textattr(7); clrscr();
  textcolor(15); center(10, _pl("KOŁO INFORMATYCZNE '2006"));
  textcolor(14); center(12, "I LO w Tarnowie");
  textcolor(11); center(14, "P O L E M I N O W E");
  textcolor(7);  center(PY, _pl("--- Naciśnij dowolny klawisz ---"));
  while(!getch()) ;
}

// Generuje miny na polu minowym
// oraz wyświetla planszę gry
//------------------------------
void generuj_pole_minowe()
{
  int i, j;

// generujemy pole minowe

  for(i = 0; i < PX; i++)
    for(j = 0; j < PY; j++) pole[j][i] = ' ';
  for(i = 0; i < MMAX; i++)
    pole[1 + rand() % (PY - 2)][1 + rand() % (PX - 2)] = '*';
  pole[1][78] = ' ';
  for(j = PY - 4; j < PY; j++)
    for(i = 1; i < 4; i++) pole[j][i] = ' ';

// wyświetlamy planszę gry

  textattr(0x20); clrscr();
  frame(FRAME_SOLID, 8, 0, 0, PX - 1, PY - 1);
  fillrectattr(0x70, 0, PY, PX - 1, PY);
  putxy('#', 0x29, PX - 2, 1);    // wyjście z pola minowego
}

// Główna pętla zdarzeń gry
//-------------------------
void szukaj_min()
{
  int  i, j;
  char key;
  bool t;

  sx = 1; sy = PY - 2; // pozycja sapera
  while(true)
  {
    putxy('O', 0x2f, sx, sy);
    t = false;
    for(i = sx - 1; i <= sx + 1; i++)
      for(j = sy - 1; j <= sy + 1; j++)
        t = t || (pole[j][i] == '*');
    if(t)
    {
      textattr(0x7c); center(PY, "*** UWAGA, MINY ***");
    }
    else
    {
      textattr(0x71); center(PY, "   --- PUSTO ---   ");
    }
    if(kbhit())
    {
      putxy(177, 0x20, sx, sy);
      while(!(key = getch())) ;
      switch(key)
      {
        case 72 : // strzałka w górę
                  if(getchxy(sx, sy - 1) != char(219)) sy--;
                  break;
        case 80 : // strzałka w dół
                  if(getchxy(sx, sy + 1) != char(219)) sy++;
                  break;
        case 75 : // strzałka w lewo
                  if(getchxy(sx - 1, sy) != char(219)) sx--;
                  break;
        case 77 : // strzałka w prawo
                  if(getchxy(sx + 1, sy) != char(219)) sx++;
                  break;
      } 
    }
    if(pole[sy][sx] == '*')
    {
      for(j = 1; j < PY; j++)
        for(i = 1; i < PX; i++)
          if(pole[j][i] == '*') putxy('*', 0x24, i, j);
      putxy('+', 0x2f, sx, sy);
      textattr(0x80); center(PY - 1, _pl("+++ POLEGŁ NA POLU CHWAŁY +++"));
      break;
    }
    if(getchxy(sx, sy) == '#')
    {
      for(j = 1; j < PY; j++)
        for(i = 1; i < PX; i++)
          if(pole[j][i] == '*') putxy('*', 0x20, i, j);
      putxy('X', 0xe1, sx, sy);
      textattr(0x8f); center(PY - 1, _pl("*** WITAJ W KLUBIE SAPERÓW ***"));
      break;
    }
  } 
}

// Funkcja sprawdza, czy gracz chce kontynuować rozgrywkę
//-------------------------------------------------------
bool dalsza_gra()
{
  char key;
  textattr(0x70);
  center(PY, _pl("Jeśli chcesz zagrać jeszcze raz, naciśnij klawisz [T]."));
  while(!(key = getch())) ;
  return (key == 't') || (key == 'T'); 
}

// Program główny
//---------------
main()
{
  _cinit();
  srand((unsigned)time(NULL)); 
  fullscreen(true);
  cursoroff();
  ekran_tytulowy();
  do
  {
    generuj_pole_minowe();
    szukaj_min();
  } while(dalsza_gra());
  cursoron();
  fullscreen(false);
}
Widok okienka konsoli
w uruchomionym programie
obrazek

       Wyjaśnienie

Gra Pole Minowe pochodzi z wczesnych lat 80-tych XX wieku. Zasady są bardzo proste. Jesteś saperem, który musi wytyczyć ścieżkę poprzez pole minowe. Zaczynasz w lewym dolnym rogu planszy i masz dojść do prawego górnego rogu, w którym widnieje znak '#'. Jeśli ci się to uda, wygrywasz grę. Jednakże problemem są miny rozmieszczone w sposób losowy po całym polu gry. Nie widzisz ich, jednakże posiadasz wykrywacz, który informuje cię, czy w polach przyległych bezpośrednio do twojej pozycji znajduje się mina lub miny. Wtedy na pasku wiadomości u spodu ekranu pojawia się odpowiedni napis. Jeśli jesteś nieuważny i wejdziesz na minę, gra się kończy jak na powyższym obrazku.

Gra jest bardzo prosta. Pole minowe zapamiętane jest w 2-wymiarowej tablicy pole[][]. Tablica ta dokładnie odwzorowuje planszę gry. Jeśli na ekranie gracz znajduje się na pozycji x,y, to w tablicy jest to pozycja pole[y[[x] - współrzędne są odwrotnie, ponieważ pierwszy wymiar oznacza ilość wierszy, a drugi wymiar ilość kolumn.

Główna pętla gry jest następująca:

void szukaj_min()
{
  int  i, j;
  char key;
  bool t;
Na początku funkcji deklarujemy kilka zmiennych:
i,j - liczniki pętli
key - naciśnięty klawisz
t - używane do testów na obecność min
  sx = 1; sy = PY - 2; // pozycja sapera
Zmienne sx i sy przechowują pozycję sapera na planszy. Inicjujemy je na lewy dolny róg.
  while(true)
  {
Rozpoczynamy pętlę zdarzeń gry. Jest to pętla nieskończona, którą przerwiemy w przypadku osiągnięcia prawego górnego narożnika pola gry lub wejścia na minę.
    putxy('O', 0x2f, sx, sy);
Umieszczamy na planszy sapera.
    t = false;
    for(i = sx - 1; i <= sx + 1; i++)
      for(j = sy - 1; j <= sy + 1; j++)
        t = t || (pole[j][i] == '*');
Sprawdzamy, czy w polach otaczających pozycję sapera są jakieś miny. Jeśli tak, to zmienna t przyjmie wartość true.
    if(t)
    {
      textattr(0x7c); center(PY, "*** UWAGA, MINY ***");
    }
    else
    {
      textattr(0x71); center(PY, "   --- PUSTO ---   ");
    }
Jeśli wykryto miny, wypisujemy ostrzeżenie. W przypadku braku min wypisujemy tekst uspokajający.
    if(kbhit())
    {
      putxy(177, 0x20, sx, sy);
      while(!(key = getch())) ;
      switch(key)
      {
        case 72 : // strzałka w górę
                  if(getchxy(sx, sy - 1) != char(219)) sy--;
                  break;
        case 80 : // strzałka w dół
                  if(getchxy(sx, sy + 1) != char(219)) sy++;
                  break;
        case 75 : // strzałka w lewo
                  if(getchxy(sx - 1, sy) != char(219)) sx--;
                  break;
        case 77 : // strzałka w prawo
                  if(getchxy(sx + 1, sy) != char(219)) sx++;
                  break;
      } 
    }
Jeśli naciśnięto klawisz, znak sapera zastępujemy znakiem ścieżki. Odczytujemy kod klawisza do key. Reagujemy tylko na klawisze kursora zmieniając odpowiednio współrzędne sapera, jeśli jest to możliwe (np. gracz próbuje wejść na bandę).

Uwaga: instrukcja break służy tutaj do wyjścia z instrukcji switch(). Nie przerywa ona działania pętli zdarzeń.

    if(pole[sy][sx] == '*')
    {
      for(j = 1; j < PY; j++)
        for(i = 1; i < PX; i++)
          if(pole[j][i] == '*') putxy('*', 0x24, i, j);
      putxy('+', 0x2f, sx, sy);
      textattr(0x80); center(PY - 1, _pl("+++ POLEGŁ NA POLU CHWAŁY +++"));
      break;
    }
Po zmianie współrzędnych sapera (czyli po wykonaniu ruchu gracza) musimy sprawdzić, czy saper nie wszedł na minę. Jeśli tak, wyświetlamy wszystkie miny w kolorze czerwonym oraz tekst kondolencyjny. Pętlę zdarzeń przerywamy.

Przerwanie pętli zdarzeń skutkuje wyjściem z funkcji szukaj_min(), co kończy daną rozgrywkę.

    if(getchxy(sx, sy) == '#')
    {
      for(j = 1; j < PY; j++)
        for(i = 1; i < PX; i++)
          if(pole[j][i] == '*') putxy('*', 0x20, i, j);
      putxy('X', 0xe1, sx, sy);
      textattr(0x8f); center(PY - 1, _pl("*** WITAJ W KLUBIE SAPERÓW ***"));
      break;
    }
  } 
}
Sprawdzamy, czy saper osiągnął punkt końcowy gry. Jeśli tak, również wyświetlamy miny w kolorze czarnym. W miejsce znaku '#' wpisujemy znak 'X' oraz na pasku wiadomości wyświetlamy tekst gratulacyjny. Pętlę zdarzeń przerywamy.

Przerwanie pętli zdarzeń skutkuje wyjściem z funkcji szukaj_min(), co kończy daną rozgrywkę.


   I Liceum Ogólnokształcące   
im. Kazimierza Brodzińskiego
w Tarnowie

©2024 mgr Jerzy Wałaszek

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji
GNU Free Documentation License.

Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl

W artykułach serwisu są używane cookies. Jeśli nie chcesz ich otrzymywać,
zablokuj je w swojej przeglądarce.
Informacje dodatkowe