Tic tac toe
From CodeCodex
[edit] Implementation
[edit] Java
© Part or all of this code is protected under copyright but is free to use and modify.
/*
* @(#)TicTacToe.java 1.2 95/10/13
*
* Copyright (c) 1994-1996 Sun Microsystems, Inc. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software
* and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and
* without fee is hereby granted.
* Please refer to the file http://java.sun.com/copy_trademarks.html
* for further important copyright and trademark information and to
* http://java.sun.com/licensing.html for further important licensing
* information for the Java (tm) Technology.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
* THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
*
* THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
* CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
* PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
* NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
* SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
* SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
* PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). SUN
* SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR
* HIGH RISK ACTIVITIES.
*/
import java.awt.Image;
import java.awt.Graphics;
import java.awt.Dimension;
import java.awt.Event;
import java.awt.Color;
import java.applet.Applet;
import java.util.Random;
/**
* A TicTacToe applet. A very simple, and mostly brain-dead
* implementation of your favorite game! <p>
*
* In this game a position is represented by a white and black
* bitmask. A bit is set if a position is ocupied. There are
* 9 squares so there are 1<<9 possible positions for each
* side. An array of 1<<9 booleans is created, it marks
* all the winning positions.
*
* @version 1.2, 13 Oct 1995
* @author Arthur van Hoff
* @modified 96/04/23 Jim Hagen : winning sounds
*/
public
class TicTacToe extends Applet {
private static final Random rand = new Random();
/**
* White's current position. The computer is white.
*/
int white;
/**
* Black's current position. The user is black.
*/
int black;
/**
* The squares in order of importance...
*/
final static int moves[] = {4, 0, 2, 6, 8, 1, 3, 5, 7};
/**
* The winning positions.
*/
static boolean won[] = new boolean[1 << 9];
static final int DONE = (1 << 9) - 1;
static final int OK = 0;
static final int WIN = 1;
static final int LOSE = 2;
static final int STALEMATE = 3;
/**
* Mark all positions with these bits set as winning.
*/
static void isWon(int pos) {
for (int i = 0 ; i < DONE ; i++) {
if ((i & pos) == pos) {
won[i] = true;
}
}
}
/**
* Initialize all winning positions.
*/
static {
isWon((1 << 0) | (1 << 1) | (1 << 2));
isWon((1 << 3) | (1 << 4) | (1 << 5));
isWon((1 << 6) | (1 << 7) | (1 << 8));
isWon((1 << 0) | (1 << 3) | (1 << 6));
isWon((1 << 1) | (1 << 4) | (1 << 7));
isWon((1 << 2) | (1 << 5) | (1 << 8));
isWon((1 << 0) | (1 << 4) | (1 << 8));
isWon((1 << 2) | (1 << 4) | (1 << 6));
}
/**
* Compute the best move for white.
* @return the square to take
*/
int bestMove(int white, int black) {
int bestmove = -1;
loop:
for (int i = 0 ; i < 9 ; i++) {
int mw = moves[i];
if ((white & (1 << mw)) == 0 && (black & (1 << mw)) == 0) {
int pw = white | (1 << mw);
if (won[pw]) {
// white wins, take it!
return mw;
}
for (int mb = 0 ; mb < 9 ; mb++) {
if ((pw & (1 << mb)) == 0 && (black & (1 << mb)) == 0) {
int pb = black | (1 << mb);
if (won[pb]) {
// black wins, take another
continue loop;
}
}
}
// Neither white nor black can win in one move, this will do.
if (bestmove == -1) {
bestmove = mw;
}
}
}
if (bestmove != -1) {
return bestmove;
}
// No move is totally satisfactory, try the first one that is open
for (int i = 0 ; i < 9 ; i++) {
int mw = moves[i];
if ((white & (1 << mw)) == 0 && (black & (1 << mw)) == 0) {
return mw;
}
}
// No more moves
return -1;
}
/**
* User move.
* @return true if legal
*/
boolean yourMove(int m) {
if (m < 0 || m > 8) {
return false;
}
if (((black | white) & (1 << m)) != 0) {
return false;
}
black |= 1 << m;
return true;
}
/**
* Computer move.
* @return true if legal
*/
boolean myMove() {
if ((black | white) == DONE) {
return false;
}
int best = bestMove(white, black);
white |= 1 << best;
return true;
}
/**
* Figure what the status of the game is.
*/
int status() {
if (won[white]) {
return WIN;
}
if (won[black]) {
return LOSE;
}
if ((black | white) == DONE) {
return STALEMATE;
}
return OK;
}
/**
* Who goes first in the next game?
*/
boolean first = true;
/**
* The image for white.
*/
Image notImage;
/**
* The image for black.
*/
Image crossImage;
/**
* Initialize the applet. Resize and load images.
*/
public void init() {
notImage = getImage(getCodeBase(), "images/not.gif");
crossImage = getImage(getCodeBase(), "images/cross.gif");
}
/**
* Paint it.
*/
public void paint(Graphics g) {
Dimension d = size();
g.setColor(Color.black);
int xoff = d.width / 3;
int yoff = d.height / 3;
g.drawLine(xoff, 0, xoff, d.height);
g.drawLine(2*xoff, 0, 2*xoff, d.height);
g.drawLine(0, yoff, d.width, yoff);
g.drawLine(0, 2*yoff, d.width, 2*yoff);
int i = 0;
for (int r = 0 ; r < 3 ; r++) {
for (int c = 0 ; c < 3 ; c++, i++) {
if ((white & (1 << i)) != 0) {
g.drawImage(notImage, c*xoff + 1, r*yoff + 1, this);
} else if ((black & (1 << i)) != 0) {
g.drawImage(crossImage, c*xoff + 1, r*yoff + 1, this);
}
}
}
}
/**
* The user has clicked in the applet. Figure out where
* and see if a legal move is possible. If it is a legal
* move, respond with a legal move (if possible).
*/
public boolean mouseUp(Event evt, int x, int y) {
switch (status()) {
case WIN:
case LOSE:
case STALEMATE:
play(getCodeBase(), "audio/return.au");
white = black = 0;
if (first) {
white |= 1 << rand.nextInt(9);
}
first = !first;
repaint();
return true;
}
// Figure out the row/colum
Dimension d = size();
int c = (x * 3) / d.width;
int r = (y * 3) / d.height;
if (yourMove(c + r * 3)) {
repaint();
switch (status()) {
case WIN:
play(getCodeBase(), "audio/yahoo1.au");
break;
case LOSE:
play(getCodeBase(), "audio/yahoo2.au");
break;
case STALEMATE:
break;
default:
if (myMove()) {
repaint();
switch (status()) {
case WIN:
play(getCodeBase(), "audio/yahoo1.au");
break;
case LOSE:
play(getCodeBase(), "audio/yahoo2.au");
break;
case STALEMATE:
break;
default:
play(getCodeBase(), "audio/ding.au");
}
} else {
play(getCodeBase(), "audio/beep.au");
}
}
} else {
play(getCodeBase(), "audio/beep.au");
}
return true;
}
public String getAppletInfo() {
return "TicTacToe by Arthur van Hoff";
}
}
Source: http://rintintin.colorado.edu/~epperson/Java/TicTacToe.java
[edit] OCaml
From the OCaml distribution:
module Array = StdLabels.Array
module Tictactoe = struct
type t = [`base|`widget|`container|`box|`tictactoe]
module Signals = struct
module S = GtkSignal
let tictactoe : ([>`tictactoe],_) S.t =
{ S.classe = `tictactoe; S.name = "tictactoe";
S.marshaller = S.marshal_unit }
let emit_tictactoe = S.emit_unit ~sgn:tictactoe
end
let create : unit -> t Gtk.obj =
let _,tictactoe_new = GtkNew.make_new_widget
~name:"Tictactoe" ~parent:GtkNew.VBOX ~signals:[Signals.tictactoe]
in fun () -> GtkBase.Object.try_cast (tictactoe_new ()) "Tictactoe"
end
class tictactoe_signals obj = object
inherit GContainer.container_signals obj
method tictactoe =
GtkSignal.connect ~sgn:Tictactoe.Signals.tictactoe obj ~after
end
exception Trouve
class tictactoe ?packing ?show () =
let obj : Tictactoe.t Gtk.obj = Tictactoe.create () in
let box = new GPack.box_skel obj in
object (self)
inherit GObj.widget obj
val mutable buttons = [||]
val mutable buttons_handlers = [||]
val label = GMisc.label ~text:"Go on!" ~packing:box#add ()
method clear () =
for i = 0 to 2 do
for j = 0 to 2 do
let button = buttons.(i).(j)
and handler = buttons_handlers.(i).(j) in
button#misc#handler_block handler;
button#set_active false;
button#misc#handler_unblock handler
done
done
method connect = new tictactoe_signals obj
method emit_tictactoe () =
GtkSignal.emit_unit obj ~sgn:Tictactoe.Signals.tictactoe
method toggle () =
let rwins = [| [| 0; 0; 0 |]; [| 1; 1; 1 |]; [| 2; 2; 2 |];
[| 0; 1; 2 |]; [| 0; 1; 2 |]; [| 0; 1; 2 |];
[| 0; 1; 2 |]; [| 0; 1; 2 |] |]
and cwins = [| [| 0; 1; 2 |]; [| 0; 1; 2 |]; [| 0; 1; 2 |];
[| 0; 0; 0 |]; [| 1; 1; 1 |]; [| 2; 2; 2 |];
[| 0; 1; 2 |]; [| 2; 1; 0 |] |] in
label#set_text"Go on!";
try
for k = 0 to 7 do
let rec aux i =
(i = 3) ||
(buttons.(rwins.(k).(i)).(cwins.(k).(i))#active) && (aux (i+1)) in
if aux 0 then raise Trouve
done
with Trouve -> label#set_text "Win!!"; self#emit_tictactoe ()
initializer
let table =
GPack.table ~rows:3 ~columns:3 ~homogeneous:true ~packing:box#add () in
buttons <-
Array.init 3 ~f:
(fun i -> Array.init 3 ~f:
(fun j ->
GButton.toggle_button ~width:20 ~height:20
~packing:(table#attach ~left:i ~top:j ~expand:`BOTH) ()));
buttons_handlers <-
Array.mapi buttons ~f:
(fun i -> Array.mapi ~f:
(fun j button -> button #connect#toggled ~callback:self#toggle));
GObj.pack_return self ~packing ~show;
()
end
let win (ttt : tictactoe) _ =
Printf.printf "Gagne!!\n" ;
flush stdout;
ttt #clear ()
let essai () =
let window = GWindow.window ~title:"Tictactoe" ~border_width:10 () in
window #connect#destroy ~callback:GMain.Main.quit;
let ttt = new tictactoe ~packing:window#add () in
ttt #connect#tictactoe ~callback:(win ttt);
window #show ();
GMain.Main.main ()
let _ = essai ()

