Strona główna » Po Godzinach » Gry » Potop - Kod Źródłowy
 

Potop - Kod Źródłowy

· Gra · Kod źródłowy ·

Wstęp

Gra Potop została napisana przy wykorzystaniu języka JavaScript. Kod nie wymaga żadnych zewnętrznych bibliotek, aby działać. Widoczna plansza to obiekty HTML, a nad ułożeniem wszystkiego na stronie czuwa CSS.

Implementacja

Zmienne globalne

Skrypt korzysta z następujących zmiennych globalnych:

  1. var obj_game, obj_msg, obj_board, div_board, div_pieces;
  2. var field_start = [0, 0], field_start_svg = null;
  3. var map, moveMax, move;
  4. var Gcolors = 0;
  5. var AIList;

(1.) Zmienne, które odpowiadają za zarządzanie ustawieniem obiektów na planszy. (2.) Zmienna field_start określa domyślne pole startowe oraz field_start_svg to zmienna, która będzie przechowywać uchwyt do pola, które jest polem startowym zamalowywania.

(3.) Zmienna map odpowiada za przechowywanie mapy, moveMax jest ustalane podczas rozwiązywania zagadki przez AI i jej wartość określa ile ruchów potrzeba, aby wykonać wyzwanie. Z kolei move analogicznie odpowiada ile ruchów do tej pory wykonał gracz. (4.) Gcolors odpowiada za przechowanie informacji ile kolorów zostaje użyte do losowania planszy. (5.) Ostatnia zmienna AIList jest używana przez algorytm jako zmienna danych tymczasowych w trakcie oszacowywania ilości ruchów do wyzwania.

Przygotowanie planszy

Przed utworzeniem planszy należy dokonać inicjalizacji pola gry. Można tego dokonać przy pomocy funkcji initialize(). Nie przyjmuje ona żadnych argumentów i powinna zostać wywołana tylko po załadowaniau strony.

Domyślnie skrypt ma zaimplemntowany fragment kodu, który wykonuje potrzebne funkcje w określonej kolejności zaraz po załadowaniu strony.

  1. document.addEventListener("DOMContentLoaded", function(){
  2.  initialize();
  3.  prepareGame();
  4. }, false);

Z kolei przygotowanie rzogrywki polega na (2.) utworzeniu nowej, losowej planszy, (3.) oblicz ile kroków jest na wyzwanie i (4.) wyświetl komunikat powitalny.

Losowanie planszy

Do losowania planszy służy fragment kodu w funkcji createBoard(), która przyjmuje trzy argumenty: width - elementów na szerokość, height - elementów na wysokość oraz colors - z ilu kolorów ma składać się plansza. Przygotowanie polega na utworzeniu tablicy x×y o losowych wartościach.

  1.  map = [];
  2.  for(var y = 0; y < height; y++) {
  3.   var map_sub = [];
  4.   for(var x = 0; x < width; x++) {
  5.    map_sub.push(Math.floor(Math.random()*colors));
  6.   }
  7.   map.push(map_sub);
  8.  }

Malowanie planszy

Po kliknięciu w dowolne, kolorowe wiadro uruchamiana jest funkcja fillBoardInit(). Przyjmuje ona jeden argument ncol, który określa wylewany kolor.

  1. function fillBoardInit(ncol){
  2.  move++;
  3.  var data = "Ruch: " + move + ", wyzwanie ";
  4.  data += move < moveMax ? "limit ruchów: " + (moveMax - move) : "nieukończone";
  5.  reportStatus(data);
  6.  fillBoard(field_start[0],field_start[1],field_start_svg.getAttribute("class")[1],ncol);
  7.  for(var y = 0; y < map.length; y++) {
  8.   for(var x = 0; x < map[0].length; x++) {
  9.    if(getElement(x,y).getAttribute("class")[1] != ncol)
  10.     return;
  11.   }
  12.  }
  13.  reportStatus(move <= moveMax ? "Wyzwanie ukończone! (wykonanych ruchów: " + move + ")" : "Zwycięstwo, ale wyzwanie nie zostało ukończone");
  14. }

