ultimatepp/uppdev/Chess/main.cpp
cxl 3cd394812c Merge continued
git-svn-id: svn://ultimatepp.org/upp/trunk@10263 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2016-10-04 08:34:39 +00:00

274 lines
5.4 KiB
C++

#include <CtrlLib/CtrlLib.h>
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();
}