Sign in to follow this  
Followers 0

Tik-Tak-Toe

44 posts in this topic

Posted (edited)

VERY simple.. lol i took the lazy way out.. see Unbeatable tick tack toe for a better one...

X=AI

O=USER

USER goes first

this has SOMEwhat of a strategy in it... and is MUCH harder to win has custom GUI's and messages... blah blah check it out.. post some comments on how i could do it better please... and i DON'T want to make it UNBEATABLE.. cause that wouldn't be fun.. maybe nearly unbeatable.. maybe later..

EDIT

its more difficult now but still has a few bugs X's replace O's spot in center some times and declares a AI WIN when it should have been a TIE

EDIT

fairly random scenarios based on a valued system.

3|2|3

2|4|2

3|2|3

if there isn't a spot to block\win it goes to find the most valuable, if there are multiple it randomizes it. not exactly predictable. or is it? :S

Opt ('GuiOnEVentMode',1)
Dim $GRID[3][3]
Dim $row[3], $column[3],$diagonal[2]
$nTieCount = 0
$nTurnCount = 0
$nLossCount = 0
$nWinCount = 0
$nAI = -1
$sAI = 'o'
$nPLAYER = 1
$sPLAYER = 'x'
$turn = $nPLAYER
$w_h = 75
$guiw = ($w_h*3)+40
$guih = ($w_h*5)
$font_s = ($w_h*2)/4
$window_hwnd = GUICreate ('tic tac toe',$guiw,$guih)
GUISetOnEvent (-3,'End')
$lWinCount = GUICtrlCreateLabel ('WINS:',10,40+($w_h*3),($guiw-20)/3,$w_h/2,0x0200)
$lLossCount = GUICtrlCreateLabel ('LOSSES:',10+($guiw-20)/3,40+($w_h*3),($guiw-20)/3,$w_h/2,0x0200)
$lTieCount = GUICtrlCreateLabel ('Ties:',$guiw-($guiw-20)/3,40+($w_h*3),($guiw-20)/3,$w_h/2,0x0200)
For $x = 0 To 2
	For $y = 0 To 2
		$GRID[$x][$y] = GUICtrlCreateButton ('',10+(10*$x)+($x*$w_h),10+(10*$y)+($y*$w_h),$w_h,$w_h)
			GUICtrlSetOnEvent ($GRID[$x][$y],'Clicked')
	Next
Next
Dim $GRIDval2[4]
	$GRIDval2[0] = $GRID[0][1]
	$GRIDval2[1] = $GRID[2][0]
	$GRIDval2[2] = $GRID[2][2]
	$GRIDval2[3] = $GRID[2][1]
Dim $GRIDval3[4]
	$GRIDval3[0] = $GRID[0][0]
	$GRIDval3[1] = $GRID[0][2]
	$GRIDval3[2] = $GRID[2][0]
	$GRIDval3[3] = $GRID[2][2]
$diagonal[0] = $GRID[0][0] & '|' & $GRID[1][1] & '|' & $GRID[2][2]
$diagonal[1] = $GRID[2][0] & '|' & $GRID[1][1] & '|' & $GRID[0][2]
For $n = 0 To 2
	$row[$n] = $GRID[$n][0] & '|' & $GRID[$n][1] & '|' & $GRID[$n][2]
	$column[$n] = $GRID[0][$n] & '|' & $GRID[1][$n] & '|' & $GRID[2][$n]
Next
GUICtrlCreateButton ('Reset',10,(3*$w_h)+$w_h+20,$guiw-20,$w_h/2)
GUICtrlSetOnEvent (-1,'Start')
GUISetState ()
Start ()
While 1
	CheckStats ()
	CheckWin ()
	Sleep (100)
WEnd
Func Start ()
	$turn = $nPLAYER
	$nTurnCount = 0
	WinSetState ($window_hwnd,'',@SW_ENABLE)
	For $n = 0 To 2
		For $u = 0 To 2
			GUICtrlSetData ($GRID[$n][$u],'')
			GUICtrlSetState ($GRID[$n][$u],64)
		Next
	Next
EndFunc
Func CheckStats ()
	If GUICtrlRead ($lWinCount) <> 'WINS:'&$nWinCount Then GUICtrlSetData ($lWinCount,'WINS:'&$nWinCount)
	If GUICtrlRead ($lLossCount) <> 'LOSSES:'&$nLossCount Then GUICtrlSetData ($lLossCount,'LOSSES:'&$nLossCount)
	If GUICtrlRead ($lTieCount) <> 'TIES:'&$nTieCount Then GUICtrlSetData ($lTieCount,'TIES:'&$nTieCount)
