#include using namespace Upp; enum { EMPTY, BLACK, WHITE }; enum { BOARD = 6 }; enum { STALL = -100000 }; struct Game { Point black[BOARD]; Point white[BOARD]; byte board[BOARD][BOARD]; Game Reversed(); void Move(int figure, Point pos); void Update(); void Paint(Draw& w); void Reset(); int Evaluate(); void EvaluateMove(int fig, Point pos, int& best, int& bfig, Point& bpos, int depth); int GetBest(int& fig, Point& pos, int depth); void Dump(); }; void Game::Dump() { LOG("-----------------"); for(int i = 0; i < BOARD; i++) { String ln; for(int j = 0; j < BOARD; j++) switch(board[j][i]) { case 0: ln << '.'; break; case BLACK: ln << '#'; break; case WHITE: ln << 'O'; break; } LOG(ln); } } int Game::Evaluate() { int q = 0; for(int i = 0; i < BOARD; i++) { if(black[i].y == BOARD - 1) return -1000; if(black[i].y >= 0) q--; if(white[i].y == 0) return 1000; if(white[i].y >= 0) q++; } return q; } void Game::EvaluateMove(int fig, Point pos, int& best, int& bfig, Point& bpos, int depth) { Game g2 = *this; g2.Move(fig, pos); int q; q = g2.Evaluate(); if(depth > 0 && q != 1000 && q != -1000) { LOGBEGIN(); LOG(">>>"); Game op = g2.Reversed(); Point d; int b; b = op.GetBest(b, d, q > best ? depth - 1 : depth - 2); if(b != STALL) if(b > 100) q = -b + 1; else if(b < -100) q = -b - 1; else q = -b; LOGEND(); } if(q > best) { best = q; bfig = fig; bpos = pos; } } int Game::GetBest(int& fig, Point& pos, int depth) { int best = STALL; for(int i = 0; i < BOARD; i++) if(white[i].y > 0) { Point p = white[i]; Game game = *this; p.y -= 2; if(p.y == BOARD - 1 - 2 && game.board[p.x][p.y] == 0) EvaluateMove(i, p, best, fig, pos, depth); p.y++; if(game.board[p.x][p.y] == 0) EvaluateMove(i, p, best, fig, pos, depth); p.x--; if(p.x >= 0 && game.board[p.x][p.y] == BLACK) EvaluateMove(i, p, best, fig, pos, depth); p.x += 2; if(p.x <= BOARD - 1 && game.board[p.x][p.y] == BLACK) EvaluateMove(i, p, best, fig, pos, depth); } if(best == STALL) LOG("STALL"); else { LOG("BEST"); Game game = *this; game.Move(fig, pos); game.Dump(); } return best; } inline Point Reverse(Point p) { return Point(p.x, p.y >= 0 ? BOARD - 1 - p.y : -1); } Game Game::Reversed() { Game game; for(int i = 0; i < BOARD; i++) { game.black[i] = Reverse(white[i]); game.white[i] = Reverse(black[i]); } game.Update(); return game; } void Game::Update() { memset(board, 0, sizeof(board)); for(int i = 0; i < BOARD; i++) { if(black[i].y >= 0) board[black[i].x][black[i].y] = BLACK; if(white[i].y >= 0) board[white[i].x][white[i].y] = WHITE; } } void Game::Move(int i, Point pos) { if(board[pos.x][pos.y] == BLACK) for(int i = 0; i < BOARD; i++) if(black[i] == pos) { black[i].y = -1; break; } board[white[i].x][white[i].y] = 0; white[i] = pos; board[pos.x][pos.y] = WHITE; } void Game::Reset() { for(int i = 0; i < BOARD; i++) { black[i].x = white[i].x = i; white[i].y = BOARD - 1; black[i].y = 0; } Update(); } void Game::Paint(Draw& w) { for(int i = 0; i < BOARD; i++) for(int j = 0; j < BOARD; j++) { w.DrawRect(i * 32, j * 32, 32, 32, (i ^ j) & 1 ? White : LtGray); if(board[i][j]) { Rect r = RectC(i * 32 + 8, j * 32 + 8, 16, 16); w.DrawRect(r, Black); w.DrawRect(r.Deflated(2, 2), board[i][j] == WHITE ? White : Gray); } } } struct Chess : TopWindow { Game game; int moveno; virtual void Paint(Draw& w) { game.Paint(w); w.DrawText(0, 0, AsString(moveno + 1)); } void Result() { int q = game.Evaluate(); PromptOK(q == 0 ? "Tie" : q > 0 ? "White has won" : "Black has won"); game.Reset(); Refresh(); moveno = 0; if(rand() & 1) BlackMove(); } void BlackMove() { int fig; Point pos; if(game.Evaluate() == 1000 || game.GetBest(fig, pos, 0) == STALL) { Result(); return; } Game g = game.Reversed(); if(g.GetBest(fig, pos, moveno++ ? 9 : 0) != STALL) { g.Move(fig, pos); game = g.Reversed(); if(game.Evaluate() == -1000 || game.GetBest(fig, pos, 0) == STALL) Result(); } else Result(); Refresh(); } void WhiteMove(int fig, Point pos) { game.Move(fig, pos); Refresh(); Sync(); BlackMove(); } virtual void LeftDown(Point p, dword flags) { p /= 32; if(p.x >= 0 && p.x <= BOARD && p.y >= 0 && p.y <= BOARD) { for(int i = 0; i < BOARD; i++) { Point pp = game.white[i]; if(pp.y > 0) { pp.y -= 2; if(p.y == BOARD - 1 - 2 && pp == p && game.board[pp.x][pp.y] == 0) { WhiteMove(i, p); return; } pp.y++; if(pp == p && game.board[pp.x][pp.y] == 0) { WhiteMove(i, p); return; } pp.x -= 1; if(pp == p && p.x >= 0 && game.board[pp.x][pp.y] == BLACK) { WhiteMove(i, p); return; } pp.x += 2; if(pp == p && p.x <= BOARD - 1 && game.board[pp.x][pp.y] == BLACK) { WhiteMove(i, p); return; } } } } BeepExclamation(); } Chess() { SetRect(0, 0, 32 * BOARD, 32 * BOARD); game.Reset(); moveno = 0; BlackMove(); } }; GUI_APP_MAIN { Chess chess; chess.Run(); }