SadBunny Posted February 6, 2009 Share Posted February 6, 2009 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. expandcollapse popup#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. Link to comment Share on other sites More sharing options...
BigDod Posted February 6, 2009 Share Posted February 6, 2009 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. 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 Link to comment Share on other sites More sharing options...
SadBunny Posted February 6, 2009 Author Share Posted February 6, 2009 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. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now