[Xotcl] Simple example: TicTacToe
Rick Hedin
rhedin@aquifer.geology.uiuc.edu
Mon, 12 Mar 2001 16:44:20 -0600
This is a multi-part message in MIME format.
------=_NextPart_000_0000_01C0AB13.AFA0C050
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
Hello all.
I was having some trouble understanding basic things about XOTcl. I found
an old TicTacToe program written in OTcl (by Gustaf?) and translated it so
it would run on Tk rather than Mofe. It's self-contained, involves several
cooperating objects, and has a simple domain. Maybe some other beginner
would find going through it useful.
I have attached the script to this mail message.
Regards,
Rick
------=_NextPart_000_0000_01C0AB13.AFA0C050
Content-Type: application/octet-stream;
name="tictactoe.xot"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="tictactoe.xot"
#!/usr/bin/X11/mofe --f=0A=
=0A=
set seed [pid]=0A=
proc random nvalues {=0A=
global seed=0A=
set seed [expr ($seed*12731+34197)%21473]=0A=
return [expr $seed%$nvalues]=0A=
}=0A=
=0A=
wm iconify . =0A=
=0A=
# It seems as though topLevel is a special motif keyword. I've replaced =
it, =0A=
# wherever it occurs, with .top . =0A=
toplevel .top=0A=
=0A=
=0A=
Class TicTacToe=0A=
=0A=
TicTacToe instproc init {parent} {=0A=
=0A=
if 0 { ;# I don't think fallback resources are necessary. =0A=
fallbackResources topLevel \=0A=
*XmPushButton*fontList -*-helvetica-medium-r-normal-*-14-*-*-* \=0A=
*msgArea.background turquoise \=0A=
*msgArea.foreground black \=0A=
*XmPushButton*background gray90 \=0A=
*commandArea.background turquoise \=0A=
*gameBoard.background turquoise=0A=
}=0A=
=0A=
Engine engine=0A=
# XmForm form $parent=0A=
frame $parent.form=0A=
# XmSeparator sep form ;# I don't think we need a separator. =0A=
# Message msgArea form=0A=
Message msgArea $parent.form=0A=
# Command commandArea form=0A=
Command commandArea $parent.form=0A=
# GameBoard gameBoard form=0A=
GameBoard gameBoard $parent.form=0A=
pack $parent.form=0A=
=0A=
# sV gameBoard \ ;# The 1st, 3rd and 4th sV just =0A=
# topAttachment ATTACH_FORM \ ;# position the elements. =0A=
# leftAttachment ATTACH_FORM \=0A=
# rightAttachment ATTACH_FORM \=0A=
# bottomWidget sep \=0A=
# bottomAttachment ATTACH_WIDGET=0A=
=0A=
# sV sep \ ;# This 2nd one is just not =
necessary. =0A=
# topAttachment ATTACH_NONE \=0A=
# leftAttachment ATTACH_FORM \=0A=
# rightAttachment ATTACH_FORM \=0A=
# bottomWidget msgArea \=0A=
# bottomAttachment ATTACH_WIDGET=0A=
=0A=
# sV msgArea \=0A=
# topAttachment ATTACH_NONE \=0A=
# leftAttachment ATTACH_FORM \=0A=
# rightAttachment ATTACH_FORM \=0A=
# bottomWidget commandArea \=0A=
# bottomAttachment ATTACH_WIDGET=0A=
=0A=
# sV commandArea \=0A=
# topAttachment ATTACH_NONE \=0A=
# leftAttachment ATTACH_FORM \=0A=
# rightAttachment ATTACH_FORM \=0A=
# bottomAttachment ATTACH_FORM=0A=
=0A=
pack $parent.form.gameBoard -side top -fill x -expand 1 =0A=
pack $parent.form.msgArea -side top -fill x -expand 1 =0A=
pack $parent.form.commandArea -side top -fill x -expand 1 =0A=
=0A=
}=0A=
=0A=
# It seems to me that sV combines the characteristics of pack (here) and =0A=
# of config (below). =0A=
# =0A=
# I guess packing can be regard as a variety of attribute. =0A=
=0A=
=0A=
#************************************************************************=
******=0A=
# GameBoard Class=0A=
#************************************************************************=
******=0A=
Class GameBoard=0A=
=0A=
GameBoard instproc init {passedParent} {=0A=
[self] instvar grid ;# Replaced all occurrences of $self with [self]. =0A=
[self] instvar parent=0A=
set parent $passedParent=0A=
set gridsize 100=0A=
=0A=
# XmRowColumn gameBoard $parent \=0A=
# numColumns 3 \=0A=
# packing PACK_COLUMN \=0A=
# adjustLast FALSE=0A=
# =0A=
# for {set i 0} {$i < 9} {incr i} {=0A=
# set grid($i) [XmDrawnButton xo gameBoard \=0A=
# userData $i \=0A=
# recomputeSize FALSE \=0A=
# width $gridsize \=0A=
# height $gridsize \=0A=
# labelType pixmap \=0A=
# activateCallback "engine recordMove %U" ]=0A=
# [self] activateSquare $i=0A=
# }=0A=
# I don't believe the userData is ever used. =0A=
# Hm. Maybe %U gives the user data. =0A=
=0A=
frame $parent.gameBoard=0A=
=0A=
for {set i 0} {$i < 3} {incr i} {=0A=
=0A=
set grid($i) [button $parent.gameBoard.b$i \=0A=
-image N -width $gridsize -height $gridsize \=0A=
-command "engine recordMove $i"]=0A=
set grid([expr $i + 3]) [button $parent.gameBoard.b[expr $i + 3] \=0A=
-image N -width $gridsize -height $gridsize \=0A=
-command "engine recordMove [expr $i + 3]"]=0A=
set grid([expr $i + 6]) [button $parent.gameBoard.b[expr $i + 6] \=0A=
-image N -width $gridsize -height $gridsize \=0A=
-command "engine recordMove [expr $i + 6]"]=0A=
[self] activateSquare $i=0A=
[self] activateSquare [expr $i + 3]=0A=
[self] activateSquare [expr $i + 6]=0A=
=0A=
grid $grid($i) $grid([expr $i + 3]) $grid([expr $i + 6])=0A=
=0A=
}=0A=
}=0A=
=0A=
# Okay. So this is what the grid array is. 9 buttons, to be arranged =0A=
# in a 3x3 grid. =0A=
# =0A=
# In this XmDrawnButton syntax, I wonder if xo is the name of the =
button, =0A=
# and gameBoard is the button's parent. Like XmRowColumn gameBoard =
$parent. =0A=
# Or XmSeparator sep form, or XmForm form $parent (<--topLevel). =0A=
# =0A=
# gameBoard is both instantiated as a class and as a widget. This =
appears =0A=
# to be their method of hooking together widgets and classes. =0A=
# GameBoard gameBoard form=0A=
# XmRowColumn gameBoard $parent=0A=
# I wonder if they are kept distinct by context, or OTcl has an =
automatic =0A=
# "Well, that didn't work; let's try interpreting it as a widget" =
feature. =0A=
# =0A=
# Have changed all occurrences of -bitmap to -image, because I couldn't =0A=
# figure out how to create a non-predefined bitmap. =0A=
=0A=
=0A=
GameBoard instproc markSquare {position value} {=0A=
[self] instvar grid=0A=
[self] deactivateSquare $position=0A=
# sV $grid($position) labelPixmap $value alignment alignment_center=0A=
$grid($position) config -image $value=0A=
# We plan to do the center alignment when the buttons are created and =
gridded.=0A=
}=0A=
=0A=
GameBoard instproc clear {} {=0A=
[self] instvar grid=0A=
foreach i [array names grid] {=0A=
[self] activateSquare $i=0A=
}=0A=
}=0A=
=0A=
GameBoard instproc activateSquare {position} {=0A=
[self] instvar grid =0A=
# sV $grid($position) \=0A=
# pushButtonEnabled TRUE \=0A=
# shadowType SHADOW_OUT \=0A=
# shadowThickness 2 \=0A=
# highlightColor white \=0A=
# labelPixmap Unspecified=0A=
$grid($position) config -state normal -relief raised -borderwidth 2 \=0A=
-highlightcolor white -image N =0A=
# I am unsure about highlightcolor, even though the name is the same. =0A=
}=0A=
=0A=
GameBoard instproc deactivateSquare {position} {=0A=
[self] instvar grid =0A=
# sV $grid($position) \=0A=
# pushButtonEnabled FALSE \=0A=
# shadowType SHADOW_IN \=0A=
# highlightColor gray90=0A=
$grid($position) config -state disabled -relief sunken -highlightcolor =
gray90=0A=
}=0A=
=0A=
GameBoard instproc highlightSquare {position} {=0A=
[self] instvar grid =0A=
# sV $grid($position) \=0A=
# shadowType SHADOW_ETCHED_OUT \=0A=
# shadowThickness 10=0A=
$grid($position) config -relief groove -borderwidth 10=0A=
}=0A=
=0A=
GameBoard instproc deemphasizeSquare {position} {=0A=
[self] instvar grid =0A=
# sV $grid($position) shadowThickness 0=0A=
$grid($position) config -borderwidth 0 =0A=
}=0A=
#************************************************************************=
******=0A=
# Message Class=0A=
#************************************************************************=
******=0A=
Class Message=0A=
=0A=
Message instproc init {passedParent} {=0A=
[self] instvar parent=0A=
set parent $passedParent=0A=
# XmLabel msgArea $parent \=0A=
# labelString " " recomputeSize 0=0A=
label $parent.msgArea -text " " =0A=
[self] postMessage ""=0A=
}=0A=
=0A=
Message instproc postMessage {message} {=0A=
[self] instvar parent=0A=
# sV msgArea labelString $message=0A=
$parent.msgArea config -text "$message"=0A=
# Apparently in motif, a widget has a unique name throughout the =
widget tree, =0A=
# and the widget knows who its parent is. =0A=
}=0A=
=0A=
Message instproc postAlert {{message {}}} {=0A=
if ![string match $message {}] {=0A=
[self] postMessage $message=0A=
}=0A=
bell=0A=
}=0A=
#************************************************************************=
******=0A=
# Command Class=0A=
#************************************************************************=
******=0A=
Class Command=0A=
=0A=
Command instproc init {parent} {=0A=
# XmForm commandArea $parent ;# I say it's a kind of frame. =0A=
frame $parent.commandArea=0A=
# XmPushButton newGame commandArea \=0A=
# topOffset 5 \=0A=
# bottomOffset 5 \=0A=
# leftOffset 5 \=0A=
# topAttachment ATTACH_FORM \=0A=
# leftAttachment ATTACH_FORM \=0A=
# rightAttachment ATTACH_NONE \=0A=
# bottomAttachment ATTACH_FORM \=0A=
# labelString "new" \=0A=
# activateCallback "[self] newGameCallback"=0A=
button $parent.commandArea.newGame -text new -command "[self] =
newGameCallback"=0A=
pack $parent.commandArea.newGame -side left=0A=
# XmPushButton quit commandArea \=0A=
# topOffset 5 \=0A=
# bottomOffset 5 \=0A=
# rightOffset 5 \=0A=
# topAttachment ATTACH_FORM \=0A=
# leftAttachment ATTACH_NONE \=0A=
# rightAttachment ATTACH_FORM \=0A=
# bottomAttachment ATTACH_FORM \=0A=
# activateCallback "[self] quitCallback"=0A=
button $parent.commandArea.quit -text quit -command "[self] =
quitCallback"=0A=
pack $parent.commandArea.quit -side right=0A=
}=0A=
=0A=
Command instproc newGameCallback {} {=0A=
engine reset=0A=
}=0A=
=0A=
Command instproc quitCallback {} {=0A=
# quit ;# Why did I have to change quit to exit? Did quit by some =0A=
;# mysterious alchemy refer to Engine::quit? =0A=
;# No. Engine::reset took an explicit reference. =0A=
;# I suppose quit could have been a mofe keyword. =0A=
exit=0A=
}=0A=
#************************************************************************=
******=0A=
# Engine Subsystem=0A=
#************************************************************************=
******=0A=
#************************************************************************=
******=0A=
# Board Class=0A=
#************************************************************************=
******=0A=
Class Board=0A=
=0A=
Board instproc init {} {=0A=
[self] instvar winningBits=0A=
set winningBits(0) 1..1..1..=0A=
set winningBits(1) .1..1..1.=0A=
set winningBits(2) ..1..1..1=0A=
set winningBits(3) 111......=0A=
set winningBits(4) ...111...=0A=
set winningBits(5) ......111=0A=
set winningBits(6) 1...1...1=0A=
set winningBits(7) ..1.1.1..=0A=
[self] clear=0A=
}=0A=
=0A=
Board instproc winningSquares {} {=0A=
[self] instvar winningPattern=0A=
return [split $winningPattern {}]=0A=
}=0A=
=0A=
Board instproc clear {} {=0A=
[self] instvar state=0A=
set state NNNNNNNNN=0A=
}=0A=
=0A=
Board instproc recordMove {position mark} {=0A=
[self] instvar state=0A=
if ![string match [string index $state $position] N] {=0A=
return ILLEGALMOVE=0A=
}=0A=
set last [expr $position - 1]=0A=
set state [string range $state 0 [expr $position - 1]]$mark[string =
range \=0A=
$state [expr $position + 1] end]=0A=
return VALIDMOVE=0A=
}=0A=
=0A=
Board instproc pattern {} {=0A=
[self] instvar state=0A=
return $state=0A=
}=0A=
=0A=
Board instproc isVacant {position} {=0A=
[self] instvar state=0A=
string match [string index $state $position] N=0A=
}=0A=
=0A=
Board instproc freeSquares {{list {0 1 2 3 4 5 6 7 8}}} {=0A=
[self] instvar state=0A=
foreach position $list {=0A=
if [string match [string index $state $position] N] {=0A=
lappend freelist $position=0A=
}=0A=
}=0A=
return $freelist=0A=
}=0A=
=0A=
Board instproc numFreeSquares {{list {0 1 2 3 4 5 6 7 8}}} {=0A=
[self] instvar state=0A=
set count 0=0A=
foreach position $list {=0A=
if [string match [string index $state $position] N] {=0A=
incr count=0A=
}=0A=
}=0A=
return $count=0A=
}=0A=
=0A=
Board instproc whoHasWon {} {=0A=
[self] instvar winningBits state winningPattern=0A=
for {set i 0} {$i < 8} {incr i} {=0A=
regsub -all {\.} $winningBits($i) 0 winningPattern=0A=
regsub -all 1 $winningBits($i) O player=0A=
if [regexp $player $state] {=0A=
return O=0A=
}=0A=
regsub -all 1 $winningBits($i) X player=0A=
if [regexp $player $state] {=0A=
return X=0A=
}=0A=
}=0A=
if [[self] numFreeSquares]>0 {=0A=
return N=0A=
}=0A=
return TIE=0A=
}=0A=
#************************************************************************=
******=0A=
# MoveGenerator Class=0A=
#************************************************************************=
******=0A=
Class MoveGenerator=0A=
=0A=
MoveGenerator instproc init {} {=0A=
[self] instvar strategy=0A=
# Dies sind die Strategie-Pattern, die unmittelbar im n=E4chsten Zug zu =
einem Sieg f=FChren=0A=
set strategy(1,pattern) 1..1.....=0A=
set strategy(1,move) 6=0A=
set strategy(2,pattern) 1.....1..=0A=
set strategy(2,move) 3=0A=
set strategy(3,pattern) ...1..1..=0A=
set strategy(3,move) 0=0A=
set strategy(4,pattern) .1..1....=0A=
set strategy(4,move) 7=0A=
set strategy(5,pattern) .1.....1.=0A=
set strategy(5,move) 4=0A=
set strategy(6,pattern) ....1..1.=0A=
set strategy(6,move) 1=0A=
set strategy(7,pattern) ..1..1...=0A=
set strategy(7,move) 8=0A=
set strategy(8,pattern) ..1.....1=0A=
set strategy(8,move) 5=0A=
set strategy(9,pattern) .....1..1=0A=
set strategy(9,move) 2=0A=
set strategy(10,pattern) 11.......=0A=
set strategy(10,move) 2=0A=
set strategy(11,pattern) 1.1......=0A=
set strategy(11,move) 1=0A=
set strategy(12,pattern) .11......=0A=
set strategy(12,move) 0=0A=
set strategy(13,pattern) ...11....=0A=
set strategy(13,move) 5=0A=
set strategy(14,pattern) ...1.1...=0A=
set strategy(14,move) 4=0A=
set strategy(15,pattern) ....11...=0A=
set strategy(15,move) 3=0A=
set strategy(16,pattern) ......11.=0A=
set strategy(16,move) 8=0A=
set strategy(17,pattern) ......1.1=0A=
set strategy(17,move) 7=0A=
set strategy(18,pattern) .......11=0A=
set strategy(18,move) 6=0A=
set strategy(19,pattern) 1...1....=0A=
set strategy(19,move) 8=0A=
set strategy(20,pattern) 1.......1=0A=
set strategy(20,move) 4=0A=
set strategy(21,pattern) ....1...1=0A=
set strategy(21,move) 0=0A=
set strategy(22,pattern) ..1.1....=0A=
set strategy(22,move) 6=0A=
set strategy(23,pattern) ..1...1..=0A=
set strategy(23,move) 4=0A=
set strategy(24,pattern) ....1.1..=0A=
set strategy(24,move) 2=0A=
}=0A=
=0A=
MoveGenerator instproc getNextMove {whoseMove} {=0A=
[self] instvar strategy=0A=
set pattern [board pattern]=0A=
set movesLeft [board numFreeSquares]=0A=
if {$movesLeft =3D=3D 0} {=0A=
return -1=0A=
}=0A=
# Hier wird zun=E4chst =FCberpr=FCft, ob der Computer mit dem n=E4chsten =
Zug gewinnen kann. Ist dies der Fall, macht er den entsprechenden Zug. =
Ansonsten wird =FCberpr=FCft, ob ein Sieg des Gegenspielers verhindert =
werden kann.=0A=
for {set i 1} {$i < 25} {incr i} {=0A=
regsub -all 1 $strategy($i,pattern) O player=0A=
if [regexp $player $pattern] {=0A=
if [board isVacant $strategy($i,move)] {=0A=
return $strategy($i,move)=0A=
}=0A=
}=0A=
regsub -all 1 $strategy($i,pattern) X player=0A=
if [regexp $player $pattern] {=0A=
if [board isVacant $strategy($i,move)] {=0A=
return $strategy($i,move)=0A=
}=0A=
}=0A=
}=0A=
# liegt kein in der Strtegie hinterlegtes Muster vor, wird als Zug die =
Mitte gew=E4hlt, falls sie frei ist=0A=
if [board isVacant 4] {=0A=
return 4=0A=
}=0A=
# Ist die Mitte nicht mehr frei, wird versucht eine der Ecken zu besetzen=0A=
set numFreeCorners [board numFreeSquares {0 2 6 8}]=0A=
if {$numFreeCorners > 0} {=0A=
set freeElements [board freeSquares {0 2 6 8}]=0A=
set randomIndex [random $numFreeCorners]=0A=
# ist auch dies erfolglos, sind die vier Kantenfelder an der Reihe=0A=
} else {=0A=
set numFreeEdges [board numFreeSquares {1 3 5 7}]=0A=
set freeElements [board freeSquares {1 3 5 7}]=0A=
set randomIndex [random $numFreeEdges]=0A=
}=0A=
return [lindex $freeElements $randomIndex]=0A=
}=0A=
#************************************************************************=
******=0A=
# Engine Class=0A=
#************************************************************************=
******=0A=
Class Engine=0A=
=0A=
Engine instproc init {} {=0A=
[self] instvar gameOver whoseMove messages=0A=
set messages(NEWGAMEMSG) "New Game. Choose an X square"=0A=
set messages(ILLEGALMOVEMSG) "Illegal Move, choose another X square"=0A=
set messages(USERSMOVEMSG) "Choose an X square"=0A=
set messages(WINSMSG-X) "X Wins!"=0A=
set messages(WINSMSG-O) "O Wins!"=0A=
set messages(TIEGAMEMSG) "Tie Game"=0A=
set messages(GAMEISOVERMSG) "Sorry, game is over"=0A=
set gameOver 0=0A=
set whoseMove X=0A=
Board board=0A=
MoveGenerator moveGenerator=0A=
}=0A=
=0A=
Engine instproc reset {} {=0A=
[self] instvar gameOver whoseMove messages=0A=
set whoseMove X=0A=
set gameOver 0=0A=
board clear=0A=
gameBoard clear=0A=
msgArea postMessage $messages(NEWGAMEMSG)=0A=
}=0A=
=0A=
Engine instproc recordMove {position} {=0A=
[self] instvar gameOver whoseMove messages =0A=
if $gameOver {=0A=
msgArea postAlert $messages(GAMEISOVERMSG)=0A=
return=0A=
}=0A=
if [string match [board recordMove $position $whoseMove] VALIDMOVE] {=0A=
gameBoard markSquare $position $whoseMove=0A=
} else {=0A=
msgArea postAlert $messages(ILLEGALMOVEMSG)=0A=
return=0A=
}=0A=
=0A=
[self] checkForWin=0A=
if $gameOver {=0A=
return=0A=
}=0A=
=0A=
if [string match $whoseMove O] {=0A=
set whoseMove X=0A=
msgArea postMessage $messages(USERSMOVEMSG)=0A=
} else {=0A=
set whoseMove O=0A=
[self] recordMove [moveGenerator getNextMove $whoseMove]=0A=
}=0A=
}=0A=
=0A=
Engine instproc checkForWin {} {=0A=
[self] instvar gameOver whoseMove messages=0A=
set winner [board whoHasWon]=0A=
if [string match $winner N] {=0A=
return=0A=
} =0A=
set gameOver 1=0A=
if [string match $winner TIE] {=0A=
set winningSquares {0 0 0 0 0 0 0 0 0}=0A=
msgArea postAlert $messages(TIEGAMEMSG)=0A=
} else {=0A=
set winningSquares [board winningSquares]=0A=
msgArea postAlert $messages(WINSMSG-$winner)=0A=
}=0A=
for {set i 0} {$i < 9} {incr i} {=0A=
gameBoard deactivateSquare $i=0A=
if [lindex $winningSquares $i] {=0A=
gameBoard highlightSquare $i=0A=
} else {=0A=
gameBoard deemphasizeSquare $i=0A=
}=0A=
}=0A=
}=0A=
=0A=
Engine instproc quit {} {=0A=
exit=0A=
}=0A=
=0A=
#************************************************************************=
******=0A=
# Main=0A=
#************************************************************************=
******=0A=
=0A=
# XmInstallImage .top {=0A=
# /* XPM */=0A=
# static char * o_xpm[] =3D {=0A=
# "32 32 3 1",=0A=
# " c None s None",=0A=
# ". c black",=0A=
# "X c white",=0A=
# " ",=0A=
# " ..... ",=0A=
# " ....XXXXX.... ",=0A=
# " .XXXXXXXXXXXXX. ",=0A=
# " ..XXXXXXXXXXXXXXX.. ",=0A=
# : : : =0A=
# " ..XXXXXXXXXXXXXXX.. ",=0A=
# " .XXXXXXXXXXXXX. ",=0A=
# " ....XXXXX.... ",=0A=
# " ..... "};=0A=
# } O=0A=
# =0A=
# XmInstallImage .top {=0A=
# /* XPM */=0A=
# static char * x_xpm[] =3D {=0A=
# "32 32 2 1",=0A=
# " c black",=0A=
# ". c None s None",=0A=
# " ............................ ",=0A=
# " .......................... ",=0A=
# ". ........................ .",=0A=
# ".. ...................... ..",=0A=
# "... .................... ...",=0A=
# : : : =0A=
# "... .................... ...",=0A=
# ".. ...................... ..",=0A=
# ". ........................ .",=0A=
# " .......................... ",=0A=
# " ............................ "};=0A=
# } X=0A=
# =0A=
# # Stolen from tk8.3.2\tests\imgBmap.test. =0A=
# image create bitmap i1 -data $data1=0A=
# i1 configure -data {=0A=
# #define foo2_height 14=0A=
# #define foo2_width 15=0A=
# static char foo2_bits[] =3D {=0A=
# 0xff, 0xff, 0xff, 0x81, 0xff, 0x81, 0xff, 0x81, 0xff, 0x81,=0A=
# 0xff, 0x81, 0xff, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0x81,=0A=
# 0xff, 0x81, 0xff, 0x81, 0xff, 0x81, 0xff, 0x81, 0xff, 0x81,=0A=
# 0xff, 0xff};=0A=
# }=0A=
=0A=
image create bitmap O -foreground green -data {=0A=
#define oooo_height 32=0A=
#define oooo_width 32=0A=
static char oooo_bits[] =3D {=0A=
0x00,0x00,0x00,0x00,=0A=
0x00,0x00,0x00,0x00,=0A=
0x00,0xc0,0x07,0x00,=0A=
0x00,0xfc,0x7f,0x00,=0A=
0x00,0xfe,0xff,0x00,=0A=
0x80,0xff,0xff,0x03,=0A=
0xc0,0xff,0xff,0x07,=0A=
0xe0,0xff,0xff,0x0f,=0A=
0xe0,0xff,0xff,0x0f,=0A=
0xf0,0xff,0xff,0x1f,=0A=
0xf8,0xff,0xff,0x3f,=0A=
0xf8,0xff,0xff,0x3f,=0A=
0xf8,0xff,0xff,0x3f,=0A=
0xf8,0xff,0xff,0x3f,=0A=
0xfc,0xff,0xff,0x7f,=0A=
0xfc,0xff,0xff,0x7f,=0A=
0xfc,0xff,0xff,0x7f,=0A=
0xfc,0xff,0xff,0x7f,=0A=
0xfc,0xff,0xff,0x7f,=0A=
0xf8,0xff,0xff,0x3f,=0A=
0xf8,0xff,0xff,0x3f,=0A=
0xf8,0xff,0xff,0x3f,=0A=
0xf8,0xff,0xff,0x3f,=0A=
0xf0,0xff,0xff,0x1f,=0A=
0xe0,0xff,0xff,0x0f,=0A=
0xe0,0xff,0xff,0x0f,=0A=
0xc0,0xff,0xff,0x07,=0A=
0x80,0xff,0xff,0x03,=0A=
0x00,0xfe,0xff,0x00,=0A=
0x00,0xfc,0x7f,0x00,=0A=
0x00,0xc0,0x07,0x00,=0A=
0x00,0x00,0x00,0x00};=0A=
}=0A=
# Image create bitmap name -data {...} returns the name as its return =
value. =0A=
=0A=
image create bitmap X -foreground green -data {=0A=
#define xxxx_height 32=0A=
#define xxxx_width 32=0A=
static char xxxx_bits[] =3D {=0A=
0xfc,0xff,0xff,0x3f,=0A=
0xf8,0xff,0xff,0x1f,=0A=
0xf1,0xff,0xff,0x8f,=0A=
0xe3,0xff,0xff,0xc7,=0A=
=0A=
0xc7,0xff,0xff,0xe3,=0A=
0x8f,0xff,0xff,0xf1,=0A=
0x1f,0xff,0xff,0xf8,=0A=
0x3f,0xfe,0x7f,0xfc,=0A=
=0A=
0x7f,0xfc,0x3f,0xfe,=0A=
0xff,0xf8,0x1f,0xff,=0A=
0xff,0xf1,0x8f,0xff,=0A=
0xff,0xe3,0xc7,0xff,=0A=
=0A=
0xff,0xc7,0xe3,0xff,=0A=
0xff,0x8f,0xf1,0xff,=0A=
0xff,0x1f,0xf8,0xff,=0A=
0xff,0x3f,0xfc,0xff,=0A=
=0A=
0xff,0x3f,0xfc,0xff,=0A=
0xff,0x1f,0xf8,0xff,=0A=
0xff,0x8f,0xf1,0xff,=0A=
0xff,0xc7,0xe3,0xff,=0A=
=0A=
0xff,0xe3,0xc7,0xff,=0A=
0xff,0xf1,0x8f,0xff,=0A=
0xff,0xf8,0x1f,0xff,=0A=
0x7f,0xfc,0x3f,0xfe,=0A=
=0A=
0x3f,0xfe,0x7f,0xfc,=0A=
0x1f,0xff,0xff,0xf8,=0A=
0x8f,0xff,0xff,0xf1,=0A=
0xc7,0xff,0xff,0xe3,=0A=
=0A=
0xe3,0xff,0xff,0xc7,=0A=
0xf1,0xff,0xff,0x8f,=0A=
0xf8,0xff,0xff,0x1f,=0A=
0xfc,0xff,0xff,0x3f};=0A=
}=0A=
# The upper-right to lower-left stripe is narrower than the upper-left =0A=
# to lower-right stripe. I have no idea why. =0A=
=0A=
# I've decided to have an explicit nothingness bitmap. When there is =
*no* =0A=
# bitmap, Tk interprets the height and width in terms of characters. =0A=
image create bitmap N -data {=0A=
#define nnnn_height 32=0A=
#define nnnn_width 32=0A=
static char nnnn_bits[] =3D {=0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00, =0A=
0x00, 0x00, 0x00, 0x00};=0A=
}=0A=
=0A=
TicTacToe game .top=0A=
# realize=0A=
=0A=
# XmXxxx things we'll have to replace: =0A=
# =0A=
# XmPushButton=0A=
# XmForm=0A=
# XmSeparator=0A=
# XmRowColumn=0A=
# XmDrawnButton=0A=
# XmLabel=0A=
# XmInstallImage=0A=
------=_NextPart_000_0000_01C0AB13.AFA0C050--