0,0 → 1,619 |
// |
// 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(); |
} |
} |
// 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(2,2,40,20,3,0xe0e0e0); |
__menuet__write_text(8,8,0x333333,"New",3); |
__menuet__window_redraw(2); |
} |
|
void app_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; |
|
|
} |
} |
} |
|