# Tic Tac Toe (boter, kaas en eieren in Dutch)

## Recommended Posts

Hi people!

I thought it'd be fun to try and use AutoIt and put up an excersize for myself to make a tic tac toe game with a computer player with a recursive exhaustive depth-first score calculating algorithm (nice and easy to code, though hard on CPU time) to determine it's moves.

The idea of the game (just in case): the user starts and chooses first place to put his/her symbol (the X in this case). The computer then puts an O at another place. That order is repeated until one of the players wins or the board is full. The object of the game is to make sure you get three-in-a-row, horizontally, vertically or diagonally. or at least make sure that the other player doesn't. For anyone with an IQ over that of a desert cactus, this game always ends in a draw. If I made the algorithm perfect, which I believe I did, it should not be possible to beat the computer. It is perfectly possible to lose from it though.

Note that I applied a hack to speed up the first move the computer needs to calculate (because it took like 15 seconds before the computer knew what to do): if user placed X in the middle then computer places first O in upper left corner. If the center square is free, the computer places it's first O there. (This is in fact always the resuilt of the algorithm anyway, so it's not influencing the AI, but a mere timesaver shortcut.)

This is very possibly FAR from perfectly efficient, because this is the first way that I thought of how to do this. Some googling shows that there are TONS of efficient algorithms to play a perfect tic-tac-toe game, but this was about quickly figuring it out for myself, not about following blindly and mindlessly in other people's footsteps.

```#include <guiconstants.au3>

Dim \$knop[3][3]
Dim \$grid[3][3]
\$eerstemove = True

\$mainGui = GUICreate("test", 105, 105)

For \$x = 0 To 2
For \$y = 0 To 2
\$knop[\$x][\$y] = GUICtrlCreateButton(" ", 10 + \$x * 30, 10 + \$y * 30, 25, 25)
\$grid[\$x][\$y] = 0
Next
Next

GUISetState()

While 1
_waitForUserMove()
_doeEindDing(\$grid)
_makeOwnMove(\$grid)
_doeEindDing(\$grid)
WEnd

Func _doeEindDing(\$grid)
If _checkForFinish(\$grid) = -1 Then
MsgBox(0, 0, "You win!")
Exit
ElseIf _checkForFinish(\$grid) = 1 Then
MsgBox(0, 0, "I win!")
Exit
EndIf
If _gridIsFull(\$grid) Then
MsgBox(0, 0, "Draw!")
Exit
EndIf
EndFunc  ;==>_doeEindDing

Func _gridIsFull(\$ag4)
For \$x=0 To 2
For \$y=0 To 2
If \$ag4[\$x][\$y]=0 Then Return False
Next
Next
Return True
EndFunc

Func _makeOwnMove(\$ag)
If \$eerstemove Then
\$eerstemove = False
If \$ag[1][1]=0 Then
\$x=1
Else
\$x=0
EndIf
\$grid[\$x][\$x] = 2
GUICtrlSetData(\$knop[\$x][\$x], "O")
Return
EndIf
Dim \$aScore[3][3]
\$maxScore = -100000
\$maxScoreX = -1
\$maxScoreY = -1
For \$x = 0 To 2
For \$y = 0 To 2
If \$ag[\$x][\$y] = 0 Then
\$aScore[\$x][\$y] = _calculateScore(\$x, \$y, \$ag, 0, 2)
If \$aScore[\$x][\$y] > \$maxScore Then
\$maxScore = \$aScore[\$x][\$y]
\$maxScoreX = \$x
\$maxScoreY = \$y
EndIf
EndIf
Next
Next
\$grid[\$maxScoreX][\$maxScoreY] = 2
GUICtrlSetData(\$knop[\$maxScoreX][\$maxScoreY], "O")
EndFunc  ;==>_makeOwnMove

Func _calculateScore(\$x, \$y, \$ag2, \$startScore, \$player)
\$ag2[\$x][\$y] = \$player
Local \$recPlayer = 0
If \$player = 1 Then
\$recPlayer = 2
Else
\$recPlayer = 1
EndIf
Local \$score = 0
\$score += _checkForFinish(\$ag2)
For \$x = 0 To 2
For \$y = 0 To 2
If \$ag2[\$x][\$y] = 0 Then
\$score += _calculateScore(\$x, \$y, \$ag2, 0, \$recPlayer)
EndIf
Next
Next
Return \$score
EndFunc  ;==>_calculateScore

Func _checkForFinish(\$ag3)
For \$p = 1 To 2
For \$i = 0 To 2
If (\$ag3[\$i][0] == \$p And \$ag3[\$i][1] == \$p And \$ag3[\$i][2] == \$p) Or (\$ag3[0][\$i] == \$p And \$ag3[1][\$i] == \$p And \$ag3[2][\$i] == \$p) Then
Return ((\$p - 2) * 3) + 1
EndIf
Next
If (\$ag3[0][0] == \$p And \$ag3[1][1] == \$p And \$ag3[2][2] == \$p) Or (\$ag3[2][0] == \$p And \$ag3[1][1] == \$p And \$ag3[0][2] == \$p) Then
Return ((\$p - 2) * 3) + 1
EndIf
Next
Return 0
EndFunc  ;==>_checkForFinish

Func _waitForUserMove()
Do
\$msg = GUIGetMsg()
Sleep(10)
Until _msgIsKnop(\$msg) <> 0
Dim \$knopInd[2]
\$knopInd = _msgIsKnop(\$msg)
GUICtrlSetData(\$knop[\$knopInd[0]][\$knopInd[1]], "X")
\$grid[\$knopInd[0]][\$knopInd[1]] = 1
EndFunc  ;==>_waitForUserMove

Func _msgIsKnop(\$msg)
For \$x = 0 To 2
For \$y = 0 To 2
If \$msg = \$knop[\$x][\$y] Then
If \$grid[\$x][\$y] <> "0" Then
Beep(1000, 5)
Return
EndIf
Dim \$knopInd[2]
\$knopInd[0] = \$x
\$knopInd[1] = \$y
Return \$knopInd
EndIf
Next
Next
If \$msg = \$GUI_EVENT_CLOSE Then Exit
Return 0
EndFunc  ;==>_msgIsKnop```

Roses are FF0000, violets are 0000FF... All my base are belong to you.

##### Share on other sites

I am afraid it does not know when it is beat. If you select a corner it selects the middle then you select the opposite corner and do the obvious to win.

Get Beta versions Here Get latest SciTE editor Here AutoIt 1-2-3 by Valuater - A great starting point.

Time you enjoyed wasting is not wasted time ......T.S. Elliot
Suspense is worse than disappointment................Robert Burns
God help the man who won't help himself, because no-one else will...........My Grandmother

##### Share on other sites

I am afraid it does not know when it is beat. If you select a corner it selects the middle then you select the opposite corner and do the obvious to win.

LOL! I found that out too after I posted it (i only tested like one or two games and was not even playing to win ). Better do the whole thing from scratch, this AI sucks balls

Thanks anyway for rubbing it in, hahaha...

Roses are FF0000, violets are 0000FF... All my base are belong to you.

## Create an account

Register a new account