EndFunc
Func CheckWin ()
	Local $eval, $n
	$eval = StringEval($diagonal[0])
	If $eval = -3 Or $eval = 3 Then Win ($eval)
	$eval = StringEval($diagonal[1])
	If $eval = -3 Or $eval = 3 Then Win ($eval)
	For $n = 0 To 2
		$eval = StringEval($row[$n])
		If $eval = -3 Or $eval = 3 Then Win ($eval)
		$eval = StringEval($column[$n])
		If $eval = -3 Or $eval = 3 Then Win ($eval)
	Next
EndFunc
Func Win ($value)
	If $value/$nPLAYER = 3 Then
		MsgBox (0,'WIN','Player Has Won!',25,$window_hwnd)
		$nWinCount += 1
	EndIf
	If $value/$nAI = 3 Then
		MsgBox (0,'WIN','Computer Has Won!',25,$window_hwnd)
		$nLossCount += 1
	EndIf
	Start ()
EndFunc
Func Check ()
	Local $n
	If $nTurnCount >= 8 Then
		MsgBox (0,'TIE','Tie Game',25,$window_hwnd)
		$nTieCount += 1
		Start ()
	Else
		CheckMove(StringEval($diagonal[0]),$diagonal[0])
		CheckMove(StringEval($diagonal[1]),$diagonal[1])
		For $n = 0 To 2
			CheckMove(StringEval($row[$n]),$row[$n])
			CheckMove(StringEval($column[$n]),$column[$n])
		Next
		If $turn = $nAI Then
			If GUICtrlRead ($GRID[1][1]) == '' Then
				Move($GRID[1][1])
			Else
				If MiniMaxValuing ($GRIDval3) = -1 Then
					If MiniMaxValuing ($GRIDval2) = -1 Then
						Do
							$r = Random (0,2,1)
							$c = Random (0,2,1)
						Until GUICtrlRead ($GRID[$r][$c]) == ''
						Move ($GRID[$r][$c])
					EndIf
				EndIf
			EndIf
		EndIf
	EndIf
EndFunc
Func Move ($ID)
	GUICtrlSetData ($ID,$sAI)
	GUICtrlSetState ($ID,128)
	$turn = $nPLAYER
	$nTurnCount += 1
	WinSetState ($window_hwnd,'',@SW_ENABLE)
EndFunc
Func Clicked ()
	$turn = $nAI
	$nTurnCount += 1
	GUICtrlSetData (@GUI_CtrlId,$sPLAYER)
	GUICtrlSetState (@GUI_CtrlId,128)
	WinSetState ($window_hwnd,'',@SW_DISABLE)
	Check ()
EndFunc
Func CheckMove ($value,$IDarray)
	If $value = 3 Or $value = -3 Then
		Win ($value)
		If $turn = $nAI Then
			If GUICtrlRead ($GRID[1][1]) == '' Then
				Move ($GRID[1][1])
				Return
			EndIf
			If $value = 2 Or $value = -2 Then
				Local $guiIDarray = StringSplit ($IDarray,'|',2)
				Local $n = 0
				For $n = 0 To UBound ($guiIDarray)-1
					$guiIDarray[$n] = Number ($guiIDarray[$n])
					If GUICtrlRead ($guiIDarray[$n]) == '' Then
						Move ($guiIDarray[$n])
						Return
					EndIf
				Next
			EndIf
			Return
		EndIf
	EndIf
EndFunc
Func StringEval ($IDarray)
	Dim $guiIDarray = StringSplit ($IDarray,'|',2)
	Dim $valuearray[UBound ($guiIDarray)]
	Local $value = 0, $n = 0
	For $n = 0 To UBound ($guiIDarray)-1
		$guiIDarray[$n] = $guiIDarray[$n]
		If GUICtrlRead ($guiIDarray[$n]) == '' Then $valuearray[$n] = 0
		If GUICtrlRead ($guiIDarray[$n]) == $sPLAYER Then $valuearray[$n] = $nPLAYER
		If GUICtrlRead ($guiIDarray[$n]) == $sAI Then $valuearray[$n] = $nAI
		$value += $valuearray[$n]
	Next
	Return $value