(2.) Zwiększ licznik ruchów i (3. - 5.) pokaż komunikat o rozgrywce. (6.) Wywołaj funkcję fillBoard(), która zaczynając od pola startowego zamaluje aktualny kolor od wskazanego pola na nowy. Następnie (7. - 12.) sprawdzane jest czy istnieje pole o innym kolorze niż aktualnie wybranym. Jeśli wszystkie pola mają ten sam kolor (13.) to zostanie pokazany komunikat o zwycięstwie.

Zamalowywanie planszy

W celu zamalowania planszy funkcja jest wykonywana rekurencyjnie.

  1. function fillBoard(x,y,col,ncol){
  2.  if(getElement(x,y).getAttribute("class")[1] != col)
  3.   return;
  4.  getElement(x,y).setAttribute("class", "p" + ncol);
  5.  if(x > 0)
  6.   fillBoard(x-1,y,col,ncol);
  7.  if(x + 1 < map[0].length)
  8.   fillBoard(x+1,y,col,ncol);
  9.  if(y > 0)
  10.   fillBoard(x,y-1,col,ncol);
  11.  if(y + 1 < map.length)
  12.   fillBoard(x,y+1,col,ncol);
  13. }

(2.) Jeśli dane pole już zostało zmienione to (3.) funkcja jest przerywana. Jest to jedyny warunek stopu rekurencji. (4.) W przeciwnym razie ustal kolor pola na nowy i (5. - 12.)

Wyzwanie

Jednym z najważniejszych elementów gry jest wyznaczenie wyzwania - pewnej ilości ruchów w ile można zakończyć plansze. Rozwiązywanie planszy rozpoczyna funkcja AISolveInit().

  1. function AISolveInit(){
  2.  AIList = [];
  3.  for(var i = 0; i < Gcolors; i++)
  4.   AIList.push(0);
  5.  moveMax = AISolve();
  6. }

(2.) Przygotuj listę kolorów i (3. - 4.) wypełnij ją zerami. (5.) Rozpocznij poszukiwanie minimalnej ilości ruchów.

Wyszukiwanie minimalnej ilości ruchów rozwiązuje algorytm chciwy. W każdym ruchu program określa, który kolor wybrać, aby zmaksymalizować listę zamalowanych pól na wybrany kolor. Algorytm przedstawia się następująco:

  1. function AISolve(){
  2.  var w = 0;
  3.  while(true){
  4.   w += 1;
  5.   for(var i = 0; i < Gcolors; i++)
  6.    AIList[i] = 0;
  7.   listColors(field_start[0],field_start[1],map[field_start[1]][field_start[0]], -1);
  8.   var maxi = 0;
  9.   for(var i = 1; i < Gcolors; i++)
  10.    if(AIList[i] > AIList[maxi])
  11.     maxi = i;
  12.   listColors(field_start[0],field_start[1],map[field_start[1]][field_start[0]], maxi);
  13.   var ok = true;
  14.   var t = 0;
  15.   for(var y = 0; y < map.length && ok; y++) {
  16.    for(var x = 0; x < map[0].length && ok; x++) {
  17.     if(map[y][x] != map[0][0]) {
  18.      t++;
  19.      ok = false;
  20.     }
  21.    }
  22.   }
  23.   if(ok) break;
  24.  }
  25.  return w;
  26. }

(2.) Przyjmij, że planszę można zakończy w zero ruchów (punkt wyjściowy zliczania). (3.) Dopóki pętla nie zostanie przerwana to: (4.) zwiększ ilość potrzebnych rychów i (5. - 6.) zresetuj tablicę ile pól innych kolorów sąsiaduje z aktualnym. (7.) Zlicz ile jest kolorów każdego typu wokół aktualnie zamalowanego obszaru. (8. - 11.) Znajdź kolor, którego najwięcej pól znajduje się wokół obszaru. (12.) Następnie zamaluj aktualny obszar na nowy kolor. Potem w pętli (13. - 23.) sprawdź czy plansza została całkowicie zamalowana. Jeśli tak to (24.) zakończ wyoknywanie pętli i (26.) zwróć wartość w.

Do wyjaśnienia pozostała funkcja listColors(), która jest identyczna do funkcji fillBoard(). Różnica polega jedynie na tym, że po wyjściu z zamalowanego obszaru program rozpoznaje kolor i (3.) zwiększa odpowiedni licznik w tablicy zliczającej na podstawie której potem jest wybierany kolor zamalowujący.