home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1999 mARCH
/
PCWK3A99.iso
/
Linux
/
DDD331
/
DDD-3_1_.000
/
DDD-3_1_
/
ddd-3.1.1
/
ddd
/
tictactoe.C
< prev
next >
Wrap
C/C++ Source or Header
|
1998-12-02
|
12KB
|
563 lines
// $Id: tictactoe.C,v 1.7 1998/12/02 10:23:47 zeller Exp $ -*- C++ -*-
// Tic-Tac-Toe Game
// Copyright (C) 1998 Technische Universitaet Braunschweig, Germany.
// Written by Andreas Zeller <zeller@ips.cs.tu-bs.de>.
//
// This file is part of DDD.
//
// DDD is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// DDD is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with DDD -- see the file COPYING.
// If not, write to the Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// DDD is the data display debugger.
// For details, see the DDD World-Wide-Web page,
// `http://www.cs.tu-bs.de/softech/ddd/',
// or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
// Based on a Java program by Scott L. Patterson <scott@uniqsys.com>.
// See http://www.uniqsys.com/~scpatt/java/TicTacToe/ for details.
char tictactoe_rcsid[] =
"$Id: tictactoe.C,v 1.7 1998/12/02 10:23:47 zeller Exp $";
#ifdef __GNUG__
#pragma implementation
#endif
#include "tictactoe.h"
#include "icons/tictactoe/circle.xbm"
#include "icons/tictactoe/cross.xbm"
#include "icons/tictactoe/empty.xbm"
#include <Xm/Xm.h>
#include <Xm/RowColumn.h>
#include <Xm/PushB.h>
#include <Xm/SelectioB.h> // XmCreatePromptDialog()
#include <iostream.h>
#include <unistd.h>
#include "Command.h"
#include "Delay.h"
#include "DestroyCB.h"
#include "HelpCB.h"
#include "InitImage.h"
#include "LessTifH.h"
#include "TimeOut.h"
#include "assert.h"
#include "bool.h"
#include "cook.h"
#include "verify.h"
#include "wm.h"
#include "status.h"
#include "version.h"
// Board is: 1 2 3
// 4 5 6
// 7 8 9
static int board[10];
static bool winning[10];
static Widget buttons[10];
#define NO_ONE 0
#define PLAYER1 1
#define PLAYER2 4
#define CATSEYE -1
// Search the rows for a near win
static bool moveRow(int current_player)
{
for (int x = 0; x < 3; x++)
{
int sum = 0;
for (int y = 1; y < 4; y++)
sum += board[(x * 3) + y];
// Almost a win -- block it
if (sum == (current_player * 2))
for (int y = 1; y < 4; y++)
if (board[(x * 3) + y] == NO_ONE)
{
board[(x * 3) + y] = PLAYER2;
return true;
}
}
return false;
}
// Search the columns for a near win
static bool moveColumn(int current_player)
{
for (int x = 1; x < 4; x++)
{
int sum = 0;
for (int y = 0; y < 3; y++)
sum += board[x+(y*3)];
// Almost a win -- block it
if (sum == (current_player * 2))
for (int y = 0; y < 3; y++)
if (board[x + (y * 3)] == NO_ONE)
{
board[x + (y * 3)] = PLAYER2;
return true;
}
}
return false;
}
// Search the diagonals for a near win
static bool moveDiagonal(int current_player)
{
static const int p1[3] = {1, 5, 9};
static const int p2[3] = {3, 5, 7};
int sum = 0;
int i;
for (i = 0; i < 3; i++)
sum += board[p1[i]];
if (sum == (current_player*2))
for (i = 0; i < 3; i++)
if (board[p1[i]] == NO_ONE)
{
board[p1[i]] = PLAYER2;
return true;
}
sum = 0;
for (i = 0; i < 3; i++)
sum += board[p2[i]];
if (sum == (current_player * 2))
for (i = 0; i < 3; i++)
if (board[p2[i]] == NO_ONE)
{
board[p2[i]] = PLAYER2;
return true;
}
return false;
}
// Computer AI
// 1. Search for possible wins for me
// 2. Search for possible wins for opponent
// 3. Perform most strategic move
static void autoMove()
{
// Can I win
if (moveRow(PLAYER2))
return;
if (moveColumn(PLAYER2))
return;
if (moveDiagonal(PLAYER2))
return;
// Can he/she win
if (moveRow(PLAYER1))
return;
if (moveColumn(PLAYER1))
return;
if (moveDiagonal(PLAYER1))
return;
// Most strategic move
if (board[5] == NO_ONE)
{
board[5] = PLAYER2;
return;
}
// Very Special cases
if ((board[5] == PLAYER2) && (board[9] == NO_ONE) &&
(board[8] == PLAYER1) && (board[3] == PLAYER1))
{
board[9] = PLAYER2;
return;
}
if ((board[5] == PLAYER2) && (board[9] == NO_ONE) &&
(board[7] == PLAYER1) && (board[6] == PLAYER1))
{
board[9] = PLAYER2;
return;
}
if ((board[5] == PLAYER2) && (board[7] == NO_ONE) &&
(board[8] == PLAYER1) && (board[1] == PLAYER1))
{
board[7] = PLAYER2;
return;
}
// Special cases
int *r = 0;
if ((board[5] == PLAYER2) &&
(((board[1] == PLAYER1) && (board[9] == PLAYER1)) ||
((board[3] == PLAYER1) && (board[7] == PLAYER1))))
{
static int rtmp[9] = {5, 2, 4, 6, 8, 1, 3, 7, 9};
r = rtmp;
}
else if ((board[5] == PLAYER2) &&
(board[2] == PLAYER1) && (board[4] == PLAYER1))
{
static int rtmp[9] = {5, 1, 4, 6, 8, 2, 3, 7, 9};
r = rtmp;
}
else if ((board[5] == PLAYER2) &&
(board[2] == PLAYER1) && (board[6] == PLAYER1))
{
static int rtmp[9] = {5, 3, 4, 6, 8, 1, 2, 7, 9};
r = rtmp;
}
else if ((board[5] == PLAYER2) &&
(board[8] == PLAYER1) && (board[4] == PLAYER1))
{
static int rtmp[9] = {5, 7, 4, 6, 8, 1, 3, 2, 9};
r = rtmp;
}
else if ((board[5] == PLAYER2) &&
(board[8] == PLAYER1) && (board[6] == PLAYER1))
{
static int rtmp[9] = {5, 9, 4, 6, 8, 1, 3, 7, 2};
r = rtmp;
}
else
{
static int tics = 0;
if (++tics % 10 == 0)
{
// In one out of 10 cases, give the user a chance.
static int rtmp[9] = {5, 2, 4, 6, 8, 1, 3, 7, 9};
r = rtmp;
}
else
{
static int rtmp[9] = {5, 1, 3, 7, 9, 2, 4, 6, 8};
r = rtmp;
}
}
for (int i = 0; i < 9; i++)
if (board[r[i]] == NO_ONE) {
board[r[i]] = PLAYER2;
return;
}
}
static int winner()
{
int i;
for (i = 1; i < 10; i++)
winning[i] = false;
// Check for diagonal win
int sum;
sum = board[3] + board[5] + board[7];
if (sum == 3 || sum == 12)
{
winning[3] = winning[5] = winning[7] = true;
return sum == 3 ? PLAYER1 : PLAYER2;
}
sum = board[1] + board[5] + board[9];
if (sum == 3 || sum == 12)
{
winning[1] = winning[5] = winning[9] = true;
return sum == 3 ? PLAYER1 : PLAYER2;
}
// Search the columns for a win
int x;
for (x = 1; x < 4; x++)
{
sum = 0;
for (int y = 0; y < 3; y++)
sum += board[x + (y * 3)];
if (sum == 3 || sum == 12)
{
for (int y = 0; y < 3; y++)
winning[x + (y * 3)] = true;
return sum == 3 ? PLAYER1 : PLAYER2;
}
}
// Search the rows for a near win
for (x = 0; x < 3; x++)
{
sum = 0;
for (int y = 1; y < 4; y++)
sum += board[(x * 3) + y];
if (sum == 3 || sum == 12)
{
for (int y = 1; y < 4; y++)
winning[(x * 3) + y] = true;
return sum == 3 ? PLAYER1 : PLAYER2;
}
}
// Check for all squares filled
for (i = 1; i < 10; i++)
if (board[i] == NO_ONE)
return NO_ONE;
return CATSEYE;
}
static void initBoard()
{
for (int i = 1; i < 10; i++)
board[i] = NO_ONE;
}
// Convert NAME into a color, using PIX as default
static Pixel color(Widget w, String name, Pixel pixel)
{
XrmValue from, to;
from.size = strlen(name);
from.addr = name;
to.size = sizeof(pixel);
to.addr = (String)&pixel;
XtConvertAndStore(w, XtRString, &from, XtRPixel, &to);
return pixel;
}
static void repaint()
{
int win = winner();
for (int i = 1; i <= 9; i++)
{
char *name = 0;
switch (board[i])
{
case NO_ONE:
name = "empty";
break;
case PLAYER1:
name = "circle";
break;
case PLAYER2:
name = "cross";
break;
}
assert(name != 0);
Pixel foreground;
Pixel background;
XtVaGetValues(buttons[i],
XmNforeground, &foreground,
XmNbackground, &background,
NULL);
if (win == NO_ONE || winning[i])
{
if (board[i] == PLAYER1)
foreground = color(buttons[i], "red4",
BlackPixelOfScreen(XtScreen(buttons[i])));
else
foreground = BlackPixelOfScreen(XtScreen(buttons[i]));
}
Pixmap p = XmGetPixmap(XtScreen(buttons[i]), name,
foreground, background);
XtVaSetValues(buttons[i],
XmNlabelType, XmPIXMAP,
XmNlabelPixmap, p,
XmNlabelInsensitivePixmap, p,
NULL);
XtSetSensitive(buttons[i], win == NO_ONE && board[i] == NO_ONE);
}
switch (win)
{
case PLAYER1:
set_status("You win.");
break;
case PLAYER2:
set_status(DDD_NAME " wins.");
break;
case CATSEYE:
set_status("Cat's eye.");
break;
}
}
static void MoveCB(XtPointer client_data, XtIntervalId *id)
{
(void) id; // Use it
XtIntervalId *timer = (XtIntervalId *)client_data;
assert(*timer == *id);
*timer = 0;
autoMove();
repaint();
}
static const int THINKING_TIME = 0; // `Thinking' time in ms
static void make_move(int move)
{
static XtIntervalId timer = 0;
// Is it a valid move?
if ((move < 1) || (move > 9) || (board[move] != NO_ONE))
return;
// Are we still thinking?
if (timer != 0)
return;
board[move] = PLAYER1;
repaint();
if (winner() == NO_ONE)
{
for (int i = 1; i < 10; i++)
XtSetSensitive(buttons[i], False);
// Make a move in THINKING_TIME ms
timer = XtAppAddTimeOut(XtWidgetToApplicationContext(buttons[move]),
THINKING_TIME, MoveCB, XtPointer(&timer));
}
}
// Install the given X bitmap as NAME
static void InstallImage(unsigned char *bits, int width, int height,
const string& name)
{
XImage *image = CreateImageFromBitmapData(bits, width, height);
Boolean ok = XmInstallImage(image, name);
if (!ok)
cerr << "Could not install " << quote(name) << " bitmap\n";
}
static void install_images()
{
static bool installed = false;
if (installed)
return;
InstallImage(cross_bits, cross_width, cross_height, "cross");
InstallImage(circle_bits, circle_width, circle_height, "circle");
InstallImage(empty_bits, empty_width, empty_height, "empty");
installed = true;
}
static void ResetTicTacToeCB(Widget, XtPointer, XtPointer)
{
static int tics = 0;
initBoard();
if (tics++ % 2 == 0)
autoMove();
repaint();
set_status("Welcome to Tic Tac Toe!");
}
static void MakeMoveCB(Widget, XtPointer client_data, XtPointer)
{
if (winner() != NO_ONE)
initBoard();
make_move((int)client_data);
}
static Widget create_tictactoe(Widget parent)
{
static Widget board = 0;
if (board != 0)
return board;
install_images();
Arg args[10];
int arg = 0;
XtSetArg(args[arg], XmNorientation, XmHORIZONTAL); arg++;
XtSetArg(args[arg], XmNpacking, XmPACK_COLUMN); arg++;
XtSetArg(args[arg], XmNnumColumns, 3); arg++;
board = XmCreateRowColumn(parent, "board", args, arg);
for (int i = 1; i <= 9; i++)
{
arg = 0;
buttons[i] = XmCreatePushButton(board, "field", args, arg);
XtManageChild(buttons[i]);
XtAddCallback(buttons[i], XmNactivateCallback,
MakeMoveCB, XtPointer(i));
}
XtManageChild(board);
return board;
}
void TicTacToeCB(Widget, XtPointer, XtPointer)
{
static Widget dialog = 0;
if (dialog == 0)
{
Arg args[10];
int arg = 0;
XtSetArg(args[arg], XmNautoUnmanage, False); arg++;
dialog = verify(XmCreatePromptDialog(find_shell(),
"tictactoe", args, arg));
Delay::register_shell(dialog);
if (lesstif_version <= 79)
XtUnmanageChild(XmSelectionBoxGetChild(dialog,
XmDIALOG_APPLY_BUTTON));
XtUnmanageChild(XmSelectionBoxGetChild(dialog,
XmDIALOG_HELP_BUTTON));
XtUnmanageChild(XmSelectionBoxGetChild(dialog,
XmDIALOG_CANCEL_BUTTON));
XtUnmanageChild(XmSelectionBoxGetChild(dialog,
XmDIALOG_TEXT));
XtUnmanageChild(XmSelectionBoxGetChild(dialog,
XmDIALOG_SELECTION_LABEL));
XtAddCallback(dialog, XmNhelpCallback, ImmediateHelpCB, NULL);
XtAddCallback(dialog, XmNokCallback, ResetTicTacToeCB, NULL);
XtAddCallback(dialog, XmNcancelCallback, UnmanageThisCB,
XtPointer(dialog));
create_tictactoe(dialog);
}
ResetTicTacToeCB(0, 0, 0);
manage_and_raise(dialog);
}