diff --git a/Makefile b/Makefile index b6b2ffa..18246e2 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CXX = g++ -CXXFLAGS = -std=c++17 -O2 -pedantic -Wall -Wextra -Werror +CXXFLAGS = -std=c++17 -O2 -pedantic -Wall -Wextra -Werror -fno-stack-protector -fstack-protector LDFLAGS = -lexpat -lsfml-network -lsfml-system -lsfml-window -lsfml-graphics -lpthread -lcppunit INC = -Inetwork -Imodel -Iui -Icontroller -Iai @@ -48,22 +48,22 @@ $(MAIN): $(OBJDIR) $(OBJDIR)/$(MAIN).o $(MAIN_TEST_MODEL): $(OBJDIR) $(OBJDIR)/$(MAIN_TEST_MODEL).o -$(OBJDIR)/%.o: $(SRCDIR_MODEL)/%.cpp +$(OBJDIR)/%.o: $(SRCDIR_MODEL)/%.cpp $(SRCDIR_MODEL)/%.hpp $(CXX) $(CXXFLAGS) $(INC) -c -MMD -o $@ $< -$(OBJDIR)/%.o: $(SRCDIR_NETWORK)/%.cpp +$(OBJDIR)/%.o: $(SRCDIR_NETWORK)/%.cpp $(SRCDIR_NETWORK)/%.hpp $(CXX) $(CXXFLAGS) $(INC) -c -MMD -o $@ $< -$(OBJDIR)/%.o: $(SRCDIR_UI)/%.cpp +$(OBJDIR)/%.o: $(SRCDIR_UI)/%.cpp $(SRCDIR_UI)/%.hpp $(CXX) $(CXXFLAGS) $(INC) -c -MMD -o $@ $< -$(OBJDIR)/%.o: $(SRCDIR_CONTROLLER)/%.cpp +$(OBJDIR)/%.o: $(SRCDIR_CONTROLLER)/%.cpp $(SRCDIR_CONTROLLER)/%.hpp $(CXX) $(CXXFLAGS) $(INC) -c -MMD -o $@ $< -$(OBJDIR)/%.o: $(SRCDIR_AI)/%.cpp +$(OBJDIR)/%.o: $(SRCDIR_AI)/%.cpp $(SRCDIR_AI)/%.hpp $(CXX) $(CXXFLAGS) $(INC) -c -MMD -o $@ $< -$(OBJDIR)/%.o: $(SRCDIR_TEST_MODEL)/%.cpp +$(OBJDIR)/%.o: $(SRCDIR_TEST_MODEL)/%.cpp $(SRCDIR_TEST_MODEL)/%.hpp $(CXX) $(CXXFLAGS) $(INC) -c -MMD -o $@ $< $(OBJDIR)/$(MAIN).o: $(MAIN).cpp diff --git a/README.md b/README.md index 6b2b58c..7201093 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Project from our (with sergeypospelov and Yurafobus1) team at spring 2020. `sudo apt-get install libtclap-dev` -install SFML +Для установки библиотеки sfml надо в командной строке ввести: `sudo apt-get install libsfml-dev` diff --git a/ai/CompPlayer.cpp b/ai/CompPlayer.cpp index a60f579..78d4d20 100644 --- a/ai/CompPlayer.cpp +++ b/ai/CompPlayer.cpp @@ -1,9 +1,12 @@ #include "CompPlayer.hpp" #include #include +#include static const int INF = (int)1e9; +int cnt1 = 0, cnt2 = 0; + CompPlayer::CompPlayer(number_of_player turn, int seconds, int deep) : controller::IPlayer(turn), seconds_(seconds), deep_(deep) {} @@ -32,8 +35,44 @@ bool CompPlayer::send_move(const BoardCell &from, const BoardCell &to) { return false; } -int CompPlayer::score(GameState G) const { - int ordw = 0, ordb = 0, queenw = 0, queenb = 0, killw = 0, killb = 0; +int CompPlayer::score(const GameState &G) { + int white_position[8][8] = + { + {64, 63, 62, 61, 60, 59, 58, 57}, + {56, 55, 54, 53, 52, 51, 50, 49}, + {48, 47, 46, 45, 44, 43, 42, 41}, + {40, 39, 38, 37, 36, 35, 34, 33}, + {32, 31, 30, 29, 28, 27, 26, 25}, + {24, 23, 22, 21, 20, 19, 18, 17}, + {16, 15, 14, 13, 12, 11, 10, 9}, + {8, 7, 6, 5, 4, 3, 2, 1} + }; + + int black_position[8][8] = + { + {1, 2, 3, 4, 5, 6, 7, 8}, + {9, 10, 11, 12, 13, 14, 15, 16}, + {17, 18, 19, 20, 21, 22, 23, 24}, + {25, 26, 27, 28, 29, 30, 31, 32}, + {33, 34, 35, 36, 37, 38, 39, 40}, + {41, 42, 43, 44, 45, 46, 47, 48}, + {49, 50, 51, 52, 53, 54, 55, 56}, + {57, 58, 59, 60, 61, 62, 63, 64} + }; + + int only_queen[8][8] = + { + {1, 2, 3, 4, 4, 3, 2, 1}, + {9, 10, 11, 12, 12, 11, 10, 9}, + {17, 18, 19, 20, 20, 19, 18, 17}, + {25, 26, 27, 28, 28, 27, 26, 25}, + {25, 26, 27, 28, 28, 27, 26, 25}, + {17, 18, 19, 20, 20, 19, 18, 17}, + {9, 10, 11, 12, 12, 11, 10, 9}, + {1, 2, 3, 4, 4, 3, 2, 1} + }; + int ordw = 0, ordb = 0, queenw = 0, queenb = 0; + int sum_with_w = 0, sum_with_b = 0, sum_out_w = 0, sum_out_b = 0; for (int i = 0; i < G.SIZE; i++) for (int j = 0; j < G.SIZE; j++) { if (G.board[i][j] == 'w') @@ -44,105 +83,143 @@ int CompPlayer::score(GameState G) const { queenw++; if (G.board[i][j] == 'B') queenb++; - if ((G.board[i][j] == 'w' || G.board[i][j] == 'W') && - G.kill(FIRST, BoardCell(i, j))) - killw++; - if ((G.board[i][j] == 'b' || G.board[i][j] == 'B') && - G.kill(SECOND, BoardCell(i, j))) - killb++; + if (G.board[i][j] == 'w' || G.board[i][j] == 'W') + sum_with_w += white_position[i][j], sum_out_w += only_queen[i][j]; + if (G.board[i][j] == 'b' || G.board[i][j] == 'B') + sum_with_b += black_position[i][j], sum_out_b += only_queen[i][j]; } - return ordw - ordb + (2 * queenw + 5) * (2 * queenw + 5) * (2 * queenw + 5) - (2 * queenb + 5) * (2 * queenb + 5) * (2 * queenb + 5) + (killw + 7) * (killw + 7) - (killb + 7) * (killb + 7); + if (ordw + ordb > 0) + return 100 * (ordw - ordb) + 1000 * (queenw - queenb) + sum_with_w - sum_with_b; + else + return 1000 * (queenw - queenb) + sum_out_w - sum_out_b; } -std::pair CompPlayer::alpha_beta(GameState G, int alpha, int beta, - clock_t start_time, int seconds, - int deep, std::mt19937 gen) const { - state current = G.check_win(); - if (current != GAME) { - if (current == DRAW) - return std::make_pair(0, Move()); - if (current == FIRST_WIN) - return std::make_pair(INF, Move()); - return std::make_pair(-INF, Move()); +void CompPlayer::alpha_beta(const GameState &G, int alpha, int beta, + int deep, std::pair &total, bool flow) { + cnt1++; + if (G.move_to_draw >= G.DRAW_MOVE) { + total = std::make_pair(0, Move()); + return; } - if (deep == 0) - return std::make_pair(score(G), Move()); - clock_t current_time = clock(); - if (1.0 * (current_time - start_time) / CLOCKS_PER_SEC > seconds) - return std::make_pair(score(G), Move()); - number_of_player player = G.who_moves(); - std::vector kill; - std::vector ordinary; + if (deep == 0) { + total = std::make_pair(score(G), Move()); + return; + } + + bool exist_white = false, exist_black = false; for (int i = 0; i < G.SIZE; i++) for (int j = 0; j < G.SIZE; j++) { - std::vector correct = - G.get_list_of_correct_moves(player, BoardCell(i, j)); - for (int z = 0; z < (int)correct.size(); z++) { - if (G.is_kill(player, BoardCell(i, j), correct[z])) - kill.push_back(Move(BoardCell(i, j), correct[z])); - else - ordinary.push_back(Move(BoardCell(i, j), correct[z])); - } + if (G.board[i][j] == 'w' || G.board[i][j] == 'W') + exist_white = true; + if (G.board[i][j] == 'b' || G.board[i][j] == 'B') + exist_black = true; + } + if (!exist_white || !exist_black) { + if (exist_white) + total = std::make_pair(INF, Move()); + else + total = std::make_pair(-INF, Move()); + return; + } + + //clock_t current_time = clock(); + //if (1.0 * (current_time - start_time) / CLOCKS_PER_SEC > seconds) + //return std::make_pair(score(G), Move()); + + number_of_player player = G.who_moves(); + + std::vector moves; + int delta, up, down, lef, rig; + if (player == SECOND) + up = 0, down = G.SIZE, lef = 0, rig = G.SIZE, delta = 1; + else + up = G.SIZE - 1, down = -1, lef = G.SIZE - 1, rig = -1, delta = -1; + + for (int i = up; i != down; i += delta) + for (int j = lef; j != rig; j += delta) { + std::vector correct; + G.get_list_of_correct_moves(player, BoardCell(i, j), correct); + for (int z = 0; z < (int)correct.size(); z++) + moves.push_back(Move(BoardCell(i, j), correct[z])); } - shuffle(kill.begin(), kill.end(), gen); - shuffle(ordinary.begin(), ordinary.end(), gen); + + if (moves.empty()) { + if (player == FIRST) + total = std::make_pair(-INF, Move()); + else + total = std::make_pair(INF, Move()); + return; + } + Move best_move; int current_score = (player == FIRST ? -INF : INF); - for (int i = 0; i < (int)kill.size(); i++) { - GameState cop = G; - cop.move(player, kill[i].from, kill[i].to); - std::pair result = - alpha_beta(cop, alpha, beta, start_time, seconds, deep, gen); - if (player == FIRST) { - if (result.first >= current_score) { - best_move = kill[i]; - current_score = result.first; - } - alpha = std::max(alpha, result.first); - if (alpha > beta) - return std::make_pair(alpha, kill[i]); - } else { - if (result.first <= current_score) { - best_move = kill[i]; - current_score = result.first; + bool fl = !G.find_kill(player); + std::vector > res((int)moves.size()); + + if (flow) { + std::vector act; + for (int i = 0; i < (int)moves.size(); i++) { + GameState cop = G; + cop.move(player, moves[i].from, moves[i].to); + act.push_back(std::thread(alpha_beta, std::ref(cop), alpha, beta, + deep - fl, std::ref(res[i]), false)); + if ((i+1) % NUMBER_OF_THREADS == 0) { + for (int j = 0; j < (int)act.size(); j++) + act[j].join(); + act.clear(); } - beta = std::min(beta, result.first); - if (alpha > beta) - return std::make_pair(beta, kill[i]); } + for (int j = 0; j < (int)act.size(); j++) + act[j].join(); + act.clear(); } - for (int i = 0; i < (int)ordinary.size(); i++) { - GameState cop = G; - cop.move(player, ordinary[i].from, ordinary[i].to); - std::pair result = - alpha_beta(cop, alpha, beta, start_time, seconds, deep - 1, gen); - if (player == FIRST) { - if (result.first >= current_score) { - best_move = ordinary[i]; - current_score = result.first; + +// std::cerr << "OK!" << std::endl; + + for (int i = 0; i < (int)moves.size(); i++) { + if (!flow) { + GameState cop = G; + cop.move(player, moves[i].from, moves[i].to); + alpha_beta(cop, alpha, beta, deep - fl, res[i], false); } - alpha = std::max(alpha, result.first); - if (alpha > beta) - return std::make_pair(alpha, ordinary[i]); - } else { - if (result.first <= current_score) { - best_move = ordinary[i]; - current_score = result.first; + + if (player == FIRST) { + if (res[i].first >= current_score) { + best_move = moves[i]; + current_score = res[i].first; + } + alpha = std::max(alpha, res[i].first); + if (alpha > beta) { + total = std::make_pair(alpha, moves[i]); + cnt2++; + return; + } + } else { + if (res[i].first <= current_score) { + best_move = moves[i]; + current_score = res[i].first; + } + beta = std::min(beta, res[i].first); + if (alpha > beta) { + total = std::make_pair(beta, moves[i]); + cnt2++; + return; + } } - beta = std::min(beta, result.first); - if (alpha > beta) - return std::make_pair(beta, ordinary[i]); } - } - return std::make_pair(current_score, best_move); + total = std::make_pair(current_score, best_move); + return; } -Move CompPlayer::get_next_move(GameState G, int seconds, int deep) const { - std::mt19937 gen(time(0)); +Move CompPlayer::get_next_move(const GameState &G, int seconds, int deep) const { + std::pair result; + (void)seconds; + cnt1 = 0, cnt2 = 0; clock_t start = clock(); - std::pair result = - alpha_beta(G, -INF, INF, start, seconds, deep, gen); - std::cout << result.first << '\n'; + alpha_beta(G, -INF, INF, deep, result, true); + clock_t finish = clock(); + std::cout << 1.0 * (finish - start) / CLOCKS_PER_SEC << '\n' << + cnt1 << ' ' << cnt2 << '\n'; return result.second; } diff --git a/ai/CompPlayer.hpp b/ai/CompPlayer.hpp index 9caf185..6fad9b2 100644 --- a/ai/CompPlayer.hpp +++ b/ai/CompPlayer.hpp @@ -3,22 +3,20 @@ #include "GameState.hpp" #include "Player.hpp" -#include -#include class CompPlayer : public controller::IPlayer { private: int seconds_; int deep_; - std::pair alpha_beta(GameState G, int alpha, int beta, - clock_t start_time, int seconds, int deep, - std::mt19937 gen) const; - int score(GameState G) const; - Move get_next_move(GameState G, int seconds, int deep) const; + static void alpha_beta(const GameState &G, int alpha, int beta, + int deep, std::pair &total, bool flow); + static int score(const GameState &G); + Move get_next_move(const GameState &G, int seconds, int deep) const; mutable GameState gs; + static const int NUMBER_OF_THREADS = 4; public: CompPlayer(number_of_player, int seconds, int deep); diff --git a/fonts/1.otf b/fonts/1.otf new file mode 100644 index 0000000..b6c6ccb Binary files /dev/null and b/fonts/1.otf differ diff --git a/main.cpp b/main.cpp index 6e790eb..7b7cc99 100644 --- a/main.cpp +++ b/main.cpp @@ -106,6 +106,10 @@ int main(int argc, char **argv) { // TODO: make own main for every game mode game_state = game_test.return_current_state(); + if (mode == "ai") { + (dynamic_cast(enemy))->set_game_state(game_state); + } + while (!core.get_events().empty()) { controller::Event *event = core.get_events().front().get(); controller::MoveEvent *move = @@ -115,7 +119,7 @@ int main(int argc, char **argv) { // TODO: make own main for every game mode controller::GiveUpEvent *giveUp = dynamic_cast(event); - controller::process(giveUp, enemy, player, game_test, mode); + controller::process(giveUp, player, enemy, game_test, mode); // currently, there is only MoveEvent. // TODO: need to process another events! diff --git a/model/Game.cpp b/model/Game.cpp index eb8e65f..06c16b2 100644 --- a/model/Game.cpp +++ b/model/Game.cpp @@ -4,6 +4,7 @@ Game::Game() { current = GameState(); game.push_back(current); + natation.push_back("0."); } int Game::number_of_states() const { return (int) game.size(); } @@ -25,14 +26,23 @@ GameState Game::watch_state(int number) const { GameState& Game::return_current_state() { return current; } +static char to_char(int a) { + return a + 96; +} + void Game::move(number_of_player player, BoardCell from, BoardCell to) { GameState copy = current; current.move(player, from, to); - if (current != copy) + if (current != copy) { game.push_back(current); + natation.push_back(std::to_string(number_of_states() - 1) + "." + + to_char(from.y + 1) + std::to_string(8 - from.x) + ">" + to_char(to.y + 1) + std::to_string(8 - to.x)); + } return; } + + void Game::save_to_file(const std::string &file) const { std::ofstream os(file); os << "\n"; diff --git a/model/Game.hpp b/model/Game.hpp index 38d9cf4..4f2430c 100644 --- a/model/Game.hpp +++ b/model/Game.hpp @@ -24,6 +24,8 @@ class Game { friend void XMLCALL endElement(void *userData, const XML_Char *name); friend class TestGame; + + std::vector natation; }; #endif diff --git a/model/GameState.cpp b/model/GameState.cpp index 619b310..8802b27 100644 --- a/model/GameState.cpp +++ b/model/GameState.cpp @@ -14,6 +14,34 @@ GameState::GameState() { board[1][j] = 'b', board[SIZE - 3][j] = 'w', board[SIZE - 1][j] = 'w'; for (int j = 1; j < SIZE; j += 2) board[0][j] = 'b', board[2][j] = 'b', board[SIZE - 2][j] = 'w'; + + for (int i = 0; i < SIZE; i++) + for (int j = 0; j < SIZE; j++) { + if (i == 0 || j == 0) + white_up_down[i][j] = black_up_down[i][j] = 0; + else { + white_up_down[i][j] = white_up_down[i - 1][j - 1]; + black_up_down[i][j] = black_up_down[i - 1][j - 1]; + } + if (board[i][j] == 'w' || board[i][j] == 'W') + white_up_down[i][j]++; + if (board[i][j] == 'b' || board[i][j] == 'B') + black_up_down[i][j]++; + } + + for (int i = SIZE - 1; i >= 0; i--) + for (int j = 0; j < SIZE; j++) { + if (i == SIZE - 1 || j == 0) + white_down_up[i][j] = black_down_up[i][j] = 0; + else { + white_down_up[i][j] = white_down_up[i + 1][j - 1]; + black_down_up[i][j] = black_down_up[i + 1][j - 1]; + } + if (board[i][j] == 'w' || board[i][j] == 'W') + white_down_up[i][j]++; + if (board[i][j] == 'b' || board[i][j] == 'B') + black_down_up[i][j]++; + } return; } @@ -22,7 +50,8 @@ bool GameState::inside(BoardCell cell) const { } bool GameState::check_ordinary(number_of_player player, BoardCell from, - BoardCell to) const { + BoardCell to, bool &die) const { + die = false; if ((player == SECOND && board[from.x][from.y] == 'w') || (player == FIRST && board[from.x][from.y] == 'b')) return false; @@ -40,43 +69,50 @@ bool GameState::check_ordinary(number_of_player player, BoardCell from, for (int dy = -1; dy <= 1; dy += 2) if (to == BoardCell(from.x + dx * 2, from.y + dy * 2) && (board[from.x + dx][from.y + dy] == oth1 || - board[from.x + dx][from.y + dy] == oth2)) + board[from.x + dx][from.y + dy] == oth2)) { + die = true; return true; + } return false; } bool GameState::check_queen(number_of_player player, BoardCell from, - BoardCell to) const { + BoardCell to, bool &die) const { + die = false; if ((player == SECOND && board[from.x][from.y] == 'W') || (player == FIRST && board[from.x][from.y] == 'B')) return false; if (to.x + to.y != from.x + from.y && to.x - to.y != from.x - from.y) return false; - - int cntb = 0, cntw = 0, dy = (to.x + to.y == from.x + from.y ? -1 : 1); - while (to != from) { - if (board[to.x][to.y] == 'w' || board[to.x][to.y] == 'W') - cntw++; - if (board[to.x][to.y] == 'b' || board[to.x][to.y] == 'B') - cntb++; - if (to.x < from.x) - to.x++, to.y += dy; - else - to.x--, to.y -= dy; + + int bal_white = 0, bal_black = 0; + if (from.x - from.y == to.x - to.y) { + if (from.y < to.y) + std::swap(from, to); + bal_white = white_up_down[from.x - 1][from.y - 1] - white_up_down[to.x][to.y]; + bal_black = black_up_down[from.x - 1][from.y - 1] - black_up_down[to.x][to.y]; } + else { + if (from.y < to.y) + std::swap(from, to); + bal_white = white_down_up[from.x + 1][from.y - 1] - white_down_up[to.x][to.y]; + bal_black = black_down_up[from.x + 1][from.y - 1] - black_down_up[to.x][to.y]; + } + + die = (bal_white + bal_black > 0); if (player == FIRST) - if (cntw == 0 && cntb <= 1) + if (bal_white == 0 && bal_black <= 1) return true; else return false; - else if (cntb == 0 && cntw <= 1) + else if (bal_black == 0 && bal_white <= 1) return true; else return false; } bool GameState::check_move(number_of_player player, BoardCell from, - BoardCell to) const { + BoardCell to, bool &die) const { if (!inside(from) || !inside(to)) return false; if (board[from.x][from.y] == '.') @@ -85,62 +121,53 @@ bool GameState::check_move(number_of_player player, BoardCell from, return false; if (board[from.x][from.y] == 'w' || board[from.x][from.y] == 'b') - return check_ordinary(player, from, to); + return check_ordinary(player, from, to, die); - return check_queen(player, from, to); + return check_queen(player, from, to, die); } bool GameState::kill(number_of_player who, BoardCell pos) const { - for (int i = 0; i < SIZE; i++) - for (int j = 0; j < SIZE; j++) { - if (!check_move(who, pos, BoardCell(i, j))) - continue; - BoardCell cur = BoardCell(i, j); - bool fl = false; - int dy = (i + j == pos.x + pos.y ? -1 : 1); - while (cur.x != pos.x) { - if (board[cur.x][cur.y] != '.') - fl = true; - if (cur.x < pos.x) - cur.x++, cur.y += dy; - else - cur.x--, cur.y -= dy; + char small = (who == FIRST ? 'w' : 'b'); + char big = (who == FIRST ? 'W' : 'B'); + if (!inside(pos) || (board[pos.x][pos.y] != small && board[pos.x][pos.y] != big)) + return false; + if (board[pos.x][pos.y] == small) { + for (int sgn1 = -1; sgn1 <= 1; sgn1 += 2) + for (int sgn2 = -1; sgn2 <= 1; sgn2 += 2) { + bool die = false; + if (check_move(who, pos, BoardCell(pos.x + 2 * sgn1, pos.y + 2 * sgn2), die)) + if (die) + return true; + } + return false; + } + + for (int sgn1 = -1; sgn1 <= 1; sgn1 += 2) + for (int sgn2 = -1; sgn2 <= 1; sgn2 += 2) { + BoardCell cop = BoardCell(pos.x + 2 * sgn1, pos.y + 2 * sgn2); + while (inside(cop)) { + bool die = false; + if (check_move(who, pos, cop, die)) + if (die) + return true; + cop.x += sgn1, cop.y += sgn2; } - if (fl) - return true; } return false; } -BoardCell GameState::find_kill(number_of_player who) const { +bool GameState::find_kill(number_of_player who) const { + char small = (who == FIRST ? 'w' : 'b'); + char big = (who == FIRST ? 'W' : 'B'); for (int i = 0; i < SIZE; i++) for (int j = 0; j < SIZE; j++) - if (kill(who, BoardCell(i, j))) - return BoardCell(i, j); - return BoardCell(-1, -1); -} - -bool GameState::is_kill(number_of_player who, BoardCell from, - BoardCell to) const { - if (!check_move(who, from, to)) - return false; - - bool fl = false; - int dy = (from.x + from.y == to.x + to.y ? -1 : 1); - BoardCell cur = to; - while (cur.x != from.x) { - if (board[cur.x][cur.y] != '.') - fl = true; - if (cur.x < from.x) - cur.x++, cur.y += dy; - else - cur.x--, cur.y -= dy; - } - return fl; + if ((board[i][j] == small || board[i][j] == big) && kill(who, BoardCell(i, j))) + return true; + return false; } char GameState::get_cell(BoardCell cell) const { - assert(inside(cell)); + if (!inside(cell)) assert(0); return board[cell.x][cell.y]; } @@ -161,10 +188,48 @@ number_of_player GameState::who_moves() const { } } +void GameState::change_prefix(BoardCell pos, char news) { + if (board[pos.x][pos.y] == news) + return; + if (board[pos.x][pos.y] != '.') { + for (int shift = 0; pos.x + shift < SIZE && pos.y + shift < SIZE; shift++) { + if (board[pos.x][pos.y] == 'w' || board[pos.x][pos.y] == 'W') + white_up_down[pos.x + shift][pos.y + shift]--; + else + black_up_down[pos.x + shift][pos.y + shift]--; + } + + for (int shift = 0; pos.x - shift >= 0 && pos.y + shift < SIZE; shift++) { + if (board[pos.x][pos.y] == 'w' || board[pos.x][pos.y] == 'W') + white_down_up[pos.x - shift][pos.y + shift]--; + else + black_down_up[pos.x - shift][pos.y + shift]--; + } + } + + if (news != '.') { + for (int shift = 0; pos.x + shift < SIZE && pos.y + shift < SIZE; shift++) { + if (news == 'w' || news == 'W') + white_up_down[pos.x + shift][pos.y + shift]++; + else + black_up_down[pos.x + shift][pos.y + shift]++; + } + + for (int shift = 0; pos.x - shift >= 0 && pos.y + shift < SIZE; shift++) { + if (news == 'w' || news == 'W') + white_down_up[pos.x - shift][pos.y + shift]++; + else + black_down_up[pos.x - shift][pos.y + shift]++; + } + } + return; +} + void GameState::move(number_of_player player, BoardCell from, BoardCell to) { + bool die = false; if (who_moves() != player) return; - if (!check_move(player, from, to)) + if (!check_move(player, from, to, die)) return; if (player == who_last) if (from != last_move) @@ -172,10 +237,8 @@ void GameState::move(number_of_player player, BoardCell from, BoardCell to) { int dy = (to.x + to.y == from.x + from.y ? -1 : 1); BoardCell cop = to; - bool die = false; while (cop != from) { - if (board[cop.x][cop.y] != '.') - die = true; + change_prefix(cop, '.'); board[cop.x][cop.y] = '.'; if (cop.x < from.x) cop.x++, cop.y += dy; @@ -183,21 +246,26 @@ void GameState::move(number_of_player player, BoardCell from, BoardCell to) { cop.x--, cop.y -= dy; } if (die) { + change_prefix(to, board[from.x][from.y]); + change_prefix(from, board[to.x][to.y]); std::swap(board[to.x][to.y], board[from.x][from.y]); who_last = player; move_to_draw = 0; type_last = 1; last_move = to; } else { - BoardCell pos = find_kill(player); - if (pos != BoardCell(-1, -1)) - board[pos.x][pos.y] = '.'; - std::swap(board[to.x][to.y], board[from.x][from.y]); + if (find_kill(player)) { + return; // Запрещаю не рубить + //board[pos.x][pos.y] = '.'; // Зафук + } who_last = player; if (board[from.x][from.y] == 'W' || board[from.x][from.y] == 'B') move_to_draw++; type_last = 0; last_move = to; + change_prefix(to, board[from.x][from.y]); + change_prefix(from, board[to.x][to.y]); + std::swap(board[to.x][to.y], board[from.x][from.y]); } if (player == FIRST && to.x == 0 && board[to.x][to.y] == 'w') board[to.x][to.y] = 'W'; @@ -206,38 +274,48 @@ void GameState::move(number_of_player player, BoardCell from, BoardCell to) { return; } -std::vector -GameState::get_list_of_correct_moves(number_of_player player, - BoardCell from) const { - std::vector pos; +void GameState::get_list_of_correct_moves(number_of_player player, BoardCell from, + std::vector &moves) const { if (who_moves() != player) - return pos; + return; if (player == who_last && from != last_move) - return pos; - for (int i = 0; i < SIZE; i++) - for (int j = 0; j < SIZE; j++) - if (kill(player, BoardCell(i, j)) && !kill(player, from)) - return pos; - - for (int i = 0; i < SIZE; i++) - for (int j = 0; j < SIZE; j++) - if (check_move(player, from, BoardCell(i, j))) { - if ((kill(player, from) && is_kill(player, from, BoardCell(i, j))) || (!kill(player, from))) - pos.push_back(BoardCell(i, j)); + return; + bool fl = kill(player, from); + if (!fl && find_kill(player)) //Запрещаем не рубить + return; + + for (int sgn1 = -1; sgn1 <= 1; sgn1 += 2) + for (int sgn2 = -1; sgn2 <= 1; sgn2 += 2) { + BoardCell cop = BoardCell(from.x + sgn1, from.y + sgn2); + while (inside(cop)) { + bool die = false; + if (check_move(player, from, cop, die)) { + if (!fl || die) + moves.push_back(cop); + } + cop.x += sgn1, cop.y += sgn2; } - return pos; + } + return; } state GameState::check_win() const { if (move_to_draw >= DRAW_MOVE) return DRAW; number_of_player player = who_moves(); + char small = (player == FIRST ? 'w' : 'b'); + char big = (player == FIRST ? 'W' : 'B'); for (int i1 = 0; i1 < SIZE; i1++) - for (int j1 = 0; j1 < SIZE; j1++) + for (int j1 = 0; j1 < SIZE; j1++) { + if (board[i1][j1] != small && board[i1][j1] != big) + continue; for (int i2 = 0; i2 < SIZE; i2++) - for (int j2 = 0; j2 < SIZE; j2++) - if (check_move(player, BoardCell(i1, j1), BoardCell(i2, j2))) + for (int j2 = 0; j2 < SIZE; j2++) { + bool die = false; + if (check_move(player, BoardCell(i1, j1), BoardCell(i2, j2), die)) return GAME; + } + } if (player == FIRST) return SECOND_WIN; else diff --git a/model/GameState.hpp b/model/GameState.hpp index ad06271..1cf7597 100644 --- a/model/GameState.hpp +++ b/model/GameState.hpp @@ -19,26 +19,29 @@ class GameState { int move_to_draw, type_last; BoardCell last_move; char board[SIZE][SIZE]; + int white_up_down[SIZE][SIZE], white_down_up[SIZE][SIZE]; + int black_up_down[SIZE][SIZE], black_down_up[SIZE][SIZE]; - bool check_ordinary(number_of_player player, BoardCell from, - BoardCell to) const; - bool check_queen(number_of_player player, BoardCell from, BoardCell to) const; + bool check_ordinary(number_of_player player, BoardCell from, BoardCell to, bool &die) const; + bool check_queen(number_of_player player, BoardCell from, BoardCell to, bool &die) const; bool inside(BoardCell cell) const; bool kill(number_of_player who, BoardCell pos) const; - bool is_kill(number_of_player who, BoardCell from, BoardCell to) const; - BoardCell find_kill(number_of_player who) const; + bool find_kill(number_of_player who) const; + + void change_prefix(BoardCell pos, char news); + void show() const; public: GameState(); + GameState(const GameState &oth) = default; + GameState& operator=(const GameState &oth) = default; number_of_player who_moves() const; - bool check_move(number_of_player player, BoardCell from, BoardCell to) const; + bool check_move(number_of_player player, BoardCell from, BoardCell to, bool &die) const; void move(number_of_player player, BoardCell from, BoardCell to); - std::vector get_list_of_correct_moves(number_of_player player, - BoardCell from) const; + void get_list_of_correct_moves(number_of_player player, BoardCell from, std::vector &moves) const; state check_win() const; char get_cell(BoardCell cell) const; - void show() const; friend bool operator!=(const GameState &fir, const GameState &sec); diff --git a/test_model/TestGameState.cpp b/test_model/TestGameState.cpp index 8b90ed5..fd8f06e 100644 --- a/test_model/TestGameState.cpp +++ b/test_model/TestGameState.cpp @@ -1,5 +1,4 @@ #include "TestGameState.hpp" -#include "GameState.hpp" void TestGameState::test_init() { GameState g; @@ -25,6 +24,37 @@ void TestGameState::test_init() { return; } +void TestGameState::calculate(GameState &G) { + for (int i = 0; i < G.SIZE; i++) + for (int j = 0; j < G.SIZE; j++) { + if (i == 0 || j == 0) + G.white_up_down[i][j] = G.black_up_down[i][j] = 0; + else { + G.white_up_down[i][j] = G.white_up_down[i - 1][j - 1]; + G.black_up_down[i][j] = G.black_up_down[i - 1][j - 1]; + } + if (G.board[i][j] == 'w' || G.board[i][j] == 'W') + G.white_up_down[i][j]++; + if (G.board[i][j] == 'b' || G.board[i][j] == 'B') + G.black_up_down[i][j]++; + } + + for (int i = G.SIZE - 1; i >= 0; i--) + for (int j = 0; j < G.SIZE; j++) { + if (i == G.SIZE - 1 || j == 0) + G.white_down_up[i][j] = G.black_down_up[i][j] = 0; + else { + G.white_down_up[i][j] = G.white_down_up[i + 1][j - 1]; + G.black_down_up[i][j] = G.black_down_up[i + 1][j - 1]; + } + if (G.board[i][j] == 'w' || G.board[i][j] == 'W') + G.white_down_up[i][j]++; + if (G.board[i][j] == 'b' || G.board[i][j] == 'B') + G.black_down_up[i][j]++; + } + return; +} + void TestGameState::test_ordinary() { GameState g; for (int i = 0; i < g.SIZE; i++) @@ -42,21 +72,24 @@ void TestGameState::test_ordinary() { g.board[5][5] = 'w'; g.board[6][4] = 'w'; g.board[4][3] = 'b'; - CPPUNIT_ASSERT(g.check_ordinary(FIRST, BoardCell(2, 3), BoardCell(0, 1))); - CPPUNIT_ASSERT(g.check_ordinary(FIRST, BoardCell(3, 2), BoardCell(2, 1))); - CPPUNIT_ASSERT(!g.check_ordinary(FIRST, BoardCell(1, 2), BoardCell(3, 4))); - CPPUNIT_ASSERT(!g.check_ordinary(FIRST, BoardCell(3, 5), BoardCell(3, 7))); - CPPUNIT_ASSERT(!g.check_ordinary(FIRST, BoardCell(5, 5), BoardCell(6, 6))); - CPPUNIT_ASSERT(g.check_ordinary(FIRST, BoardCell(4, 2), BoardCell(3, 3))); - CPPUNIT_ASSERT(g.check_ordinary(FIRST, BoardCell(3, 2), BoardCell(5, 4))); - - CPPUNIT_ASSERT(!g.check_ordinary(SECOND, BoardCell(4, 3), BoardCell(2, 5))); - CPPUNIT_ASSERT(g.check_ordinary(SECOND, BoardCell(1, 2), BoardCell(3, 4))); - CPPUNIT_ASSERT(!g.check_ordinary(SECOND, BoardCell(1, 2), BoardCell(2, 2))); - CPPUNIT_ASSERT(g.check_ordinary(SECOND, BoardCell(0, 5), BoardCell(1, 6))); - CPPUNIT_ASSERT(g.check_ordinary(SECOND, BoardCell(1, 2), BoardCell(2, 1))); - CPPUNIT_ASSERT(!g.check_ordinary(SECOND, BoardCell(1, 2), BoardCell(0, 3))); - CPPUNIT_ASSERT(g.check_ordinary(SECOND, BoardCell(4, 3), BoardCell(2, 1))); + calculate(g); + + bool die = false; + CPPUNIT_ASSERT(g.check_ordinary(FIRST, BoardCell(2, 3), BoardCell(0, 1), die)); + CPPUNIT_ASSERT(g.check_ordinary(FIRST, BoardCell(3, 2), BoardCell(2, 1), die)); + CPPUNIT_ASSERT(!g.check_ordinary(FIRST, BoardCell(1, 2), BoardCell(3, 4), die)); + CPPUNIT_ASSERT(!g.check_ordinary(FIRST, BoardCell(3, 5), BoardCell(3, 7), die)); + CPPUNIT_ASSERT(!g.check_ordinary(FIRST, BoardCell(5, 5), BoardCell(6, 6), die)); + CPPUNIT_ASSERT(g.check_ordinary(FIRST, BoardCell(4, 2), BoardCell(3, 3), die)); + CPPUNIT_ASSERT(g.check_ordinary(FIRST, BoardCell(3, 2), BoardCell(5, 4), die)); + + CPPUNIT_ASSERT(!g.check_ordinary(SECOND, BoardCell(4, 3), BoardCell(2, 5), die)); + CPPUNIT_ASSERT(g.check_ordinary(SECOND, BoardCell(1, 2), BoardCell(3, 4), die)); + CPPUNIT_ASSERT(!g.check_ordinary(SECOND, BoardCell(1, 2), BoardCell(2, 2), die)); + CPPUNIT_ASSERT(g.check_ordinary(SECOND, BoardCell(0, 5), BoardCell(1, 6), die)); + CPPUNIT_ASSERT(g.check_ordinary(SECOND, BoardCell(1, 2), BoardCell(2, 1), die)); + CPPUNIT_ASSERT(!g.check_ordinary(SECOND, BoardCell(1, 2), BoardCell(0, 3), die)); + CPPUNIT_ASSERT(g.check_ordinary(SECOND, BoardCell(4, 3), BoardCell(2, 1), die)); return; } @@ -76,19 +109,22 @@ void TestGameState::test_queen() { g.board[4][6] = 'W'; g.board[6][4] = 'b'; g.board[6][7] = 'B'; - CPPUNIT_ASSERT(g.check_queen(FIRST, BoardCell(4, 6), BoardCell(0, 2))); - CPPUNIT_ASSERT(g.check_queen(FIRST, BoardCell(4, 6), BoardCell(2, 4))); - CPPUNIT_ASSERT(g.check_queen(FIRST, BoardCell(4, 6), BoardCell(5, 7))); - CPPUNIT_ASSERT(!g.check_queen(FIRST, BoardCell(4, 6), BoardCell(4, 5))); - CPPUNIT_ASSERT(!g.check_queen(FIRST, BoardCell(6, 7), BoardCell(0, 1))); - CPPUNIT_ASSERT(!g.check_queen(FIRST, BoardCell(1, 6), BoardCell(4, 3))); - - CPPUNIT_ASSERT(g.check_queen(SECOND, BoardCell(1, 6), BoardCell(4, 3))); - CPPUNIT_ASSERT(g.check_queen(SECOND, BoardCell(1, 6), BoardCell(7, 0))); - CPPUNIT_ASSERT(!g.check_queen(SECOND, BoardCell(2, 6), BoardCell(4, 3))); - CPPUNIT_ASSERT(g.check_queen(SECOND, BoardCell(1, 3), BoardCell(5, 7))); - CPPUNIT_ASSERT(g.check_queen(SECOND, BoardCell(2, 6), BoardCell(5, 3))); - CPPUNIT_ASSERT(!g.check_queen(SECOND, BoardCell(4, 6), BoardCell(3, 7))); + calculate(g); + + bool die = false; + CPPUNIT_ASSERT(g.check_queen(FIRST, BoardCell(4, 6), BoardCell(0, 2), die)); + CPPUNIT_ASSERT(g.check_queen(FIRST, BoardCell(4, 6), BoardCell(2, 4), die)); + CPPUNIT_ASSERT(g.check_queen(FIRST, BoardCell(4, 6), BoardCell(5, 7), die)); + CPPUNIT_ASSERT(!g.check_queen(FIRST, BoardCell(4, 6), BoardCell(4, 5), die)); + CPPUNIT_ASSERT(!g.check_queen(FIRST, BoardCell(6, 7), BoardCell(0, 1), die)); + CPPUNIT_ASSERT(!g.check_queen(FIRST, BoardCell(1, 6), BoardCell(4, 3), die)); + + CPPUNIT_ASSERT(g.check_queen(SECOND, BoardCell(1, 6), BoardCell(4, 3), die)); + CPPUNIT_ASSERT(g.check_queen(SECOND, BoardCell(1, 6), BoardCell(7, 0), die)); + CPPUNIT_ASSERT(!g.check_queen(SECOND, BoardCell(2, 6), BoardCell(4, 3), die)); + CPPUNIT_ASSERT(g.check_queen(SECOND, BoardCell(1, 3), BoardCell(5, 7), die)); + CPPUNIT_ASSERT(g.check_queen(SECOND, BoardCell(2, 6), BoardCell(5, 3), die)); + CPPUNIT_ASSERT(!g.check_queen(SECOND, BoardCell(4, 6), BoardCell(3, 7), die)); return; } @@ -109,24 +145,27 @@ void TestGameState::test_check_move() { g.board[5][5] = 'w'; g.board[6][4] = 'w'; g.board[4][3] = 'b'; - CPPUNIT_ASSERT(!g.check_move(FIRST, BoardCell(0, 0), BoardCell(1, 1))); - CPPUNIT_ASSERT(!g.check_move(FIRST, BoardCell(2, 3), BoardCell(0, 5))); - CPPUNIT_ASSERT(g.check_move(FIRST, BoardCell(2, 3), BoardCell(0, 1))); - CPPUNIT_ASSERT(g.check_move(FIRST, BoardCell(3, 2), BoardCell(2, 1))); - CPPUNIT_ASSERT(!g.check_move(FIRST, BoardCell(6, 4), BoardCell(8, 6))); - CPPUNIT_ASSERT(!g.check_move(FIRST, BoardCell(1, 2), BoardCell(3, 4))); - CPPUNIT_ASSERT(!g.check_move(FIRST, BoardCell(3, 5), BoardCell(3, 7))); - CPPUNIT_ASSERT(!g.check_move(FIRST, BoardCell(5, 5), BoardCell(6, 6))); - - CPPUNIT_ASSERT(!g.check_move(SECOND, BoardCell(4, 3), BoardCell(2, 5))); - CPPUNIT_ASSERT(!g.check_move(SECOND, BoardCell(1, 7), BoardCell(0, 8))); - CPPUNIT_ASSERT(!g.check_move(SECOND, BoardCell(1, 4), BoardCell(3, 2))); - CPPUNIT_ASSERT(g.check_move(SECOND, BoardCell(1, 2), BoardCell(3, 4))); - CPPUNIT_ASSERT(!g.check_move(SECOND, BoardCell(1, 2), BoardCell(2, 2))); - CPPUNIT_ASSERT(g.check_move(SECOND, BoardCell(0, 5), BoardCell(1, 6))); - CPPUNIT_ASSERT(g.check_move(SECOND, BoardCell(1, 2), BoardCell(2, 1))); - CPPUNIT_ASSERT(!g.check_move(SECOND, BoardCell(1, 2), BoardCell(0, 3))); - CPPUNIT_ASSERT(g.check_move(SECOND, BoardCell(4, 3), BoardCell(2, 1))); + calculate(g); + + bool die = false; + CPPUNIT_ASSERT(!g.check_move(FIRST, BoardCell(0, 0), BoardCell(1, 1), die)); + CPPUNIT_ASSERT(!g.check_move(FIRST, BoardCell(2, 3), BoardCell(0, 5), die)); + CPPUNIT_ASSERT(g.check_move(FIRST, BoardCell(2, 3), BoardCell(0, 1), die)); + CPPUNIT_ASSERT(g.check_move(FIRST, BoardCell(3, 2), BoardCell(2, 1), die)); + CPPUNIT_ASSERT(!g.check_move(FIRST, BoardCell(6, 4), BoardCell(8, 6), die)); + CPPUNIT_ASSERT(!g.check_move(FIRST, BoardCell(1, 2), BoardCell(3, 4), die)); + CPPUNIT_ASSERT(!g.check_move(FIRST, BoardCell(3, 5), BoardCell(3, 7), die)); + CPPUNIT_ASSERT(!g.check_move(FIRST, BoardCell(5, 5), BoardCell(6, 6), die)); + + CPPUNIT_ASSERT(!g.check_move(SECOND, BoardCell(4, 3), BoardCell(2, 5), die)); + CPPUNIT_ASSERT(!g.check_move(SECOND, BoardCell(1, 7), BoardCell(0, 8), die)); + CPPUNIT_ASSERT(!g.check_move(SECOND, BoardCell(1, 4), BoardCell(3, 2), die)); + CPPUNIT_ASSERT(g.check_move(SECOND, BoardCell(1, 2), BoardCell(3, 4), die)); + CPPUNIT_ASSERT(!g.check_move(SECOND, BoardCell(1, 2), BoardCell(2, 2), die)); + CPPUNIT_ASSERT(g.check_move(SECOND, BoardCell(0, 5), BoardCell(1, 6), die)); + CPPUNIT_ASSERT(g.check_move(SECOND, BoardCell(1, 2), BoardCell(2, 1), die)); + CPPUNIT_ASSERT(!g.check_move(SECOND, BoardCell(1, 2), BoardCell(0, 3), die)); + CPPUNIT_ASSERT(g.check_move(SECOND, BoardCell(4, 3), BoardCell(2, 1), die)); for (int i = 0; i < g.SIZE; i++) for (int j = 0; j < g.SIZE; j++) @@ -142,23 +181,25 @@ void TestGameState::test_check_move() { g.board[4][6] = 'W'; g.board[6][4] = 'b'; g.board[6][7] = 'B'; - CPPUNIT_ASSERT(g.check_move(FIRST, BoardCell(4, 6), BoardCell(0, 2))); - CPPUNIT_ASSERT(g.check_move(FIRST, BoardCell(4, 6), BoardCell(2, 4))); - CPPUNIT_ASSERT(g.check_move(FIRST, BoardCell(4, 6), BoardCell(5, 7))); - CPPUNIT_ASSERT(!g.check_move(FIRST, BoardCell(4, 6), BoardCell(4, 5))); - CPPUNIT_ASSERT(!g.check_move(FIRST, BoardCell(4, 6), BoardCell(3, 7))); - CPPUNIT_ASSERT(!g.check_move(FIRST, BoardCell(6, 7), BoardCell(0, 1))); - CPPUNIT_ASSERT(!g.check_move(FIRST, BoardCell(1, 6), BoardCell(4, 3))); - CPPUNIT_ASSERT(!g.check_move(FIRST, BoardCell(4, 6), BoardCell(6, 4))); - - CPPUNIT_ASSERT(g.check_move(SECOND, BoardCell(1, 6), BoardCell(4, 3))); - CPPUNIT_ASSERT(g.check_move(SECOND, BoardCell(1, 6), BoardCell(7, 0))); - CPPUNIT_ASSERT(!g.check_move(SECOND, BoardCell(2, 6), BoardCell(4, 3))); - CPPUNIT_ASSERT(g.check_move(SECOND, BoardCell(1, 3), BoardCell(5, 7))); - CPPUNIT_ASSERT(g.check_move(SECOND, BoardCell(2, 6), BoardCell(5, 3))); - CPPUNIT_ASSERT(!g.check_move(SECOND, BoardCell(4, 6), BoardCell(3, 7))); - CPPUNIT_ASSERT(!g.check_move(SECOND, BoardCell(6, 7), BoardCell(1, 2))); - CPPUNIT_ASSERT(!g.check_move(SECOND, BoardCell(1, 2), BoardCell(2, 2))); + calculate(g); + + CPPUNIT_ASSERT(g.check_move(FIRST, BoardCell(4, 6), BoardCell(0, 2), die)); + CPPUNIT_ASSERT(g.check_move(FIRST, BoardCell(4, 6), BoardCell(2, 4), die)); + CPPUNIT_ASSERT(g.check_move(FIRST, BoardCell(4, 6), BoardCell(5, 7), die)); + CPPUNIT_ASSERT(!g.check_move(FIRST, BoardCell(4, 6), BoardCell(4, 5), die)); + CPPUNIT_ASSERT(!g.check_move(FIRST, BoardCell(4, 6), BoardCell(3, 7), die)); + CPPUNIT_ASSERT(!g.check_move(FIRST, BoardCell(6, 7), BoardCell(0, 1), die)); + CPPUNIT_ASSERT(!g.check_move(FIRST, BoardCell(1, 6), BoardCell(4, 3), die)); + CPPUNIT_ASSERT(!g.check_move(FIRST, BoardCell(4, 6), BoardCell(6, 4), die)); + + CPPUNIT_ASSERT(g.check_move(SECOND, BoardCell(1, 6), BoardCell(4, 3), die)); + CPPUNIT_ASSERT(g.check_move(SECOND, BoardCell(1, 6), BoardCell(7, 0), die)); + CPPUNIT_ASSERT(!g.check_move(SECOND, BoardCell(2, 6), BoardCell(4, 3), die)); + CPPUNIT_ASSERT(g.check_move(SECOND, BoardCell(1, 3), BoardCell(5, 7), die)); + CPPUNIT_ASSERT(g.check_move(SECOND, BoardCell(2, 6), BoardCell(5, 3), die)); + CPPUNIT_ASSERT(!g.check_move(SECOND, BoardCell(4, 6), BoardCell(3, 7), die)); + CPPUNIT_ASSERT(!g.check_move(SECOND, BoardCell(6, 7), BoardCell(1, 2), die)); + CPPUNIT_ASSERT(!g.check_move(SECOND, BoardCell(1, 2), BoardCell(2, 2), die)); return; } @@ -190,6 +231,8 @@ void TestGameState::test_kill() { g.board[5][5] = 'w'; g.board[6][4] = 'w'; g.board[4][3] = 'b'; + calculate(g); + CPPUNIT_ASSERT(g.kill(FIRST, BoardCell(2, 3))); CPPUNIT_ASSERT(!g.kill(FIRST, BoardCell(3, 5))); CPPUNIT_ASSERT(!g.kill(FIRST, BoardCell(6, 4))); @@ -214,6 +257,8 @@ void TestGameState::test_kill() { g.board[4][6] = 'W'; g.board[6][4] = 'b'; g.board[6][7] = 'B'; + calculate(g); + CPPUNIT_ASSERT(g.kill(FIRST, BoardCell(4, 6))); CPPUNIT_ASSERT(!g.kill(FIRST, BoardCell(3, 4))); CPPUNIT_ASSERT(!g.kill(FIRST, BoardCell(1, 5))); @@ -228,8 +273,8 @@ void TestGameState::test_kill() { void TestGameState::test_find_kill() { GameState g; - CPPUNIT_ASSERT(g.find_kill(FIRST) == BoardCell(-1, -1)); - CPPUNIT_ASSERT(g.find_kill(SECOND) == BoardCell(-1, -1)); + CPPUNIT_ASSERT(!g.find_kill(FIRST)); + CPPUNIT_ASSERT(!g.find_kill(SECOND)); for (int i = 0; i < g.SIZE; i++) for (int j = 0; j < g.SIZE; j++) g.board[i][j] = '.'; @@ -245,11 +290,10 @@ void TestGameState::test_find_kill() { g.board[5][5] = 'w'; g.board[6][4] = 'w'; g.board[4][3] = 'b'; - BoardCell A = g.find_kill(FIRST); - BoardCell B = g.find_kill(SECOND); - CPPUNIT_ASSERT(A == BoardCell(2, 3) || A == BoardCell(3, 2)); - CPPUNIT_ASSERT(B == BoardCell(1, 2) || B == BoardCell(2, 6) || - B == BoardCell(4, 3)); + calculate(g); + + CPPUNIT_ASSERT(g.find_kill(FIRST)); + CPPUNIT_ASSERT(g.find_kill(SECOND)); for (int i = 0; i < g.SIZE; i++) for (int j = 0; j < g.SIZE; j++) @@ -265,8 +309,9 @@ void TestGameState::test_find_kill() { g.board[4][6] = 'W'; g.board[6][4] = 'b'; g.board[6][7] = 'B'; - A = g.find_kill(FIRST); - CPPUNIT_ASSERT(A == BoardCell(4, 6)); + calculate(g); + + CPPUNIT_ASSERT(g.find_kill(FIRST)); return; } @@ -288,6 +333,8 @@ void TestGameState::test_who_moves() { g.board[5][5] = 'w'; g.board[6][4] = 'w'; g.board[4][3] = 'b'; + calculate(g); + g.last_move = BoardCell(2, 3); g.who_last = FIRST; g.type_last = 1; @@ -316,6 +363,8 @@ void TestGameState::test_who_moves() { g.board[4][6] = 'W'; g.board[6][4] = 'b'; g.board[6][7] = 'B'; + calculate(g); + g.last_move = BoardCell(4, 6); g.who_last = FIRST; g.type_last = 0; @@ -343,6 +392,8 @@ void TestGameState::test_move() { g.board[4][2] = 'w'; g.board[4][6] = 'W'; g.board[6][7] = 'W'; + calculate(g); + GameState cop = g; g.move(FIRST, BoardCell(3, 4), BoardCell(4, 3)); CPPUNIT_ASSERT(!(cop != g)); @@ -373,9 +424,9 @@ void TestGameState::test_move() { BoardCell(i, j) != BoardCell(6, 7) && BoardCell(i, j) != BoardCell(5, 5)) CPPUNIT_ASSERT(g.board[i][j] == cop.board[i][j]); - CPPUNIT_ASSERT(g.board[6][7] == '.'); - CPPUNIT_ASSERT(g.board[4][6] == '.'); - CPPUNIT_ASSERT(g.board[5][5] == 'W'); + CPPUNIT_ASSERT(g.board[6][7] == 'W'); + CPPUNIT_ASSERT(g.board[4][6] == 'W'); + CPPUNIT_ASSERT(g.board[5][5] == '.'); return; } @@ -395,17 +446,30 @@ void TestGameState::test_get_list() { g.board[4][6] = 'W'; g.board[6][4] = 'b'; g.board[6][7] = 'W'; - std::vector A{BoardCell(4, 5), BoardCell(5, 6), BoardCell(7, 6)}; + calculate(g); + + std::vector A; std::vector B{BoardCell(5, 5)}; - std::vector C{BoardCell(7, 3), BoardCell(7, 5)}; - std::vector D{BoardCell(0, 2), BoardCell(2, 4), BoardCell(3, 5), - BoardCell(5, 5), BoardCell(5, 7), BoardCell(7, 3)}; + std::vector C; + std::vector D{BoardCell(7, 3), BoardCell(0, 2)}; + + std::vector result; + g.get_list_of_correct_moves(FIRST, BoardCell(6, 7), result); + CPPUNIT_ASSERT(result == A); + result.clear(); + + g.get_list_of_correct_moves(FIRST, BoardCell(4, 6), result); + CPPUNIT_ASSERT(result == D); + result.clear(); - CPPUNIT_ASSERT(g.get_list_of_correct_moves(FIRST, BoardCell(6, 7)) == A); - CPPUNIT_ASSERT(g.get_list_of_correct_moves(FIRST, BoardCell(4, 6)) == D); g.who_last = FIRST; - CPPUNIT_ASSERT(g.get_list_of_correct_moves(SECOND, BoardCell(3, 7)) == B); - CPPUNIT_ASSERT(g.get_list_of_correct_moves(SECOND, BoardCell(6, 4)) == C); + g.get_list_of_correct_moves(SECOND, BoardCell(3, 7), result); + CPPUNIT_ASSERT(result == B); + result.clear(); + + g.get_list_of_correct_moves(SECOND, BoardCell(6, 4), result); + CPPUNIT_ASSERT(result == C); + result.clear(); return; } @@ -421,6 +485,8 @@ void TestGameState::test_check_win() { g.board[i][j] = '.'; for (int i = 0; i < g.SIZE; i++) g.board[0][i] = 'b', g.board[1][i] = 'w'; + calculate(g); + g.who_last = SECOND; CPPUNIT_ASSERT(g.check_win() == SECOND_WIN); g.who_last = FIRST; diff --git a/test_model/TestGameState.hpp b/test_model/TestGameState.hpp index 973133a..42c6d88 100644 --- a/test_model/TestGameState.hpp +++ b/test_model/TestGameState.hpp @@ -5,8 +5,12 @@ #include #include +#include "GameState.hpp" + class TestGameState : public CppUnit::TestFixture { private: + void calculate(GameState &G); + void test_init(); void test_ordinary(); void test_queen(); diff --git a/ui/Graphics.cpp b/ui/Graphics.cpp index 776772c..b254c3d 100644 --- a/ui/Graphics.cpp +++ b/ui/Graphics.cpp @@ -57,7 +57,8 @@ void Gra::draw_possible(std::list &render_list, GameState &game_state, BoardCell past, sf::Vector2f lu_point, sf::Vector2f rd_point) { sf::Vector2f size = rd_point - lu_point; - auto b = game_state.get_list_of_correct_moves(game_state.who_moves(), past); + std::vector b; + game_state.get_list_of_correct_moves(game_state.who_moves(), past, b); for (auto &a : b) { sf::RectangleShape block; block.setSize(size / 8); @@ -86,6 +87,12 @@ void Gra::draw_SafeLoad(std::list &render_list, sf::Vector2f lu_point, void Gra::drawing() { for (auto &elem : render_list) { window.draw(elem.picture); + if (elem.data2 != "") { + sf::Text texting(elem.data2, font, 40); + texting.setColor(sf::Color::Black); + texting.setPosition(elem.picture.getPosition()); + window.draw(texting); + } } window.display(); @@ -101,7 +108,8 @@ void Gra::update(Game &game, controller::IPlayer *player) { if (state.who_moves() == player->turn) { draw_possible(render_list, state, past); } - draw_history(render_list, game.number_of_states()); + draw_history(render_list, game.number_of_states(), game); + draw_current_player(render_list, game); } void Gra::compiling_event(Game &game) { @@ -127,8 +135,9 @@ void Gra::compiling_event(Game &game) { int y = res.data[0]; BoardCell next = {y, x}; - - if (game.return_current_state().check_move(game.return_current_state().who_moves(), past, next)) { + + bool die = false; + if (game.return_current_state().check_move(game.return_current_state().who_moves(), past, next, die)) { events.push(std::shared_ptr(new controller::MoveEvent(past, next))); } past = next; @@ -153,6 +162,10 @@ void Gra::compiling_event(Game &game) { if (past.x == -5) { press_the_scroll = 1; } + + if (past.x == -6) { + events.push(std::shared_ptr(new controller::GiveUpEvent())); + } } if (event.type == sf::Event::MouseButtonReleased) { press_the_scroll = 0; @@ -191,7 +204,7 @@ Gra::Frame &Gra::collision(sf::Vector2f posi) { std::queue> &Gra::get_events() { return events; } void Gra::draw_turn(std::list &render_list, - std::string , int number, + std::string str, int number, sf::Vector2f lu_point, sf::Vector2f rd_point) { sf::Vector2f size = rd_point - lu_point; @@ -202,13 +215,7 @@ void Gra::draw_turn(std::list &render_list, block.setFillColor(sf::Color::Green); block.setOutlineColor(sf::Color::Black); block.setOutlineThickness(2); - sf::Text text; - /*text.setString(str); - block.setSize(size / 2); - block.setPosition({0, 0}); - block.move(lu_point + size / 4); - //text.getTransform());*/ - render_list.push_back(Frame(block, 1, {-3, number}, "")); + render_list.push_back(Frame(block, 1, {-3, number}, str)); lu_point.x += size.x * 7 / 8; @@ -220,7 +227,7 @@ void Gra::draw_turn(std::list &render_list, render_list.push_back(Frame(block, 1, {-4, number}, "")); } -void Gra::draw_history(std::list &render_list, int maximum, +void Gra::draw_history(std::list &render_list, int maximum, Game& game, sf::Vector2f lu_point , sf::Vector2f rd_point ) { float dx = rd_point.x - lu_point.y; @@ -233,8 +240,13 @@ void Gra::draw_history(std::list &render_list, int maximum, delta = delta / 8; rd_point.y = lu_point.y + delta.y; - for (int i = (int)(maximum * possition_of_scroll); i < std::min(maximum, (int)(maximum * possition_of_scroll) + 8); i++) { - draw_turn(render_list, "", i, lu_point, rd_point); + + int start = (maximum * possition_of_scroll); + start = std::min(start, std::max(0, game.number_of_states()- 8)); + int finish = start + (std::min(8, game.number_of_states())); + + for (int i = start; i < finish; i++) { + draw_turn(render_list, game.natation[i], i, lu_point, rd_point); rd_point += delta; lu_point += delta; } @@ -259,13 +271,32 @@ void Gra::draw_history(std::list &render_list, int maximum, } Gra::Gra() { - window.setFramerateLimit(60); - b.loadFromFile("./sprites/b.png"); - B.loadFromFile("./sprites/B.png"); - W.loadFromFile("./sprites/W.png"); - w.loadFromFile("./sprites/w.png"); - sprites.emplace('b', &b); - sprites.emplace('B', &B); - sprites.emplace('W', &W); - sprites.emplace('w', &w); - } + window.setFramerateLimit(60); + b.loadFromFile("./sprites/b.png"); + B.loadFromFile("./sprites/B.png"); + W.loadFromFile("./sprites/W.png"); + w.loadFromFile("./sprites/w.png"); + sprites.emplace('b', &b); + sprites.emplace('B', &B); + sprites.emplace('W', &W); + sprites.emplace('w', &w); + + font.loadFromFile("./fonts/1.otf"); +} + + +void Gra::draw_current_player(std::list &render_list, Game& game, + sf::Vector2f lu_point, + sf::Vector2f rd_point) { + sf::Vector2f size = rd_point - lu_point; + sf::RectangleShape block; + block.setSize(size); + block.setPosition({0, 0}); + block.move(lu_point); + block.setFillColor(sf::Color::Green); + render_list.push_back(Frame(block, 0, {-1, 0}, std::to_string(game.return_current_state().who_moves() + 1) + " is moving")); + + block.move({0, 60}); + block.setFillColor(sf::Color::Blue); + render_list.push_back(Frame(block, 1, {-6, 0}, "Give up")); +} diff --git a/ui/Graphics.hpp b/ui/Graphics.hpp index 3d4df1b..bbd0dea 100644 --- a/ui/Graphics.hpp +++ b/ui/Graphics.hpp @@ -1,6 +1,8 @@ #ifndef CHECKERS_UI_DRAW_SMF_HPP_ #define CHECKERS_UI_DRAW_SMF_HPP_ +#define SFML_NO_DEPRECATED_WARNINGS + #include "Event.hpp" #include "Game.hpp" #include @@ -57,6 +59,8 @@ class Gra { float possition_of_scroll = 0; // [0, 0.9] bool press_the_scroll = 0; + sf::Font font; + public: sf::RenderWindow window = {sf::VideoMode(1280, 720), "Chess"}; void update(Game &game, controller::IPlayer *player); @@ -77,7 +81,7 @@ class Gra { void draw_table(std::list &rendrer_list, GameState &, int collision, sf::Vector2f lu_point = sf::Vector2f(320, 40), sf::Vector2f rd_point = sf::Vector2f(960, 680)); - void draw_history(std::list &render_list, int maximum, + void draw_history(std::list &render_list, int maximum, Game&, sf::Vector2f lu_point = sf::Vector2f(40, 40), sf::Vector2f rd_point = sf::Vector2f(280, 680)); void draw_possible(std::list &render_list, GameState &game_state, @@ -87,6 +91,9 @@ class Gra { void draw_SafeLoad(std::list &render_list, sf::Vector2f lu_point = sf::Vector2f(40, 40), sf::Vector2f rd_point = sf::Vector2f(280, 120)); + void draw_current_player(std::list &render_list, Game&, + sf::Vector2f lu_point = sf::Vector2f(1000, 330), + sf::Vector2f rd_point = sf::Vector2f(1240, 390)); }; #endif