Tic Tac Toe in HolonJForth

Module TicTacToe

This game was written by Arthur van Hoff in Java and is included as a
demo program with the JDK 1.1. See jdk1.1/demo/tictactoe.
The program has been converted to HolonJForth by Wolf Wejgaard. 

Groups

 1. Class & Fields

 2. Init

 3. Moves

 4. Display

 5. Mouse

 6. TestAsApp



Class & Fields

class: TicTacToe  extends Applet  implements MouseListener 

\ White's current position, the computer is white. 
int white 

\ Black's current position, the user is black. 
int black 

\ Order of importance: 4 0 2 6 8 1 3 5 7. 
static int [] moves 

static boolean [] won 

\ Who goes first in the next game? 
boolean first 

511 final static int DONE 

0 final static int OK 

1 final static int WIN 

2 final static int LOSE 

3 final static int STALEMATE 


Init

i: tictactoe.<init>   ( -- )
     initsuper ()
     true =: first  ; 

\ Inserts the squares in order of importance. 
: initMoves  ( -- )
     9 new moves  
     4 =: 0 moves  0 =: 1 moves  2 =: 2 moves
     6 =: 3 moves  8 =: 4 moves  1 =: 5 moves  
     3 =: 6 moves  5 =: 7 moves  7 =: 8 moves  ; 

\ Mark all positions with these bits set as winning. 
: isWon   ( int pos -- )
     DONE 0 
     do   i pos & pos = 
          if  true =: i won  then  
     loop  ; 

\ Replaces " 1 i << ". Creates integer with binary bit i set = 2^i. 
: bitpos   ( int b -- int )
     1 b <<  ; 

: wins   ( int s1 int s2 int s3 -- )
     s1 bitpos s2 bitpos s3 bitpos or or isWon  ; 

\ Fill in the winning positions. 
: initWon  ( -- )
     512 new won                             \ 1 9 <<

     0 1 2 wins  3 4 5 wins  6 7 8 wins      \ horizontal
     0 3 6 wins  1 4 7 wins  2 5 8 wins      \ vertical
     0 4 8 wins  2 4 6 wins  ;               \ diagonal 

\ Called when the class is loaded. 
: tictactoe.<clinit>   ( -- )
     initMoves initWon  ; 


Moves

i: isFree   ( int m -- boolean )
     m bitpos white and 0 = m bitpos black and 0 = and  ; 

\ Returns true if move m makes white win. 
i: whiteWins   ( int m -- boolean )
     m bitpos white or won  ; 

\ Returns true if move m gives black a chance to win. 
i: blackWins   ( int m -- boolean )
     int pw  m bitpos white or =: pw
     9 0 do
          i bitpos pw and 0 = i bitpos black and 0 = and 
          if  i bitpos black or won if true return then  then
     loop
     false  ; 

\ Computes the best move for white. If there is no winning move, and if
\ all moves let black win, returns the first free move. 
i: bestMove   ( -- int )
     9 0 do i isFree i whiteWins and if i return then 
     loop  
     9 0 do i moves isFree i moves blackWins not and
            if i moves return then  
     loop  
     9 0 do i moves isFree if i moves return then 
     loop  
     DONE  ; 

\ Computer move, returns true if legal. 
i: doMyMove   ( -- boolean )
     black white or DONE = if false return then
     bestMove bitpos white or =: white  
     true  ; 

\ User move, returns true if legal. 
i: yourMove   ( int m -- boolean )
     m 0 <  m 8 > or if false return then
     black white or  m bitpos  and 0 <> if false return then
     m bitpos black or =: black  
     true  ; 

\ Figure what the status of the game is. 
i: status   ( -- int )
     white won if WIN return then
     black won if LOSE return then
     white black or DONE = if STALEMATE return then
     OK  ; 


Display

Image whiteImage 

Image blackImage 

int xoff 

int yoff 

