1 /****************************************************************************
4 Copyright (c) 2001-2004 Jerome Jacovella-St-Louis
6 ****************************************************************************/
10 enum ChipColor : byte { blue, green, empty };
13 define CLIENT = green;
15 define NUM_COLUMNS = 8;
21 define OTHELLO_PORT = 7777;
23 enum OthelloMessage : byte { newGame = 1, position };
34 // --- Othello Window Class ---
35 class Othello : Window
38 bool hosting, gameRunning, local;
40 int numChips[ChipColor];
41 OthelloSocket sockets[ChipColor];
42 ChipColor board[NUM_ROWS][NUM_COLUMNS];
44 OthelloService service { port = OTHELLO_PORT, othello = this };
47 background = black, tabCycle = true, text = "ECERE Othello", borderStyle = sizable, hasClose = true,
48 size.h = 480, clientSize.w = NUM_COLUMNS*WIDTH;
50 // --- Othello Utilities ---
51 int TurnChipsDirection(int sx, int sy, int dx, int dy, ChipColor color, int turn)
59 // Out of the board...
60 if(sx < 0 || sx >= NUM_COLUMNS || sy < 0 || sy >= NUM_ROWS)
63 // Chip of the same color...
64 if(board[sy][sx] == color || board[sy][sx] == empty)
68 x >= 0 && x < NUM_COLUMNS && y >= 0 && y < NUM_ROWS;
71 // Chip of the same color at the end of the line...
72 if(board[y][x] == color)
77 x >= 0 && x < NUM_COLUMNS && y >= 0 && y < NUM_ROWS;
80 if(board[y][x] == color)
89 else if(board[y][x] == empty)
91 // Chip of the opponent's color...
96 // No chip of the same color at the end...
102 bool validMove = false;
104 for(y = 0; y<NUM_ROWS && !validMove; y++)
105 for(x = 0; x<NUM_COLUMNS && !validMove; x++)
106 if(board[y][x] == empty && TurnChips(x, y, turn, 0))
111 int TurnChips(int sx, int sy, ChipColor color, int turn)
116 for(y = -1; y <= 1; y++)
117 for(x = -1; x <= 1; x++)
119 numChips += TurnChipsDirection(sx, sy, x,y, color, turn);
122 board[sy][sx] = color;
123 this.numChips[color] += numChips + 1;
124 this.numChips[1-color] -= numChips;
143 for(y = 0; y<NUM_ROWS; y++)
144 for(x = 0; x<NUM_COLUMNS; x++)
146 board[3][3] = board[4][4] = blue;
147 board[3][4] = board[4][3] = green;
148 numChips[blue] = numChips[green] = 2;
156 join.disabled = false;
157 host.disabled = false;
158 disconnect.disabled = false;
159 stop.disabled = false;
160 localGame.disabled = false;
162 if(gameRunning || hosting || sockets[SERVER])
163 localGame.disabled = true;
165 stop.disabled = true;
166 if(!gameRunning && !sockets[SERVER])
167 disconnect.disabled = true;
169 if(hosting || sockets[SERVER] || local)
170 host.disabled = true;
172 if(sockets[SERVER] || local || hosting)
173 join.disabled = true;
175 address.disabled = join.disabled;
181 parent = this, text = "Local Game", position = Point{ 160, 330 }, size = Size { 100, 20 }, hotKey = altL;
183 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
196 parent = this, text = "Host", position = Point { 10, 330 }, size = Size { 60, 20 }, hotKey = altH;
197 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
211 parent = this, text = "Join", position = Point{ 10, 370 }, size = Size { 40, 20 }, hotKey = altJ;
212 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
214 OthelloSocket socket { othello = this };
215 if(socket.Connect(address.line.text, OTHELLO_PORT))
217 sockets[SERVER] = socket;
226 parent = this, text = "Disconnect", position = Point { 170, 370 }, size = Size { 100, 20 }, hotKey = altD;
227 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
230 sockets[SERVER].Disconnect(0);
231 else if(sockets[CLIENT])
232 sockets[CLIENT].Disconnect(0);
246 parent = this, text = "Stop", position = Point { 80, 330 }, size = Size { 60, 20 }, hotKey = altS;
247 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
256 EditBox address { textHorzScroll = true, line.text = "localhost", parent = this, position = Point{ 60, 370 }, size = Size { 100, 20 } };
258 // Window class implementation
268 delete sockets[blue];
269 delete sockets[green];
272 BitmapResource jetonGreen { ":green.bmp", window = this };
273 BitmapResource jetonBlue { ":blue.bmp", window = this };
274 BitmapResource back { ":othello.bmp", window = this };
276 void OnRedraw(Surface surface)
279 surface.Blit(back.bitmap, 0,0, 0,0, back.bitmap.width, back.bitmap.height);
285 for (y=0; y<NUM_ROWS; y++)
287 for (x=0; x<NUM_COLUMNS; x++)
292 surface.Blit(jetonBlue.bitmap, x * WIDTH, y * HEIGHT, 0,0, WIDTH-1, HEIGHT-1);
295 surface.Blit(jetonGreen.bitmap, x * WIDTH, y * HEIGHT, 0,0, WIDTH-1, HEIGHT-1);
304 surface.SetForeground(white);
305 surface.SetBackground(blue);
306 surface.TextOpacity(true);
310 surface.SetForeground(blue);
311 surface.TextOpacity(false);
313 surface.WriteTextf(10, 400, "blue: %d", numChips[blue]);
317 surface.SetForeground(black);
318 surface.SetBackground(green);
319 surface.TextOpacity(true);
323 surface.SetForeground(green);
324 surface.TextOpacity(false);
326 surface.WriteTextf(210, 400, "green: %d", numChips[green]);
328 surface.TextOpacity(false);
329 surface.SetForeground(tomato);
331 surface.WriteTextf(100, 420, "GAME OVER");
332 else if(!local && sockets[1-turn])
333 surface.WriteTextf(50, 420, "It is your turn to move.");
337 bool OnKeyDown(Key key, unichar ch)
339 if(key == escape) Destroy(0);
343 bool OnLeftButtonDown(int x, int y, Modifiers mods)
348 if(sockets[1-turn] || local)
350 if(x < NUM_COLUMNS && y < NUM_ROWS && board[y][x] == empty)
352 OPacket packet { position, turn, (byte)x, (byte)y };
353 if(TurnChips(x, y, turn, 1))
356 sockets[1-packet.player].Send((byte *)&packet, sizeof(OPacket));
364 // --- Othello Communication ---
365 class OthelloSocket : Socket
368 void OnDisconnect(int code)
370 if(this == othello.sockets[CLIENT])
372 othello.sockets[CLIENT] = null;
373 othello.gameRunning = false;
375 else if(this == othello.sockets[SERVER])
377 othello.sockets[SERVER] = null;
378 othello.gameRunning = false;
381 othello.EnableButtons();
382 othello.Update(null);
385 uint OnReceive(const byte * buffer, uint count)
387 if(count >= sizeof(OPacket))
389 OPacket packet = *(OPacket *)buffer;
393 othello.TurnChips(packet.x, packet.y, packet.player, 1);
396 othello.gameRunning = true;
400 return sizeof(OPacket);
407 othello.sockets[SERVER] = this;
408 othello.gameRunning = true;
409 othello.EnableButtons();
413 property Othello othello { set { othello = value; } }
416 class OthelloService : Service
421 if(!othello.sockets[CLIENT] && !othello.gameRunning)
423 OPacket packet { newGame };
425 othello.sockets[CLIENT] = OthelloSocket { this, othello = othello };
426 othello.sockets[CLIENT].Send((byte *)&packet, sizeof(OPacket));
429 othello.gameRunning = true;
430 othello.EnableButtons();
431 othello.Update(null);
434 property Othello othello { set { othello = value; } }