EndFunc
Func MiniMaxValuing ($array)
	Local $n, $Count = ''
	For $n = 0 To UBound ($array,1)-1
		If GUICtrlRead ($array[$n]) == '' Then $Count &= $n & '|'
	Next
	If $Count == '' Then Return -1
	$Count = StringSplit (StringTrimRight ($Count,1),'|',2)
	Move ($array[$Count[Random (0,UBound ($Count,1)-1,1)]])
	Return 1
EndFunc
Func End ()
	Exit
EndFunc
Edited by CodyBarrett

Share this post


Link to post
Share on other sites



Posted

.. post some comments on how i could do it better please...

of course ^_^

1) make the x's and o's bigger, so they fill the button.

2) don't show the 2nd gui when ai is working. it looks so much better like this:

Func _PC_Move ()
	Do
		$i = Random (0, 9)
	Until GUICtrlRead ($Array[$i]) <> 'X' And GUICtrlRead ($Array[$i]) <> 'O'
	GUICtrlSetData ($Array[$i], 'X')
	GUICtrlSetState ($Array[$i], $GUI_DISABLE)
	$Turn += 1
	_MouseTrap ()
EndFunc

3) For other messages, try splashtexton...

Func _Tie_ ()
	SplashTextOn ("Result!!", "You tied the game!! <>_<>", 300, 50, -1, -1)
	Sleep (1000)
	_Random_ ()
	Sleep (1000)
	SplashOff ()
EndFunc

generally, just make it better!! I had a bit of fun though.

MDiesel

Share this post


Link to post
Share on other sites

Posted

well thanks.... i put the "Please wait..." to make it SEEM like the copmuter is making its decision haha ^_^ ill try a few more things out

Share this post


Link to post
Share on other sites

Posted

lol sooooo easy to take him down it needs more work on AI but still cool

GJ

Share this post


Link to post
Share on other sites

Posted

lol i made it in like.. 10 mins at school haha 7 of those minutes were googling how tic tac toe works... and i might still add a few strategies to the AI

if you didn't notice it has NO strategy.. just randomly pics out a black spot lmao

Share this post


Link to post
Share on other sites

Posted

I want to play X, and go first.

^_^

Share this post


Link to post
Share on other sites

Posted (edited)

well... sorry haha but in the new version up at the top... i havent won once.. and your still O but you get to go first

EDIT

just tested 10 times.. all 10 i started in the center.. it was a 40% WIN.. 30% TIE and 20% LOSE haha and well.. 10% glitch (would have been a win but it said TIE and restarted)

Edited by CodyBarrett

Share this post


Link to post
Share on other sites

Posted

well... sorry haha but in the new version up at the top... i havent won once.. and your still O but you get to go first

Lol I won first go ;) You Choose Bottom Left, Bottom Right, Then Middle Bottom. Simple ^_^

Share this post


Link to post
Share on other sites

Posted

lol sometimes it does that.. xD.. but then again.. i wanna keep the player interested and not frustrated... not like

"OMFG!! YOU DOU***BAG!! LEMME WIN ONCE!!! F***!!!"

but more like

"^_^ sweet i won!, lets play again!"

hahaha... but yeah anyone know how to fix the few bugs in there?

bugs i found:

#1 soemtimes if you go middle.. it replaces your O with an X and freezes... SOLUTION hit TAB then ENTER to restart

#2 sometimes when the AI is about to lose it calls a TIE...

#3 like the post above this.. sometimes it isn't very smart...SOLUTION make it smarter LMAO but nah...this isn't a real problem

Share this post


Link to post
Share on other sites

Posted

he keeps placing his "x" ontop of my "o" to bet me

Share this post


Link to post
Share on other sites

Posted (edited)

thats my problem #1... just hit TAB ENTER and it will restart it.. because it freezes when it happens... im not sure why this is happening

EDIT

fixed it alittle... UPDATED AT TOP lol

FIXED:

*reduced the glitches now it only does it a few times..

*smarter AI

*harder to win

*i find it more fun ^_^

Edited by CodyBarrett

Share this post


Link to post
Share on other sites

Posted

Very nice interface.

You will need to work on the code because the game is still bugged. Here is what I've noticed so far:

- sometimes the script replaces the upper corner with its own entry overwriting my own entry (work on _Find_Blank_Spot )

- sometimes the script decides it's a tie after only 2 moves

- the script freeze quite often during the game and it needs to be shut down

Other than that: keep up the good work ^_^

Share this post


Link to post
Share on other sites

Posted (edited)

thanks enaiman..

#1 ill look into..

i realized #2 when i went Middle.. bottom left... and it said tie...

