|
@@ -0,0 +1,186 @@
|
|
|
+#include <iostream>
|
|
|
+
|
|
|
+#include "Game.h"
|
|
|
+#include "Types.h"
|
|
|
+
|
|
|
+Game::Game() : activeX(-1), activeY(-1) {
|
|
|
+ reset();
|
|
|
+}
|
|
|
+
|
|
|
+void Game::reset() {
|
|
|
+ activeX = -1;
|
|
|
+ activeY = -1;
|
|
|
+ for(uint x = 0; x < 9; x++) {
|
|
|
+ for(uint y = 0; y < 5; y++) {
|
|
|
+ fields[x][y] = (y > 2 ? FieldState::WHITE : FieldState::BLACK);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ fields[0][2] = FieldState::WHITE;
|
|
|
+ fields[2][2] = FieldState::WHITE;
|
|
|
+ fields[4][2] = FieldState::EMPTY;
|
|
|
+ fields[5][2] = FieldState::WHITE;
|
|
|
+ fields[7][2] = FieldState::WHITE;
|
|
|
+}
|
|
|
+
|
|
|
+void Game::reset(String& output) {
|
|
|
+ reset();
|
|
|
+ output.append("Fanorona Game\n");
|
|
|
+ print(output);
|
|
|
+ output.append("Human Color: White(O)\nAIColor: Black(#)\nHuman turn\nselect stone: ");
|
|
|
+}
|
|
|
+
|
|
|
+void Game::print(String& s) const {
|
|
|
+ s.append("\n 0 1 2 3 4 5 6 7 8\n");
|
|
|
+ printLine(s, 0);
|
|
|
+ s.append(" |\\|/|\\|/|\\|/|\\|/|\n");
|
|
|
+ printLine(s, 1);
|
|
|
+ s.append(" |/|\\|/|\\|/|\\|/|\\|\n");
|
|
|
+ printLine(s, 2);
|
|
|
+ s.append(" |\\|/|\\|/|\\|/|\\|/|\n");
|
|
|
+ printLine(s, 3);
|
|
|
+ s.append(" |/|\\|/|\\|/|\\|/|\\|\n");
|
|
|
+ printLine(s, 4);
|
|
|
+ s.append('\n');
|
|
|
+}
|
|
|
+
|
|
|
+void Game::printLine(String& s, int index) const {
|
|
|
+ static const char map[] = {
|
|
|
+ '#', 'O', '.'
|
|
|
+ };
|
|
|
+ s.append(index + '0').append(' ');
|
|
|
+ for(int x = 0; x < 8; x++) {
|
|
|
+ if(x == activeX && index == activeY) {
|
|
|
+ s.append("*-");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ s.append(map[fields[x][index]]).append('-');
|
|
|
+ }
|
|
|
+ if(8 == activeX && index == activeY) {
|
|
|
+ s.append('*');
|
|
|
+ } else {
|
|
|
+ s.append(map[fields[8][index]]);
|
|
|
+ }
|
|
|
+ s.append('\n');
|
|
|
+}
|
|
|
+
|
|
|
+void Game::parse(const String& input, String& output) {
|
|
|
+ if(input.getLength() <= 2 || !isDigit(input[0]) || input[1] != ' ' || !isDigit(input[2])) {
|
|
|
+ revertToSelection(output);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ uint x = input[0] - '0';
|
|
|
+ uint y = input[2] - '0';
|
|
|
+ if(x >= 9 || y >= 6) {
|
|
|
+ revertToSelection(output);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if(activeX == -1 || activeY == -1) {
|
|
|
+ markActive(x, y, output);
|
|
|
+ } else {
|
|
|
+ move(x, y, output);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+bool Game::isDigit(char c) const {
|
|
|
+ return c >= '0' && c <= '9';
|
|
|
+}
|
|
|
+
|
|
|
+void Game::markActive(int x, int y, String& output) {
|
|
|
+ if(fields[x][y] != FieldState::WHITE) {
|
|
|
+ revertToSelection(output);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ activeX = x;
|
|
|
+ activeY = y;
|
|
|
+ print(output);
|
|
|
+ output.append("Human Color: White(O)\nAIColor: Black(#)\nselect location to move: ");
|
|
|
+}
|
|
|
+
|
|
|
+void Game::move(int x, int y, String& output) {
|
|
|
+ if(fields[x][y] != FieldState::EMPTY || !areNeighbours(activeX, activeY, x, y)) {
|
|
|
+ revertToSelection(output);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ fields[activeX][activeY] = FieldState::EMPTY;
|
|
|
+ fields[x][y] = FieldState::WHITE;
|
|
|
+ removeLine(x, y, activeX, activeY, FieldState::BLACK);
|
|
|
+ removeLine(activeX, activeY, x, y, FieldState::BLACK);
|
|
|
+ activeX = x;
|
|
|
+ activeY = y;
|
|
|
+ print(output);
|
|
|
+ output.append("Human Color: White(O)\nAIColor: Black(#)\n");
|
|
|
+ print(output);
|
|
|
+ output.append("Human Color: White(O)\nAIColor: Black(#)\nAI turn\n");
|
|
|
+ activeX = -1;
|
|
|
+ activeY = -1;
|
|
|
+ botMove(output);
|
|
|
+}
|
|
|
+
|
|
|
+bool Game::areNeighbours(int x, int y, int x2, int y2) const {
|
|
|
+ if(x == x2 && y == y2) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ int diffX = x - x2;
|
|
|
+ int diffY = y - y2;
|
|
|
+ if(diffX < -1 || diffX > 1 || diffY < -1 || diffY > 1) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if(diffX == 0 || diffY == 0) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return !((x & 1) ^ (y & 1));
|
|
|
+}
|
|
|
+
|
|
|
+void Game::revertToSelection(String& output) {
|
|
|
+ activeX = -1;
|
|
|
+ activeY = -1;
|
|
|
+ print(output);
|
|
|
+ output.append("Human Color: White(O)\nAIColor: Black(#)\nHuman turn\nselect stone: ");
|
|
|
+}
|
|
|
+
|
|
|
+void Game::removeLine(int x, int y, int x2, int y2, FieldState remove) {
|
|
|
+ int diffX = x2 - x;
|
|
|
+ int diffY = y2 - y;
|
|
|
+ while(true) {
|
|
|
+ x2 += diffX;
|
|
|
+ y2 += diffY;
|
|
|
+ if(x2 < 0 || x2 >= 9 || y2 < 0 || y2 >= 5 || fields[x2][y2] != remove) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ fields[x2][y2] = FieldState::EMPTY;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void Game::botMove(String& output) {
|
|
|
+ while(true) {
|
|
|
+ int x = 0;
|
|
|
+ int y = 0;
|
|
|
+ while(true) {
|
|
|
+ x = rand() % 9;
|
|
|
+ y = rand() % 5;
|
|
|
+ if(fields[x][y] == FieldState::EMPTY) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for(uint i = 0; i < 10; i++) {
|
|
|
+ int mx = x + (rand() % 3) - 1;
|
|
|
+ int my = y + (rand() % 3) - 1;
|
|
|
+ if((mx == x && my == y) || mx < 0 || mx >= 9 || my < 0 || my >= 5 || fields[mx][my] != FieldState::BLACK) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ fields[mx][my] = FieldState::EMPTY;
|
|
|
+ fields[x][y] = FieldState::BLACK;
|
|
|
+ removeLine(mx, my, x, y, FieldState::WHITE);
|
|
|
+ removeLine(x, y, mx, my, FieldState::WHITE);
|
|
|
+
|
|
|
+ activeX = x;
|
|
|
+ activeY = y;
|
|
|
+ print(output);
|
|
|
+ activeX = -1;
|
|
|
+ activeY = -1;
|
|
|
+ print(output);
|
|
|
+ revertToSelection(output);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|