i: drawLines   ( Graphics g Dimension d -- )
     xoff    0       xoff     d height  g  drawLine
     xoff 2* 0       xoff 2*  d height  g  drawLine
     0       yoff    d width  yoff      g  drawLine
     0       yoff 2* d width  yoff 2*   g  drawLine  ; 

i: paintImage   ( Image i int r int c Graphics g -- )
     i  r xoff * 10 +  c yoff * 10 +  this g drawImage drop  ; 

\ i is the index of the inner loop, j is the index of the outer loop. 
i: paintImages  ( Graphics g -- )
     int m  0 =: m
     3 0 do
          3 0 do
               m bitpos white and 
               if   whiteImage i j g PaintImage
               else m bitpos black and        
                    if  blackImage i j g PaintImage  then 
               then 1 += m    
          loop 
     loop  ; 

\ Overwrites Frame.paint(). Called whenever the frame is created, moved
\ or resized. 
i: paint   ( Graphics g --  )
     Dimension d  
     this getSize =: d    
     colorBlack g setColor
     d width 3 / =: xoff  
     d height 3 / =: yoff 
     g d drawLines  
     g paintImages ; 


Mouse

boolean isApplet 

i: sound   ( string file -- )
     isApplet
     if   getCodeBase file play  
     else file type space white . black . status . cr
     then  ; 

i: NewGame   ( -- )
     " audio/return.au" sound 
     0 =: white 0 =: black
     first if random 9 i>d d* d>i bitpos =: white then
     first not =: first 
     this repaint  ; 

\ Returns true if x,y is a correct move. 
i: isCorrectMove   ( int x int y -- boolean )
     Dimension d  this getSize =: d 
     x 3 * d width  /                   \ row
     y 3 * d height /                   \ column
     3 * + yourMove  ; 

i: myMove   ( -- )
     doMyMove 
     if   this repaint status case
          WIN of " audio/yahoo1.au" sound endof
          LOSE of " audio/yahoo2.au" sound endof
          STALEMATE of endof
          drop " audio/ding.au" sound endcase
     else " audio/beep.au" sound 
     then  ; 

i: evaluate   ( -- )
     status case
     WIN of " audio/yahoo1.au" sound endof
     LOSE of " audio/yahoo2.au" sound endof
     STALEMATE of endof
     drop myMove endcase ; 

\ The user has clicked in the applet. Status is OK until a game is
\ finished. 
i: mouseReleased   ( mouseEvent e -- )
     status OK = 
     if   e getX e getY isCorrectMove 
          if   this repaint  evaluate 
          else " audio/beep.au" sound
          then
     else NewGame 
     then  ; 

i: mousePressed   ( mouseEvent e -- )    ; 

i: mouseClicked   ( mouseEvent e -- )    ; 

i: mouseEntered   ( mouseEvent e -- )    ; 

i: mouseExited   ( mouseEvent e -- )    ; 

i: getAppletInfo   ( -- string )
     " TicTacToe by Arthur van Hoff"  ; 

\ Initialize the applet. Load images. 
i: TicTacToe.init   ( -- )
     getCodebase " images/not.gif" getImage =: whiteImage
     getCodebase " images/cross.gif" getImage =: blackImage
     this this addMouseListener
     true =: isApplet  ; 



TestAsApp

\ The applet can be turned into an application without modifications in
\ principle. However, sounds are not supported by applications and
\ generate an error message. We replace the sound by its filename.

i: tttApplication   ( -- )
     " images/not.gif" getImageFile =: whiteImage
     " images/cross.gif" getImageFile =: blackImage
     Frame app " Tic Tac Toe" new app ( string -- ) 
     this app addComponent drop
     this this addMouselistener
     200 200 app setSize
     app showWindow  ; 

\ TicTacToe as an application. No sounds. 
: ttt.main   ( String [] args -- )
     tictactoe t  new t () 
     t tttApplication  ; 

 




1998-2013 Wolf Wejgaard