forked from KolibriOS/kolibrios
cd74d1af33
git-svn-id: svn://kolibrios.org@5098 a494cfbc-eb01-0410-851d-a64ba20cac60
651 lines
13 KiB
C
651 lines
13 KiB
C
//
|
|
// KReversi.java
|
|
// The Othello Game, based on the algorithm of Muffy Barkocy
|
|
// (muffy@fish.com).
|
|
//
|
|
// The strategy is very very simple. The best move for the computer
|
|
// is the move that flip more pieces (preferring boards line and
|
|
// corners) and give less pieces to move to the opponent.
|
|
//
|
|
// Author: Alex "Kazuma" Garbagnati (kazuma@energy.it)
|
|
// Date: 20 Jan 96
|
|
// L.R.: 26 Jan 96
|
|
// Note:
|
|
//
|
|
|
|
|
|
|
|
#include<menuet/os.h>
|
|
#include<stdint.h>
|
|
#include<stdlib.h>
|
|
#include<stdio.h>
|
|
#include<ctype.h>
|
|
#include<string.h>
|
|
|
|
typedef unsigned int u32;
|
|
|
|
int YSHIFT= 33;
|
|
|
|
int ENGLISH = 0; //
|
|
int ITALIAN = 1; // Languages
|
|
int EXTERNAL = 2; //
|
|
|
|
#define BLACK 0x000000; //
|
|
#define BLACK_S 0x333333; //
|
|
#define WHITE 0xffffff; // Colors
|
|
#define WHITE_S 0xaaaaaa; //
|
|
|
|
|
|
int NOMOVE = 0; //
|
|
int REALMOVE = 1; // Type of move
|
|
int PSEUDOMOVE = 2; //
|
|
|
|
int Empty = 0; //
|
|
int User = 1; // Board's owners
|
|
int Computer = 2; //
|
|
|
|
#define true 1
|
|
#define false 0
|
|
|
|
int UserMove = true;
|
|
int GameOver = false;
|
|
int CopyWinOn = false;
|
|
int StillInitiated = false; // This solve a little
|
|
// problem on reinit.
|
|
|
|
int TheBoard[8][8]; // Board
|
|
int Score[8][8];
|
|
int OpponentScore[8][8];
|
|
|
|
|
|
|
|
//
|
|
// DrawBoard
|
|
// (paint the Othello Board, a 8X8 green square table)
|
|
//
|
|
// Input: graphic (Graphics)
|
|
// Output: none
|
|
// Notes:
|
|
//
|
|
void DrawBoard() {
|
|
|
|
int i;
|
|
for(i=0;i<=8;i++)
|
|
{
|
|
__asm__ __volatile__("int $0x40"::"a"(38),"b"(320),"c"(YSHIFT+(YSHIFT+(40*i))*65536+40*i),"d"(0x555555));
|
|
__menuet__line((40*i),YSHIFT,(40*i),353,0x555555); // horizontal
|
|
|
|
}
|
|
|
|
}
|
|
// End of DrawBoard
|
|
|
|
|
|
//
|
|
// DrawPiece
|
|
// (paint a piece, black or white, I'm using an 8x8 array, so
|
|
// from the input values for rows and cols must be
|
|
// subtracted 1)
|
|
//
|
|
// Input: who (int),
|
|
// column (int),
|
|
// row (int)
|
|
// Output: none
|
|
// Notes:
|
|
//
|
|
void DrawPiece(int Who, int Col, int Row) {
|
|
int pCol = (40*(Col-1)+1);
|
|
int pRow = YSHIFT+(40*(Row-1)+1);
|
|
u32 pColor,pShadow;
|
|
|
|
if (Who == User) {
|
|
pColor = BLACK;
|
|
pShadow = BLACK_S;
|
|
} else {
|
|
pColor = WHITE;
|
|
pShadow = WHITE_S;
|
|
}
|
|
TheBoard[Col-1][Row-1] = Who;
|
|
|
|
__menuet__bar(pCol+9,pRow+9,19,19,pColor);
|
|
}
|
|
// End of DrawPiece
|
|
|
|
|
|
//
|
|
// MsgWhoMove
|
|
// (paint the message informing who's move)
|
|
//
|
|
// Input: is user ? (int)
|
|
// Output: none
|
|
// Notes:
|
|
//
|
|
void MsgWhoMove(int UM) {
|
|
}
|
|
// End of MsgWhoMove
|
|
|
|
|
|
//
|
|
// FlipRow
|
|
// (calculate number of pieces are flipped by a move
|
|
// and return it. Eventually do the complete or pseudo
|
|
// move)
|
|
//
|
|
// Input: who (int)
|
|
// which board (int[][])
|
|
// position col, row (int)
|
|
// direction col, row (int)
|
|
// make move ? (int)
|
|
//
|
|
int FlipRow(int Who, int WhichBoard[8][8] , int C, int R,
|
|
int CInc, int RInc, int MakeMove) {
|
|
int NewCol;
|
|
int NewRow;
|
|
int Opponent = User + Computer - Who;
|
|
int CNT = 0;
|
|
|
|
NewCol = C - 1;
|
|
NewRow = R - 1;
|
|
while (true) {
|
|
if (((NewCol+CInc) < 0) || ((NewCol+CInc) > 7) ||
|
|
((NewRow+RInc) < 0) || ((NewRow+RInc) > 7)) {
|
|
return 0;
|
|
}
|
|
if (WhichBoard[NewCol+CInc][NewRow+RInc] == Opponent) {
|
|
CNT++;
|
|
NewCol += CInc;
|
|
NewRow += RInc;
|
|
} else if (WhichBoard[NewCol+CInc][NewRow+RInc] == Empty) {
|
|
return 0;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
if (MakeMove != NOMOVE) {
|
|
C--;
|
|
R--;
|
|
int v;
|
|
for(v=0; v<=CNT; v++) {
|
|
if (MakeMove == REALMOVE) {
|
|
DrawPiece(Who, C+1, R+1);
|
|
} else {
|
|
WhichBoard[C][R] = Who;
|
|
}
|
|
C += CInc;
|
|
R += RInc;
|
|
}
|
|
}
|
|
return CNT;
|
|
}
|
|
// End of FlipRow
|
|
|
|
|
|
//
|
|
// IsLegalMove
|
|
// (verify that the move is legal)
|
|
//
|
|
// Input: who (int)
|
|
// board (int[][])
|
|
// position col, row (int)
|
|
// Output: is legal ? (int)
|
|
// Notes:
|
|
//
|
|
int IsLegalMove(int Who, int WhichBoard[8][8] , int C, int R) {
|
|
if (WhichBoard[C-1][R-1] != Empty) {
|
|
return false;
|
|
}
|
|
int CInc,RInc;
|
|
for (CInc=-1; CInc<2; CInc++) {
|
|
for (RInc=-1; RInc<2; RInc++) {
|
|
if (FlipRow(Who, WhichBoard, C, R, CInc, RInc, NOMOVE) > 0) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
// End of IsLegalMove
|
|
|
|
|
|
//
|
|
// MakeMove
|
|
// (make the move)
|
|
//
|
|
// Input: who (int)
|
|
// position col, row (int)
|
|
// Output: false=EndGame, true=next player (int)
|
|
// Notes:
|
|
//
|
|
int MakeMove(int Who, int C, int R) {
|
|
int CInc,RInc;
|
|
for (CInc=-1; CInc<2; CInc++) {
|
|
for (RInc=-1; RInc<2; RInc++) {
|
|
FlipRow(Who, TheBoard, C, R, CInc, RInc, REALMOVE);
|
|
}
|
|
}
|
|
if (IsBoardComplete() ||
|
|
((!ThereAreMoves(Computer, TheBoard)) && (!ThereAreMoves(User, TheBoard)))) {
|
|
return false;
|
|
}
|
|
int Opponent = (User + Computer) - Who;
|
|
if (ThereAreMoves(Opponent, TheBoard)) {
|
|
UserMove = !UserMove;
|
|
}
|
|
return true;
|
|
}
|
|
// End of MakeMove
|
|
|
|
|
|
//
|
|
// EndGame
|
|
// (shows the winning message)
|
|
//
|
|
// Input: none
|
|
// Output: none
|
|
// Notes:
|
|
//
|
|
void EndGame() {
|
|
int CompPieces = 0;
|
|
int UserPieces = 0;
|
|
char *WinMsg_W = "Computer Won";
|
|
char *WinMsg_L = "User Won";
|
|
char *WinMsg_T = "???";
|
|
char *TheMsg;
|
|
|
|
int StrWidth;
|
|
|
|
int c,r;
|
|
for (c=0; c<8; c++) {
|
|
for (r=0; r<8; r++) {
|
|
if (TheBoard[c][r] == Computer) {
|
|
CompPieces++;
|
|
} else {
|
|
UserPieces++;
|
|
}
|
|
}
|
|
}
|
|
if (CompPieces > UserPieces) {
|
|
TheMsg = WinMsg_W;
|
|
} else if (UserPieces > CompPieces) {
|
|
TheMsg = WinMsg_L;
|
|
} else {
|
|
TheMsg = WinMsg_T;
|
|
}
|
|
|
|
__menuet__write_text(100,8,0xff0000,TheMsg,strlen(TheMsg));
|
|
|
|
}
|
|
// End of EndGame
|
|
|
|
|
|
//
|
|
// IsBoardComplete
|
|
// (checks if the board is complete)
|
|
//
|
|
// Input: none
|
|
// Output: the board is complete ? (int)
|
|
// Notes:
|
|
//
|
|
int IsBoardComplete() {
|
|
int i,j;
|
|
for (i=0; i<8; i++) {
|
|
for (j=0; j<8; j++) {
|
|
if (TheBoard[i][j] == Empty) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
// End of IsBoardComplete
|
|
|
|
|
|
//
|
|
// ThereAreMoves
|
|
// (checks if there are more valid moves for the
|
|
// player)
|
|
//
|
|
// Input: player (int)
|
|
// board (int[][])
|
|
// Output: there are moves ? (int)
|
|
// Notes:
|
|
//
|
|
int ThereAreMoves(int Who, int WhichBoard[8][8] ) {
|
|
int i,j;
|
|
for (i=1; i<=8; i++) {
|
|
for (j=1; j<=8; j++) {
|
|
if (IsLegalMove(Who, WhichBoard, i, j)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
// End of ThereAreMoves
|
|
|
|
|
|
//
|
|
// CalcOpponentScore
|
|
// (calculate the totalScore of opponent after
|
|
// a move)
|
|
//
|
|
// Input: position x, y (int)
|
|
// Output: score (int)
|
|
// Notes:
|
|
//
|
|
int CalcOpponentScore(int CP, int RP) {
|
|
int OpScore = 0;
|
|
int tempBoard[8][8]; // = new int[8][8];
|
|
int c,r;
|
|
for (c=0; c<8; c++) {
|
|
for (r=0; r<8; r++) {
|
|
tempBoard[c][r] = TheBoard[c][r];
|
|
}
|
|
}
|
|
int CInc,RInc;
|
|
for (CInc=-1; CInc<2; CInc++) {
|
|
for (RInc=-1; RInc<2; RInc++) {
|
|
FlipRow(Computer, tempBoard, CP+1, RP+1, CInc, RInc, PSEUDOMOVE);
|
|
}
|
|
}
|
|
if (ThereAreMoves(User, tempBoard)) {
|
|
int C,R;
|
|
for (C=0; C<8; C++) {
|
|
for (R=0; R<8; R++) {
|
|
OpScore += RankMove(User, tempBoard, C, R);
|
|
}
|
|
}
|
|
}
|
|
return OpScore;
|
|
}
|
|
// End of CalcOpponentScore()
|
|
|
|
|
|
//
|
|
// RankMoves
|
|
// (rank all moves for the computer)
|
|
//
|
|
// Input: none
|
|
// Output: none
|
|
// Notes:
|
|
//
|
|
void RankMoves() {
|
|
int C,R;
|
|
for (C=0; C<8; C++) {
|
|
for (R=0; R<8; R++) {
|
|
Score[C][R] = RankMove(Computer, TheBoard, C, R);
|
|
if (Score[C][R] != 0) {
|
|
OpponentScore[C][R] = CalcOpponentScore(C, R);
|
|
} else {
|
|
OpponentScore[C][R] = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// End of RankMoves
|
|
|
|
|
|
//
|
|
// RankMove
|
|
// (rank a move for a player on a board)
|
|
//
|
|
// Input: who moves (int)
|
|
// on which board (int[][])
|
|
// position col, row (int)
|
|
// Output: flipped pieces (int)
|
|
// Notes: best are corner, then border lines,
|
|
// worst are line near to border lines
|
|
//
|
|
int RankMove(int Who, int WhichBoard[8][8], int Col, int Row) {
|
|
int CNT = 0;
|
|
int MV = 0;
|
|
|
|
if (WhichBoard[Col][Row] != Empty) {
|
|
return 0;
|
|
}
|
|
int CInc,RInc;
|
|
for (CInc=-1; CInc<2; CInc++) {
|
|
for (RInc=-1; RInc<2; RInc++) {
|
|
MV = FlipRow(Who, WhichBoard, Col+1, Row+1, CInc, RInc, NOMOVE);
|
|
CNT += MV;
|
|
}
|
|
}
|
|
if (CNT > 0) {
|
|
if (((Col == 0) || (Col == 7)) ||
|
|
((Row == 0) || (Row == 7))) {
|
|
CNT = 63;
|
|
}
|
|
if (((Col == 0) || (Col == 7)) &&
|
|
((Row == 0) || (Row == 7))) {
|
|
CNT = 64;
|
|
}
|
|
if ((((Col == 0) || (Col == 7)) && (Row == 1) || (Row == 6)) &&
|
|
(((Col == 1) || (Col == 6)) && (Row == 0) || (Row == 7)) &&
|
|
(((Col == 1) || (Col == 6)) && (Row == 1) || (Row == 6))) {
|
|
CNT = 1;
|
|
}
|
|
}
|
|
return CNT;
|
|
}
|
|
// End of RankMove
|
|
|
|
|
|
//
|
|
// BestMove
|
|
// (calculate and execute the best move)
|
|
//
|
|
// Input: none
|
|
// Output: value, col & row (int[3])
|
|
// Notes:
|
|
//
|
|
void BestMove (int retval[3]) {
|
|
|
|
retval[0] = -998; // move value;
|
|
retval[1] = 0; // column
|
|
retval[2] = 0; // row
|
|
|
|
RankMoves();
|
|
int C,R;
|
|
for (C=0; C<8; C++) {
|
|
for (R=0; R<8; R++) {
|
|
if ((Score[C][R] == 0) && (OpponentScore[C][R] == 0)) {
|
|
Score[C][R] = -999;
|
|
} else if (Score[C][R] != 64) {
|
|
Score[C][R] = Score[C][R] - OpponentScore[C][R];
|
|
}
|
|
}
|
|
}
|
|
for (C=0; C<8; C++) {
|
|
for (R=0; R<8; R++) {
|
|
if (Score[C][R] > retval[0]) {
|
|
retval[1] = C;
|
|
retval[2] = R;
|
|
retval[0] = Score[C][R];
|
|
}
|
|
}
|
|
}
|
|
retval[1]++;
|
|
retval[2]++;
|
|
// return retval;
|
|
}
|
|
// End of BestMove
|
|
|
|
|
|
|
|
|
|
//
|
|
// paint
|
|
//
|
|
void paint() {
|
|
// MsgWhoMove(UserMove);
|
|
if (!CopyWinOn) {
|
|
int i,j;
|
|
for (i=0; i<8; i++) {
|
|
for (j=0; j<8; j++) {
|
|
if (TheBoard[i][j] != Empty) {
|
|
DrawPiece(TheBoard[i][j], i+1, j+1);
|
|
}
|
|
}
|
|
}
|
|
// } else {
|
|
// ShowAbout();
|
|
}
|
|
|
|
int _user = 0;
|
|
int _computer = 0;
|
|
int c, r;
|
|
|
|
for (c=0; c<8; c++)
|
|
for (r=0; r<8; r++) {
|
|
if (TheBoard[c][r] == User)
|
|
_user++;
|
|
if (TheBoard[c][r] == Computer)
|
|
_computer++;
|
|
}
|
|
|
|
// do not use sprintf function here please! ( sprintf(score, "User: %d - Computer: %d", _user, _computer); )
|
|
char score[64];
|
|
char tmp[8];
|
|
strcpy(score, "User (black): ");
|
|
itoa(_user++, tmp, 10);
|
|
strcat(score, tmp);
|
|
strcat(score, " - Computer (white): ");
|
|
itoa(_computer++, tmp, 10);
|
|
strcat(score, tmp);
|
|
|
|
__menuet__bar(58, 8, 250, 16, 0x777777);
|
|
__menuet__write_text(58,8,0x333333,score, strlen(score));
|
|
|
|
|
|
}
|
|
// End of paint
|
|
|
|
|
|
//
|
|
// init
|
|
//
|
|
void init() {
|
|
// This is the right size of the applet 321x387
|
|
// resize(321,387);
|
|
// I set twice the language. That's because if anybody
|
|
// forget a string in an external language file, are
|
|
// used english strings.
|
|
if (!StillInitiated) {
|
|
StillInitiated = true;
|
|
}
|
|
int i,j;
|
|
for (i=0; i<8; i++) {
|
|
for (j=0; j<8; j++) {
|
|
TheBoard[i][j] = 0;
|
|
}
|
|
}
|
|
TheBoard[3][3] = User;
|
|
TheBoard[3][4] = Computer;
|
|
TheBoard[4][3] = Computer;
|
|
TheBoard[4][4] = User;
|
|
UserMove = true;
|
|
// MsgWhoMove(true);
|
|
// repaint();
|
|
}
|
|
// End of init
|
|
|
|
|
|
|
|
|
|
|
|
void paint_win(void)
|
|
{
|
|
__menuet__window_redraw(1);
|
|
__menuet__define_window(100,100,330,400,0x33777777,0,"Reversi");
|
|
__menuet__make_button(4,4,40,20,3,0xe0e0e0);
|
|
__menuet__write_text(8,8,0x333333,"New",3);
|
|
__menuet__window_redraw(2);
|
|
}
|
|
|
|
void main(void)
|
|
{
|
|
int i;
|
|
u32 mouse_coord;
|
|
u32 mouse_butn;
|
|
int X,Y;
|
|
|
|
int TheCol, TheRow;
|
|
int BMove[3];
|
|
int BX, BY;
|
|
int retval = false;
|
|
|
|
|
|
__menuet__set_bitfield_for_wanted_events(EVENT_REDRAW + EVENT_KEY + EVENT_BUTTON + EVENT_MOUSE_CHANGE);
|
|
paint_win();
|
|
DrawBoard();
|
|
init();
|
|
paint();
|
|
|
|
for(;;)
|
|
{
|
|
i=__menuet__wait_for_event();
|
|
switch(i)
|
|
{
|
|
case 1:
|
|
paint_win();
|
|
DrawBoard();
|
|
paint();
|
|
continue;
|
|
case 2:
|
|
__menuet__getkey();
|
|
continue;
|
|
case 3:
|
|
if(__menuet__get_button_id()==1) {
|
|
__menuet__sys_exit();}
|
|
else
|
|
paint_win();
|
|
init();
|
|
DrawBoard();
|
|
paint();
|
|
continue;
|
|
case 4:
|
|
continue;
|
|
case 5:
|
|
continue;
|
|
case 6:
|
|
__asm__ __volatile__("int $0x40":"=a"(mouse_butn):"0"(37),"b"(2));
|
|
__asm__ __volatile__("int $0x40":"=a"(mouse_coord):"0"(37),"b"(1));
|
|
X = mouse_coord >> 16;
|
|
Y = mouse_coord & 0xffff;
|
|
|
|
// Process a normal click in the board
|
|
BX = X;
|
|
BY = Y - YSHIFT;
|
|
|
|
|
|
if ((BY >= 0) && (BY <= 321) &&
|
|
(mouse_butn !=0) && (UserMove)) {
|
|
TheCol = (int)((BX/40)+1);
|
|
TheRow = (int)((BY/40)+1);
|
|
|
|
if (IsLegalMove(User, TheBoard, TheCol, TheRow)) {
|
|
retval = MakeMove(User, TheCol, TheRow);
|
|
while (retval && (!UserMove)) {
|
|
//MsgWhoMove(UserMove);
|
|
BestMove(BMove);
|
|
|
|
retval = MakeMove(Computer, BMove[1], BMove[2]);
|
|
//MsgWhoMove(UserMove);
|
|
}
|
|
if (!retval) {
|
|
EndGame();
|
|
}
|
|
}
|
|
paint();
|
|
}
|
|
continue;
|
|
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
/* We use LIBC only for strcpy/itoa, so we don't need CRT startup code */
|
|
int __bss_count;
|
|
void __crt1_startup() { main(); }
|