Gra w życie

Gra w życie to przykład automatu komórkowego wymyślonego przez matematyka Johna Conwaya. Gra jest prowadzona w macierzy elementów, komórek. Każda z komórek może być żywa lub martwa. O stanie komórki w kolejnym etapie gry decyduje kilka zasad.

  • jeśli komórka jest martwa i ma dokładnie trzech sąsiadów żywych, staje się żywą
  • jeśli komórka jest żywa i ma dwóch lub trzech sąsiadów żywych, żyje dalej
  • jeśli komórka jest żywa i ma jednego lub mniej sąsiadów lub więcej niż trzech sąsiadów żywych, umiera (odpowiednio z samotności i przeludnienia).
Poniżej prosta implementacja Gry w życie. Podstawowym założeniem jest wykorzystanie macierzy przechowującej typ logiczny. Komórki żywe to elementy z wartościami true, a martwe z wartościami false. Po każdym etapie rozwoju wyświetlana jest plansza z aktualnym stanem naszej populacji komórek. Przejście do następnego etapu to naciśnięcie klawisza Enter, dowolny znak - koniec gry.
import java.util.Scanner;

/**
 * Prosta implementacja Gry w życie
 * @author kodatnik.blogspot.com
 */
public class GraWZycie {

 // stałe symbolizujące żywą i martwą komórkę
 private final char ZYWA = '#';
 private final char MARTWA = '.';
 // pola przechowujące rozmiar naszej planszy
 private int wiersze;
 private int kolumny;
 // deklaracja macierzy z planszą gry
 private boolean[][] plansza;

 // konstruktor, podajemy liczbę wierszy i kolumn planszy
 public GraWZycie(int wiersze, int kolumny) {
  // inicjalizujemy pola naszej klasy
  this.wiersze = wiersze;
  this.kolumny = kolumny;
  // tworzymy odpowiednią macierz, domyślnie wypełniona jest ona wartościami false
  plansza = new boolean[wiersze][kolumny];
 }

 // metoda pokazująca planszę na ekranie
 public void pokazPlansze(){
  // wyświetlamy każdy element planszy, w zależności od zawartości na ekranie pojawi się odpowiedni znak
  for(boolean wiersz[] : plansza){
   for(boolean element : wiersz)
    System.out.print((element) ? ZYWA : MARTWA);
   System.out.println();
  }
 }

 // przykładowa metoda uzupełniająca planszę populacją początkową
 public void utworzDaneTestowe() {
  // tworzymy populację początkową (standardowy Exploder)
  plansza[5][5] = true; plansza[5][7] = true; plansza[5][9] = true;
  plansza[6][5] = true; plansza[6][9] = true;
  plansza[7][5] = true; plansza[7][9] = true;
  plansza[8][5] = true; plansza[8][9] = true;
  plansza[9][5] = true; plansza[9][7] = true; plansza[9][9] = true;
 }

 // metoda zwraca liczbę żywych sąsiadów konkretnej komórki
 // w wywołaniu podajemy współrzędne komórki
 private int liczbaSasiadow(int x, int y) {

  // zmienna przechowująca liczbę sąsiadów
  int sasiedzi = 0;

  // sprawdzamy komórki na około naszej
  for(int i = x-1; i <= x+1; i++) {
   // jeżeli przekraczamy zakres planszy (wiersz) idziemy dalej
   if(i < 0 || i > wiersze-1) continue;
   for(int j = y-1; j <= y+1; j++) {
    // jeżeli przekraczamy zakres planszy (kolumna), lub jesteśmy w komórce(x,y) idziemy dalej
    if(j < 0 || j > kolumny-1 || (i == x && j == y)) continue;
    // jeśli sąsiad jest żywy to zwiększamy naszą zmienną
    if(plansza[i][j]) sasiedzi++;
   }
  }
  // zwracamy zmienną
  return sasiedzi;
 }

