Our user interface (above) lets the player start a new game, choosing whether he would like to go first or second as either X or O, and lists the moves (spaces marked). The larger “big” board is where the current game is played and the player marks his desired space. The smaller board dis-plays the computer thinking as calculated by the Min-Max with Alpha-Beta pruning search algorithm.
FORM1
Private Sub Form_Load() Dim i As Integer Form1.BorderStyle = 0
Text1.Text = " " + "Moves" + " "
Frame1.Visible = False
InitVariables playerMark = -1 End Sub
Private Sub Option1_Click(index As Integer)
Picture1.Enabled = True
Picture1.PaintPicture BigBoard, 0, 0 Picture2.PaintPicture SmBoard, 0, 0
InitVariables showBigBoard showSmallBoard
playerMark = (2 * (index Mod 2)) - 1 '-1 is "O", 1 is "X"
playerDONE = 1 ' Computer goes first
Option1(index).value = False ' reset Selected value Frame1.Visible = False
Option2.Enabled = True Option2.value = False
Option2.Visible = False
If index < 2 Then ' Player’s turn Text5.Text = "Your turn, please mark a space"
Picture1.Enabled = True ' Player goes first playerDONE = 0
If playerDONE = 1 Then Exit Sub flag = -1
'check the area the player has selected to mark For i = 0 To 8
If PmouseX >= (15 * BigBoxXY(i, 0)) And PmouseX <= (15 * (BigBoxXY(i, 0) + 120))
Then
If PmouseY >= (15 * BigBoxXY(i, 1)) And PmouseY <= (15 * (BigBoxXY(i, 1) + 95))
Then
If ttt(0, i) = 0 Then ttt(0, i) = playerMark
Text1.Text = Text1.Text + "You marked space " + Str(i + 1) + " "
Text4.Text = "Marked " + Str(i + 1)
showSmallBoard ' display current path scenario of board playerDONE = 1
Private Sub Picture1_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
PmouseX = X
Private Sub Picture2_Paint() showSmallBoard
End Sub
Public Sub showBigBoard() Dim i As Integer
For i = 0 To 8
If ttt(0, i) = 1 Then
Picture1.PaintPicture markX, 15 * BigBoxXY(i, 0), 15 * BigBoxXY(i, 1)
End If
If ttt(0, i) = -1 Then
Picture1.PaintPicture markO, 15 * BigBoxXY(i, 0), 15 * BigBoxXY(i, 1)
End If Next i
Clevel = 0 showSmallBoard End Sub
Public Sub showSmallBoard() Dim i As Integer
For i = 0 To 8
If ttt(Clevel, i) = 1 Then
Picture2.PaintPicture smarkX, 15 * SmBoxXY(i, 0), 15 * SmBoxXY(i, 1) End If
If ttt(Clevel, i) = -1 Then
Picture2.PaintPicture smarkO, 15 * SmBoxXY(i, 0), 15 * SmBoxXY(i, 1) End If
Next i End Sub
MODULE1
'since C++ start arrays at index Zero we will too 'Set the Global variables
Public ttt(0 To 9, 0 To 8) As Integer
Public wp(0 To 7, 0 To 2) As Integer Public BigBoxXY(0 To 8, 0 To 2) As Integer Public SmBoxXY(0 To 8, 0 To 2) As Integer Public playerMark As Integer Public Level1Data(0 To 9) As Integer Sub InitVariables()
Dim i As Integer Dim j As Integer
' Change the path according to your Directory
Path = "C://Wordware//VBTicTacToe//"
Set BigBoard = LoadPicture(Path + "TicTacToeBigBoard.bmp") Set SmBoard = LoadPicture(Path + "TicTacToeSmBoard.bmp") Set markX = LoadPicture(Path + "BigX.bmp")
Set markO = LoadPicture(Path + "BigO.bmp") Set smarkX = LoadPicture(Path + "SmallX.bmp") Set smarkO = LoadPicture(Path + "SmallO.bmp") Clevel = 0
Form1.Picture1.Enabled = False
'Initialize the Tic-Tac-Toe boards (all levels) to Zeor For i = 0 To 9
For j = 0 To 8 ttt(i, j) = 0 Next j
Next i
'We start the arrays at Zero to match our C-code
' Rows
' Define our two Tic-Tac-Toe boards
BigBoxXY(0, 0) = 0: BigBoxXY(0, 1) = 0 BigBoxXY(1, 0) = 125: BigBoxXY(1, 1) = 0 BigBoxXY(2, 0) = 243: BigBoxXY(2, 1) = 0 BigBoxXY(3, 0) = 0: BigBoxXY(3, 1) = 101 BigBoxXY(4, 0) = 125: BigBoxXY(4, 1) = 101 BigBoxXY(5, 0) = 243: BigBoxXY(5, 1) = 101 BigBoxXY(6, 0) = 0: BigBoxXY(6, 1) = 196 BigBoxXY(7, 0) = 125: BigBoxXY(7, 1) = 196 BigBoxXY(8, 0) = 243: BigBoxXY(8, 1) = 196
SmBoxXY(0, 0) = 0: SmBoxXY(0, 1) = 0 SmBoxXY(1, 0) = 22: SmBoxXY(1, 1) = 0 SmBoxXY(2, 0) = 44: SmBoxXY(2, 1) = 0 SmBoxXY(3, 0) = 0: SmBoxXY(3, 1) = 22 SmBoxXY(4, 0) = 22: SmBoxXY(4, 1) = 22 SmBoxXY(5, 0) = 44: SmBoxXY(5, 1) = 22 SmBoxXY(6, 0) = 0: SmBoxXY(6, 1) = 44 SmBoxXY(7, 0) = 22: SmBoxXY(7, 1) = 44 SmBoxXY(8, 0) = 44: SmBoxXY(8, 1) = 44
Randomize (Timer) ' initialize the Random number function End Sub
'Copy a new Tic-Tac-Toe board starting with the previous board Sub Copy_ttt(level As Integer)
Dim index As Integer
If level < 1 Then Exit Sub If level > 8 Then Exit Sub
Clevel = level ' for small tic-tac-toe board
For index = 0 To 8
ttt(level, index) = ttt(level - 1, index) Next index
Form1.showSmallBoard End Sub
' Let's verify if there's an empty space to fill Function SpaceEmpty(level As Integer) As Integer Dim index As Integer
For index = 0 To 8
If ttt(level, index) = 0 Then SpaceEmpty = index + 1 Exit Function
End If Next index
SpaceEmpty = 0 'no empty space was found End Function
' A function to check if the current board position is a winning ' one for either player
Function IsThereaWin(level As Integer, MySide As Integer) As Integer
Dim ttWin As Integer ttWin = ttWin + ttt(level, wp(wpindex, i))
Next i
If ttWin = MyWin Then ' I have 3 connecting marks IsThereaWin = 100 'I win plus space to move to Exit Function
End If
If ttWin = OppWin Then ' Opponent can get 3 connecting marks IsThereaWin = -100 'Forced plus space to block
Exit Function End If
Next wpindex
IsThereaWin = 0 End Function
' Let's check to see if there's a forced move to make
' A forced move is a winning space or a blocking space to stop a loss Function Forced_Move(level As Integer, MySide As Integer) As Integer
Dim index As Integer
If level > 0 Then Copy_ttt (level)
If ttt(level, index) = 0 Then ' empty space
Chapter 11
If trys = 0 Then ' Can we win on this turn ttt(level, index) = MySide
Else ' Can our opponent win if we don't block on this turn ttt(level, index) = -MySide 'opponent
End If
FMove = IsThereaWin(level, MySide) If FMove 0 Then
sgn1 = 1
If FMove < 0 Then sgn1 = -1
Forced_Move = sgn1 * (Abs(FMove) + index + 1) If level > 0 Then Copy_ttt (level)
Exit Function End If
End If Next index Next trys
If level > 0 Then Copy_ttt (level) Forced_Move = 0 'No forced move End Function
Sub Tic_Tac_Toe()
Dim X As Integer Dim MySide As Integer Dim spaceon As Integer Dim FMove As Integer Dim i As Integer Dim value As Integer
X = 0: MySide = -playerMark
If SpaceEmpty(0) Then 'Game still on
' A forced move to win or to block a win is the best mark move X = Forced_Move(1, MySide)
spaceon = Abs(X) Mod 100
If X 0 Then ' A forced move has been calculated ttt(0, spaceon - 1) = MySide ' either a '1' or a '-1' Form1.Text1.Text = Form1.Text1.Text + " I marked space " +
Str(spaceon) + " "
End If
'find a space that's not forced If X = 0 Then
' Initialize the level 1 available mark spaces to an extremely low value
For i = 0 To 9 Level1Data(i) = -999 Next i
' Call the Min-Max Function where Alpha is very low and Beta is very high
X = MinMaxValue(1, MySide, -999, 999) ' find the best move
' find the best space to mark from the level 1 list of valid spaces to mark
spaceon = SpaceEmpty(0) - 1 X = -999
For i = 1 To 9
if Level1Data(i) > X Then spaceon = i
X= Level1Data(i) End If
Next i
ttt(0, spaceon - 1) = MySide ' Mark the best space
Form1.Text1.Text = Form1.Text1.Text + " I marked space " + Str(spaceon) + " "
End If
Form1.Text4.Text = "Marked " + Str(spaceon)
Form1.showSmallBoard ' display current path scenario of board End If
Form1.showBigBoard playerDONE = 0
FMove = IsThereaWin(0, playerMark)
If FMove <= -100 Then ' Be prepared to see this message often Form1.Text1.Text = Form1.Text1.Text + " " + "HURRAY! I WON!"
+ " "
Form1.Text1.Text = Form1.Text1.Text + " Play me again?"
Form1.Text5.Text = "Would you like to play me again?"
playerDONE = 100
Form1.Option2.Visible = True Exit Sub
End If
Chapter 11
If FMove >= 100 Then ' You may never see this message
Form1.Text1.Text = Form1.Text1.Text + " " + "WOW! YOU'VE WON!"
+ " "
Form1.Text1.Text = Form1.Text1.Text + " Play me again?"
Form1.Text5.Text = "Would you like to play me again?"
playerDONE = 100
Form1.Option2.Visible = True Exit Sub
End If
If FMove = 0 Then ' No win found and all spaces marked
playerDONE = 0
Form1.Text5.Text = "Your turn, please mark a space"
If SpaceEmpty(0) = 0 Then ' no more empty spaces to mark Form1.Text1.Text = Form1.Text1.Text + " " + "DRAW!" + " "
Form1.Text1.Text = Form1.Text1.Text + " Play me again?"
Form1.Text5.Text = "Would you like to play me again?"
Form1.Option2.Visible = True Exit Sub
End If End If End Sub
' Just like a chess opening database, here are standard ' Tic-Tac-Toe opening marks
Sub opening()
Dim i As Integer Dim j As Integer Dim k As Integer
Form1.Text5.Text = "" ' clear message
' Check to see if we go first and second j = 0
Tic_Tac_Toe ' find a space to mark Exit Sub
Form1.Text4.Text = "Marked " + Str(i + 1)
Form1.Text1.Text = Form1.Text1.Text + " I marked space " +
Str(i + 1) + " "
playerDONE = 0 Form1.showBigBoard
Form1.Text5.Text = "Your turn, please mark a space"
Form1.Picture1.Enabled = True ' Player goes Exit Sub
End If
If j = 1 Then ' we go second
' valid moves are center and the opposite corner if the opponent ' marked a corner space
i = -1 ' a flag
If k = 4 And i = -1 Then ' center space marked
AAA: i = Int(Rnd * 4) ' valid first marks are spaces 1,3,7 and 9 If i = 4 Then GoTo AAA ' can't mark the center space
i = i * 2 ' we have a random number 0 through 4 so we double it End If
If i = -1 Then ' center space was not marked
i = 4 ' mark center space (space 5)
End If
ttt(0, i) = -playerMark
Form1.Text4.Text = "Marked " + Str(i + 1)
Form1.Text1.Text = Form1.Text1.Text + " I marked space " + ' Str(i + 1) + " "
playerDONE = 0 Form1.showBigBoard
Form1.Text5.Text = "Your turn, please mark a space"
Form1.Picture1.Enabled = True ' Player goes Exit Sub
End If End Sub
Function MinMaxValue(level As Integer, MySide As Integer, alpha As Integer, beta As Integer) As Integer
Dim WIN As Integer Dim index As Integer Dim MTlist As Long Dim nextspace As Integer
Dim X As Integer
Chapter 11
Dim succval As Integer ' reset current level board
Copy_ttt (level)
If SpaceEmpty(level) = 0 Then MinMaxValue = 0
Exit Function End If
'find a space that's not forced 'list all open spaces
MTlist = 0 ' List all the open (unmarked) spaces on this level
X = Forced_Move(level, MySide) ' Is there a forced move (a win or a ' block of a win)
If X 0 Then ' a forced move has been flagged MTlist = Abs(X Mod 100) ' space is 1 to 9
Else
For index = 0 To 8
If ttt(level, 8 - index) = 0 Then ' subtract from 8 for ascending order
MTlist = MTlist * 10 + (9 - index) End If
Next index End If
While MTlist > 0
nextspace = MTlist Mod 10 ' next space to mark
MTlist = (MTlist - nextspace) / 10 ' remainder of possible spaces ' to mark
Copy_ttt (level)
ttt(level, nextspace - 1) = MySide
Form1.Text4.Text = "Marked " + Str(nextspace)
Form1.showSmallBoard ' display current path scenario of board WIN = IsThereaWin(level, MySide)
If WIN >= 100 Then succval = WIN Else
succval = -MinMaxValue(level + 1, -MySide, -beta, -alpha) Endif
If level = 1 Then ' Save this space's value Level1Data(nextspace) = succval
If succval = 100 Then ' Winning line found MinMaxValue = succval
Exit Function End If
End If
'The Alpha-Beta pruning code
If succval >= beta Then MinMaxValue = beta Exit Function End If
If succval > alpha Then alpha = succval Wend
MinMaxValue = alpha ' return a draw End Function
//since C++ start arrays at index Zero we will too int ttt[8][8]={ {0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0}};
int wp[8][3]={{0,1,2},{3,4,5},{6,7,8}, // Rows {0,3,6},{1,4,7},{2,5,8}, // Columns {0,4,8},{2,4,6}}; // Diagonals
// Copy a new Tic-Tac-Toe board starting with the previous board void Copy_ttt(int level)
{
int index;
if(level<1) return; // invalid parameter for(index=0; index<9; index++)
ttt[level][index]= ttt[level-1][index]
}
// Let's verify if there's an empty space to fill int SpaceEmpty(int level)
{
int index;
for(index=0; index<9; index++)
if(ttt[level][index]==0)return(index+1);
return 0; // no empty space was found }
// Let's check to see if there's a forced move to make
Chapter 11
// A forced move is a winning space or a blocking space to stop // a loss
int Forced_Move(int level, int MySide) {
int index, trys, ttWin;
int OppWin= -3 * MySide;
int MyWin= 3 * MySide;
for(index=0; index<9;index++) for(trys=0; trys<2; trys++){
if(level>0) Copy_ttt(level);
if(ttt[level][index] == 0){ // empty space if(trys ==0)ttt[level][index]= MySide;
else ttt[level][index]=-MySide; // opponent
ttWin= ttt[level][wp[index][0] + ttt[level][wp[index][1] + ttt[level][wp[index][2];
if(ttWin == MyWin)return(100 + index); // I win plus space to move to else
if(ttWin == OppWin)return(-(100 + index)); // Forced plus space to block }
return 0; // No forced move }
void Tic_Tac_Toe() {
int x=0, MySide= 1, spaceon;
while(SpaceEmpty(0) && x < 100){ // Game still on x= Forced_Move(1, MySide);
spaceon= abs(x)%100;
if(x != 0)ttt[0][spaceon]= x/100; // either a '1' or a '-1' else{ // find a space that's not forced
BestMove(1); // find the best move }
x= 0; // reset 'x' }
}
(This code can be found on the book’s companion CD.)