#3 haven't had this happen yet in the new one but if it does hit [TAB] [Enter] to reset game...

EDIT

enaiman yours is VIRTUALY unbeatable(i haven't beaten it yet).. but i want mine to have some mercy on the user haha... ^_^

Edited by CodyBarrett

Share this post


Link to post
Share on other sites

Posted

I dug out my implementation of a zero-sum game where I implemented tic-tac-toe. I've posted here for reference should anyone find that they wanted to go down the route of using a minimax algorithm for a turn-based game. Apologies to CodyBarrett in advance to a little bit of thread hijacking. Sorry to say that mine doesn't let you win ^_^

#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <Array.au3>
#include <Misc.au3>

Global $aTree[10], $iSTM = Random(1, 2, 1)
$aTree[0] = "000000000"
Global $hBoard = GUICreate("Tic-Tac-Toe", 234, 234)
GUISetBkColor(0x000000)
Global $cBoard = GUICtrlCreateGraphic(8, 8, 218, 218)
GUISetState(@SW_SHOW)

_DrawBoard($aTree[0])

; Make the first move if necessary
If $iSTM = 2 Then
	_FindBestMove(0, $iSTM)
	$aTree[0] = $aTree[1]
	$iSTM = 3 - $iSTM
EndIf

Local $iMsg, $aCI, $x, $y, $iMove
Do
	$iMsg = GUIGetMsg()
	If $iMsg = $cBoard Then
		$aCI = GUIGetCursorInfo($hBoard)
		$aCI[0] -= 8
		$aCI[1] -= 8
		$x = Int($aCI[0] / 73)
		$y = Int($aCI[1] / 73)
		$iMove = $x + ($y * 3) + 1
		If StringMid($aTree[0], $iMove, 1) = "0" Then
			_MakeMove(0, $iMove, $iSTM)
			_DrawBoard(1)
			$aTree[0] = $aTree[1]
			$iSTM = 3 - $iSTM
			_FindBestMove(0, $iSTM)
			$aTree[0] = $aTree[1]
			$iSTM = 3 - $iSTM
		EndIf
	EndIf
	Sleep(10)
Until $iMsg = $GUI_EVENT_CLOSE

Exit

Func _RandomBoard()
	Local $i
	$aTree[1] = ""
	For $i = 1 To 9
		$aTree[1] &= String(Random(0, 2, 1))
	Next
	_DrawBoard(1)
EndFunc

Func _DrawBoard($iDepth)
	Local $i, $x, $y
	GUICtrlDelete($cBoard)
	$cBoard = GUICtrlCreateGraphic(8, 8, 218, 218)
	GUICtrlSetGraphic($cBoard, $GUI_GR_PENSIZE, 3)
	GUICtrlSetGraphic($cBoard, $GUI_GR_COLOR, 0xffffff, 0x000000)
	GUICtrlSetGraphic($cBoard, $GUI_GR_MOVE, 72, 0)
	GUICtrlSetGraphic($cBoard, $GUI_GR_LINE, 72, 217)
	GUICtrlSetGraphic($cBoard, $GUI_GR_MOVE, 145, 0)
	GUICtrlSetGraphic($cBoard, $GUI_GR_LINE, 145, 217)
	GUICtrlSetGraphic($cBoard, $GUI_GR_MOVE, 0, 72)
	GUICtrlSetGraphic($cBoard, $GUI_GR_LINE, 217, 72)
	GUICtrlSetGraphic($cBoard, $GUI_GR_MOVE, 0, 145)
	GUICtrlSetGraphic($cBoard, $GUI_GR_LINE, 217, 145)
	For $i = 1 To 9
		$x = Mod(($i - 1), 3) * 73 + 4
		$y = Int(($i - 1) / 3) * 73 + 4
		Switch StringMid($aTree[$iDepth], $i, 1)
			Case "1"
				GUICtrlSetGraphic($cBoard, $GUI_GR_ELLIPSE, $x, $y, 64, 64)
			Case "2"
				GUICtrlSetGraphic($cBoard, $GUI_GR_MOVE, $x, $y)
				GUICtrlSetGraphic($cBoard, $GUI_GR_LINE, $x + 63, $y + 63)
				GUICtrlSetGraphic($cBoard, $GUI_GR_MOVE, $x + 63, $y)
				GUICtrlSetGraphic($cBoard, $GUI_GR_LINE, $x, $y + 63)
		EndSwitch
	Next
	GUICtrlSetGraphic($cBoard, $GUI_GR_REFRESH)
EndFunc

Func _StaticEvaluator($iDepth)
	Local $s = 0
	$s += _ScoreLine($aTree[$iDepth], 1, 1)
	$s += _ScoreLine($aTree[$iDepth], 4, 1)
	$s += _ScoreLine($aTree[$iDepth], 7, 1)
	$s += _ScoreLine($aTree[$iDepth], 1, 3)
	$s += _ScoreLine($aTree[$iDepth], 2, 3)
	$s += _ScoreLine($aTree[$iDepth], 3, 3)
	$s += _ScoreLine($aTree[$iDepth], 1, 4)
	$s += _ScoreLine($aTree[$iDepth], 3, 2)
	Return $s
EndFunc

Func _ScoreLine(ByRef $sBoard, $a, $B)
	Local $s = StringMid($sBoard, $a, 1) & StringMid($sBoard, $a + $b, 1) & StringMid($sBoard, $a + $b + $b, 1)
	Switch $s
		Case "001", "010", "100"
			Return 1
		Case "011", "101", "110"
			Return 10
		Case "111"
			Return 1000
		Case "002", "020", "200"
			Return -1
		Case "022", "202", "220"
			Return -10
		Case "222"
			Return -1000
		Case Else
			Return 0
	EndSwitch
EndFunc

Func _GetLegalMoves(ByRef $iDepth, ByRef $iSideToMove)
	Local $s = "", $i = Random(0, 8, 1), $j
	For $j = 1 To 9
		If (StringMid($aTree[$iDepth], $i + 1, 1) = "0") Then
			$s &= String($i + 1)
		EndIf
		$i = Mod($i + 1, 9)
	Next
	Return StringSplit($s, "")
EndFunc

Func _MakeMove($iDepth, ByRef $iMove, ByRef $iSideToMove)
	$aTree[$iDepth + 1] = StringLeft($aTree[$iDepth], $iMove - 1) & String($iSideToMove) & StringMid($aTree[$iDepth], $iMove + 1)
EndFunc

Func _FindBestMove($iDepth, $iSideToMove)
	Local $iScore = _StaticEvaluator($iDepth)
	If $iDepth > 3 Then Return $iScore
	If StringInStr($aTree[$iDepth], "0") = 0 Then Return $iScore ; No valid moves available
	If ($iScore < -100) Or ($iScore > 100) Then Return $iScore ; Game is already won ... can't move any more
	Local $aMoves = _GetLegalMoves($iDepth, $iSideToMove), $i
	Local $iBestScore = _IIf(($iSideToMove = 1), -9999, 9999), $iNewScore, $iBestMove = 0
	For $i = 1 To $aMoves[0]
		_MakeMove($iDepth, $aMoves[$i], $iSideToMove)
		$iNewScore = _FindBestMove($iDepth + 1, 3 - $iSideToMove)
		If $iSideToMove = 1 Then
			If $iNewScore > $iBestScore Then
				$iBestScore = $iNewScore
				$iBestMove = $i
			EndIf
		Else
			If $iNewScore < $iBestScore Then
				$iBestScore = $iNewScore
				$iBestMove = $i
			EndIf
		EndIf
	Next
	If $iDepth = 0 Then
		_MakeMove($iDepth, $aMoves[$iBestMove], $iSideToMove)
		_DrawBoard($iDepth + 1)
	EndIf
	Return $iBestScore
EndFunc

WBD

Share this post


Link to post
Share on other sites

Posted

no problem WideBoyDixon... the more unbeatable examples the better... ill eventualy fix it.. got other stuff to do though

Share this post


Link to post
Share on other sites

Posted

@WideBoyDixon

Very nice approach - I really like it. Your example is exactly what I would expect from a good game algorythm.

It's a good algorythm and it finds always the best move. I like the way you keep the table info in a string ;)

Mine doesn't allow wins either but comparing to yours it looks like a "poor relative"

Very good job ^_^

Share this post


Link to post
Share on other sites

Posted

ima look into each of your guys code anyway.. see if i can learn something about the algo

Share this post


Link to post
Share on other sites

Posted

lol its beyond me... can some one post a simplified version?..... ^_^ i wish i was a genius

Share this post


Link to post
Share on other sites

Posted

I was frustrated so i put this project aside. Now im trying it again... its still possible to win, can someone help me by showing me what i'm doin wrong? i think it doesnt have any bugs so far can you guys voice your oppinions?

Share this post


Link to post
Share on other sites

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 account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0