 // metoda sprawdza czy dana komórka będzie żywa czy też martwa w następnym etapie
 // w wywołaniu podajemy współrzędne komórki
 private boolean ewolucja(int x, int y) {

  // sprawdzamy liczbę żywych sąsiadów
  int sasiedzi = liczbaSasiadow(x, y);

  // jeżeli nasza komórka jest żywa
  if(plansza[x][y]) {
   // jeśli liczba sąsiadów jest mniejsza lub równa jeden lub większa od trzech to nasza komórka będzie martwa
   if(sasiedzi <= 1 || sasiedzi > 3) return false;
   // jeśli liczba sąsiadów jest równa trzy lub dwa to nasza komórka będzie żywa
   if(sasiedzi == 3 || sasiedzi == 2) return true;
  } else {
   // jeśli nasza komórka jest martwa i ma dokładnie trzech żywych sąsiadów to będzie żyła
   if(sasiedzi == 3) return true;
  }
  // w każdym innym przypadku zwracamy fałsz (komórka jest martwa)
  return false;
 }

 // metoda tworzy następną populację/pokolenie komórek
 public void nastepnePokolenie() {
  // tworzymy planszę tymczasową o takim samy rozmiarze jak nasza
  boolean[][] planszaTymczasowa = new boolean[wiersze][kolumny];

  // uzupełniamy nową planszę wartościami na podstawie ogólnych zasad
  for(int i = 0; i < wiersze; i++)
   for(int j = 0; j < kolumny; j++) 
    planszaTymczasowa[i][j] = ewolucja(i, j);

  // nasza główna plansza staje się planszą tymczasową
  plansza = planszaTymczasowa;
 }

 public static void main(String[] args) {

  // wyświetlamy napisy informacyjne
  System.out.println("Gra w życie - [Enter] generuje następne pokolenie, dowolny znak i [Enter] kończy grę.");

  // obsługujemy wejście
  Scanner sc = new Scanner(System.in);

  // tworzymy nowy obiekt przekazując do konstruktora rozmiar planszy
  GraWZycie gra = new GraWZycie(15, 15);
  // wypełniamy naszą planszę wartościami testowymi
  gra.utworzDaneTestowe();
  // wyświetlamy planszę na ekranie
  gra.pokazPlansze();

  // dopóki użytkownik będzie naciskał klawisz Enter
  while(sc.nextLine().equals("")) {
   // generujemy następne pokolenie
   gra.nastepnePokolenie();
   // wyświetlamy go na ekranie
   gra.pokazPlansze();
  }
 }
}
Pojawianie się następnych etapów naszej populacji może odbywać się automatycznie (bez konieczności naciskania klawisza Enter). Poniżej zmodyfikowana wersja pętli while z metody main. Mankamentem tego rozwiązania jest to, iż zakończenie programu odbywa się jedynie poprzez jego przerwanie np. za pomocą kombinacji Ctrl+C.
while(true) {
 gra.nastepnePokolenie();
 gra.pokazPlansze();
 try {
  Thread.sleep(300); // długość pauzy w milisekundach
 } catch (Exception e) {}
}
Uruchomiona aplikacja, początkowa populacja:
Gra w życie - [Enter] generuje następne pokolenie, dowolny znak i [Enter] kończy grę.
...............
...............
...............
...............
...............
.....#.#.#.....
.....#...#.....
.....#...#.....
.....#...#.....
.....#.#.#.....
...............
...............
...............
...............
...............
Populacja w następnych etapach:
...............
...............
...............
...............
...............
......#.#......
....##...##....
....###.###....
....##...##....
......#.#......
...............
...............
...............
...............
...............
...............
...............
...............
...............
...............
.....#...#.....
....#.....#....
...#..#.#..#...
....#.....#....
.....#...#.....
...............
...............
...............
...............
...............
Gra wygląda znacznie lepiej w środowisku graficznym ;)


2 Komentarze - Gra w życie

programowanie java, c++, pascal pisze...

Pierwszy raz widze gre w zycie w konsoli ;) ale dobra robota

Najlepszekasyno pisze...

To jest interesująco zobaczyć grę od strony programowania.

Prześlij komentarz

Możesz użyć niektórych tagów HTML, takich jak <b>, <i>, <u>, <a> Nie spamuj :)

Popularne posty