Sub DrawLine
For m = 0 To 1 Step 0.025
_x2 = x1 * (1 - m) + x2 * m
_y2 = y1 * (1 - m) + y2 * m
If 0 < m Then
GraphicsWindow.DrawLine(_x1, _y1, _x2, _y2)
Program.Delay(10)
EndIf
_x1 = _x2
_y1 = _y2
EndFor
EndSub
Sub DrawEllipse
a = width / 2
b = height / 2
ox = x + width / 2
oy = y + height / 2
For angle = 0 To 360 Step 10
θ = Math.GetRadians(angle)
_x2 = ox - a * Math.Sin(θ)
_y2 = oy + b * Math.Cos(θ)
If 0 < angle Then
GraphicsWindow.DrawLine(_x1, _y1, _x2, _y2)
Program.Delay(10)
EndIf
_x1 = _x2
_y1 = _y2
EndFor
EndSub
Sub Player_MiniMax
' Player MINIMAX | Next move
' param Player_iLevel - depth level
' return iX, iY - next move position when Player_iLevel = LEVEL
' return iScore - evaluated score
Stack.PushValue("nextmove", iX)
Stack.PushValue("nextmove", iY)
Stack.PushValue("nextmove", iTurn)
Stack.PushValue("nextmove", iMaxScore)
Stack.PushValue("nextmove", bMax)
iTurn = Math.Remainder(Board_iMove, 2) + 1
If iTurn = CROSS Then
iMaxScore = -2 ' minimum
ElseIf iTurn = NOUGHT Then
iMaxScore = 2 ' maximum
EndIf
bMax = "True"
For iY = 1 To Board_iRo
For iX = 1 To Board_iRo
Game_IsPossibleMove()
If Game_bIsPossibleMove Then
If bMax = "False" Then
iXC = iX
iXY = iY
EndIf
Board_Move()
GameRecord_Move()
Game_Judge()
If Game_iWinner = CROSS Then
iScore = 1
ElseIf Game_iWinner = NOUGHT Then
iScore = -1
ElseIf Game_iWinner = DRAW Then
iScore = 0
ElseIf Player_iLevel > 1 Then
Player_iLevel = Player_iLevel - 1
Player_MiniMax()
Player_iLevel = Player_iLevel + 1
Else
iScore = 0
EndIf
If iTurn = CROSS And iScore >= iMaxScore Then ' Max level
iMaxScore = iScore
If Player_iLevel = LEVEL Then
bMax = "True"
iXC = iX
iYC = iY
EndIf
ElseIf iTurn = NOUGHT And iScore <= iMaxScore Then ' Minimum level
iMaxScore = iScore
EndIf
Board_Unmove()
GameRecord_Unmove()
EndIf
EndFor
EndFor
bMax = Stack.PopValue("nextmove")
iScore = iMaxScore
iMaxScore = Stack.PopValue("nextmove")
iTurn = Stack.PopValue("nextmove")
iY = Stack.PopValue("nextmove")
iX = Stack.PopValue("nextmove")
If Player_iLevel = LEVEL Then
iX = iXC ' next move candidate
iY = iYC ' next move candidate
EndIf
EndSub
Sub Player_Human
' Player HUMAN | Next move
' return iX, iY - next move position
GraphicsWindow.MouseDown = Player_OnMouseDown
While "True"
Player_bOutOfBoard = "True"
While Player_bOutOfBoard
Player_bNotClicked = "True"
While Player_bNotClicked
Program.Delay(200)
EndWhile
Player_GetPosition()
EndWhile
Game_IsPossibleMove()
If Game_bIsPossibleMove Then
Goto lPossibleMove
Else
Sound.PlayChimeAndWait()
EndIf
EndWhile
lPossibleMove:
GraphicsWindow.MouseDown = Player_DoNothing
iTurn = Math.Remainder((Board_iMove - 1), 2) + 1
EndSub
Sub Player_OnMouseDown
' Player HUMAN | Get mouse position
' return Player_iMX, Player_iMY - clicked mouse position
' return Player_bNotClicked - flag
Player_iMX = GraphicsWindow.MouseX
Player_iMY = GraphicsWindow.MouseY
Player_bNotClicked = "False"
EndSub
Sub Player_DoNothing
EndSub
Sub Player_GetPosition
' Player HUMAN | Get board position from mouse position
' return iX, iY - next move position
iX = Math.Floor((Player_iMX - Board_iX0) / Board_idX) + 1
iY = Math.Floor((Player_iMY - Board_iY0) / Board_idY) + 1
If iX < 1 Or iX > Board_iRo Or iY < 1 Or iY > Board_iRo Then
Player_bOutOfBoard = "True"
Else
Player_bOutOfBoard = "False"
EndIf
EndSub
Sub Game_GetPossibleMoves
' Game | Get possible moves list
' param Board_iCell[][] - board
' return iPossible - entry count of possible moves
' return iPX[], iPY[] - possible moves
' work iNP - instead of x, y for Board_iCell[][]
iPossible = 0
For iNP = 0 To 8
If Board_iCell[Math.Remainder(iNP, 3) + 1][Math.Floor(iNP / 3) + 1] = SPACE Then
iPossible = iPossible + 1
iPX[iPossible] = Math.Remainder(iNP, 3) + 1
iPY[iPossible] = Math.Floor(iNP / 3) + 1
EndIf
EndFor
EndSub
Sub Game_Init
' Game | Initialization
GraphicsWindow.BackgroundColor = "LightGray"
GraphicsWindow.Title = "Tic-tac-toe " + VERSION
Console_bShowResult = "True"
Console_bSound = "True"
Board_Init()
Console_Init()
EndSub
Sub Game_New
' Game | Set game properties for new game
Board_New()
Console_New()
GameRecord_New()
Controls.HideControl(Console_oReplay)
Controls.HideControl(Console_oNew)
Game_iWinner = SPACE
EndSub
Sub Game_IsPossibleMove
' Game | Is possible move?
' param iX, iY - next move
If Board_iCell[iX][iY] = SPACE Then
Game_bIsPossibleMove = "True"
Else
Game_bIsPossibleMove = "False"
EndIf
EndSub
Sub Game_Judge
' Game | Judge
Stack.PushValue("judge", iX)
Stack.PushValue("judge", iY)
Stack.PushValue("judge", iTurn)
If Console_bShowResult Then
GraphicsWindow.PenColor = "Magenta"
GraphicsWindow.PenWidth = 5
EndIf
Game_iWinner = SPACE
iTurn = Board_iCell[1][1] ' \
If iTurn = SPACE Then
Goto lLine2
EndIf
For i = 2 To Board_iRo
If Board_iCell[i][i] <> iTurn Then
Goto lLine2
EndIf
EndFor
If Console_bShowResult Then
x1 = Board_iX0
y1 = Board_iY0
x2 = Board_iX1
y2 = Board_iY1
DrawLine()
EndIf
Game_iWinner = iTurn
lLine2:
iTurn = Board_iCell[Board_iRo][1] ' /
If iTurn = SPACE Then
Goto lLine3
EndIf
For i = 2 To Board_iRo
If Board_iCell[Board_iRo + 1 - i][i] <> iTurn Then
Goto lLine3
EndIf
EndFor
If Console_bShowResult Then
x1 = Board_iX1
y1 = Board_iY0
x2 = Board_iX0
y2 = Board_iY1
DrawLine()
EndIf
Game_iWinner = iTurn
lLine3:
For iY = 1 To Board_iRo
iTurn = Board_iCell[1][iY]
If iTurn = SPACE Then
Goto lLine4
EndIf
For iX = 2 To Board_iRo
If Board_iCell[iX][iY] <> iTurn Then
Goto lLine4
EndIf
EndFor
If Console_bShowResult Then
x1 = Board_iX0
y1 = Board_iY0 + (iY - 1 / 2) * Board_idY
x2 = Board_iX1
y2 = Board_iY0 + (iY - 1 / 2) * Board_idY
DrawLine()
EndIf
Game_iWinner = iTurn
lLine4:
EndFor
For iX = 1 To Board_iRo
iTurn = Board_iCell[iX][1]
If iTurn = SPACE Then
Goto lLine5
EndIf
For iY = 2 To Board_iRo
If Board_iCell[iX][iY] <> iTurn Then
Goto lLine5
EndIf
EndFor
If Console_bShowResult Then
x1 = Board_iX0 + (iX - 1 / 2) * Board_idX
y1 = Board_iY0
x2 = Board_iX0 + (iX - 1 / 2) * Board_idX
y2 = Board_iY1
DrawLine()
EndIf
Game_iWinner = iTurn
lLine5:
EndFor
If Board_iMove = 9 And Game_iWinner = SPACE Then
Game_iWinner = DRAW
EndIf
If Game_iWinner = CROSS Then
Game_iScore = 1
ElseIf Game_iWinner = NOUGHT Then
Game_iScore = -1
Else
Game_iScore = 0
EndIf
If Console_bShowResult And Game_iWinner <> SPACE Then
Console_ShowWinner()
EndIf
iTurn = Stack.PopValue("judge")
iY = Stack.PopValue("judge")
iX = Stack.PopValue("judge")
EndSub
Sub Console_DoNothing
' Game console | Do nothing
EndSub
Sub Console_OnButtonClicked
' Game console | Set flags about clicked buttons
' return Console_bReplay, Console_bNew, Console_bButtonClicked
If Controls.LastClickedButton = Console_oReplay Then
Console_bReplay = "True"
Else
Console_bReplay = "False"
EndIf
If Controls.LastClickedButton = Console_oNew Then
Console_bNew = "True"
Else
Console_bNew = "False"
EndIf
If Console_bReplay Or Console_bNew Then
Console_bButtonClicked = "True"
Else
Console_bButtonClicked = "False"
EndIf
EndSub
Sub Console_New
' Game console | Set console for new game
Lamp_iOn = CROSS
Lamp_Draw()
Console_bReplay = "False"
Console_bNew = "False"
Controls.SetTextBoxText(Console_oGameRecord, GameRecord_sBuf)
GameRecord_Write()
EndSub
Sub Console_ShowWinner
' Game console | Show winner to console
iX = Board_iX1 + Board_isX * 2
iY = Board_iY0 + 30
GraphicsWindow.BrushColor = "Black"
If Game_iWinner = CROSS Then
GraphicsWindow.DrawText(iX, iY, "WIN")
ElseIf Game_iWinner = NOUGHT Then ' NAUGHT ???
GraphicsWindow.DrawText(iX, iY, "LOSE")
ElseIf Game_iWinner = DRAW Then
GraphicsWindow.DrawText(iX, iY, "DRAW")
EndIf
iY = iY + Board_iRo * Board_idY / 3
If Game_iWinner = NOUGHT Then
GraphicsWindow.DrawText(iX, iY, "WIN")
ElseIf Game_iWinner = CROSS Then
GraphicsWindow.DrawText(iX, iY, "LOSE")
ElseIf Game_iWinner = DRAW Then
GraphicsWindow.DrawText(iX, iY, "DRAW")
EndIf
EndSub
Sub Board_New
' Tic-tac-toe board | Set board for new game
Board_iMove = 0
For iY = 1 To Board_iRo
For iX = 1 To Board_iRo
Board_iCell[iX][iY] = SPACE
EndFor
EndFor
Board_Draw()
If Console_bShowResult Then
Console_HideWinner()
EndIf
EndSub
Sub Board_Draw
' Tic-tac-toe board | Draw board
GraphicsWindow.BrushColor = "#003300"
GraphicsWindow.FillRectangle(Board_iX0 - Board_isX, Board_iY0 - Board_isY, Board_iRo * Board_idX + 2 * Board_isX, Board_iRo * Board_idY + 2 * Board_isY)
If Not[done] Then
path = Program.Directory + "\BoardMask.png"
img = ImageList.LoadImage(path)
If ImageList.GetHeightOfImage(img) = 0 Then
url = "http://www.nonkit.com/smallbasic.files/BoardMask.png"
path2 = Network.DownloadFile(url)
' The following line could be harmful and has been automatically commented.
' File.CopyFile(path2, path)
img = ImageList.LoadImage(url)
EndIf
mask = Shapes.AddImage(img)
Shapes.Move(mask, Board_iX0 - Board_isX, Board_iY0 - Board_isY)
done = "True"
EndIf
GraphicsWindow.PenColor = "Khaki"
GraphicsWindow.PenWidth = 5
For i = 1 To Board_iRo - 1
iX = Board_iX0 + Board_idX * i
iY = Board_iY0 + Board_idY * i
x1 = Board_iX0
y1 = iY
x2 = Board_iX1
y2 = iY
DrawLine()
x1 = iX
y1 = Board_iY0
x2 = iX
y2 = Board_iY1
DrawLine()
EndFor
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 20
For i = 1 To Board_iRo
iX = Board_iX0 + Board_idX * (i - 1) + Board_idX / 2
GraphicsWindow.DrawText(iX, Board_iY0 - 2.5 * Board_isY, Board_cX[i])
iY = Board_iY0 + Board_idY * (i - 1) + Board_idY / 2
GraphicsWindow.DrawText(Board_iX0 - 2.5 * Board_isX, iY, Board_cY[i])
EndFor
EndSub
Sub Board_Move
' Tic-tac-toe board | set next move to board and draw the move
' param iX, iY - next move
Game_IsPossibleMove()
If Game_bIsPossibleMove Then
Board_iMove = Board_iMove + 1
iTurn = Math.Remainder((Board_iMove - 1), 2) + 1
Board_iCell[iX][iY] = iTurn
If Console_bShow Then
If iTurn = CROSS Then
Board_DrawCross()
ElseIf iTurn = NOUGHT Then
Board_DrawNought()
EndIf
GraphicsWindow.BrushColor = "Khaki"
GraphicsWindow.DrawText(Board_iX0 + (iX - 1) * Board_idX + Board_isX / 3, Board_iY0 + (iY - 1) * Board_idY + Board_isY / 3, Board_iMove)
If Console_bSound Then
Sound.PlayClickAndWait()
EndIf
EndIf
Else
TextWindow.Write("ERROR: Board_Move(")
Debug_DumpXY()
EndIf
EndSub
Sub Board_Unmove
' Tic-tac-toe board | Undo last move
' param GameRecord_iX[], GameRecord_iY[] - last moves
' return iX, iY - last move
iX = GameRecord_iX[GameRecord_iMove]
iY = GameRecord_iY[GameRecord_iMove]
If Board_iCell[iX][iY] <> SPACE Then
Board_iCell[iX][iY] = SPACE
If Console_bShow Then
GraphicsWindow.BrushColor = "DarkGreen"
GraphicsWindow.FillRectangle(Board_iX0 + (iX - 1) * Board_idX + 3, Board_iY0 + (iY - 1) * Board_idY + 3, Board_idX - 6, Board_idY - 6)
EndIf
Board_iMove = Board_iMove - 1
iTurn = Math.Remainder(Board_iMove - 1, 2) + 1
EndIf
EndSub
Sub GameRecord_New
' Game record | Set game record to new game
GameRecord_iMove = 0
Controls.SetTextBoxText(Console_oGameRecord, "")
EndSub
Sub GameRecord_Replay
' Game record | Replay game record
For iMove = 1 To GameRecord_iMove
iX = GameRecord_iX[iMove]
iY = GameRecord_iY[iMove]
iTurn = GameRecord_iTurn[iMove]
Lamp_iOn = iTurn
Lamp_Draw()
Board_Move()
Game_Judge()
EndFor
EndSub
Sub GameRecord_Read
' Game record | Read game record from textbox
GameRecord_iMove = 0
Parse_sBuf = Controls.GetTextBoxText(Console_oGameRecord)
Parse_iBufPtr = 1
Parse_iBufLen = Text.GetLength(Parse_sBuf)
While Parse_iBufPtr <= Parse_iBufLen
Parse_Move()
If Parse_bError Then
Parse_iBufPtr = Parse_iBufPtr + 1
EndIf
EndWhile
EndSub
Sub GameRecord_Write
' Game record | Write game record to textbox
GameRecord_sBuf = ""
For iMove = 1 To GameRecord_iMove
GameRecord_sBuf = GameRecord_sBuf + Text.GetSubText("ABCD", GameRecord_iX[iMove], 1)
GameRecord_sBuf = GameRecord_sBuf + Text.GetSubText("1234", GameRecord_iY[iMove], 1)
If iMove < GameRecord_iMove Then
GameRecord_sBuf = GameRecord_sBuf + " "
EndIf
EndFor
Controls.SetTextBoxText(Console_oGameRecord, GameRecord_sBuf)
EndSub
Sub GameRecord_Move
' Game record | Record next move
GameRecord_iMove = GameRecord_iMove + 1
iTurn = Math.Remainder(GameRecord_iMove - 1, 2) + 1
GameRecord_iTurn[GameRecord_iMove] = iTurn
GameRecord_iX[GameRecord_iMove] = iX
GameRecord_iY[GameRecord_iMove] = iY
EndSub
Sub GameRecord_Unmove
' Game record | Undo last move in game recode
If GameRecord_iMove > 0 Then
GameRecord_iMove = GameRecord_iMove - 1
iTurn = Math.Remainder(GameRecord_iMove - 1, 2) + 1
EndIf
EndSub
Sub Parse_Move
' Game record parse | Parse move in textbox
Parse_Upper()
If Parse_bError = "False" Then
iX = Text.GetIndexOf("ABCD", Parse_c)
Parse_Digit()
If Parse_bError = "False" Then
iY = Text.GetIndexOf("1234", Parse_c)
GameRecord_Move()
EndIf
EndIf
EndSub
Sub Parse_Upper
' Game record parse | Parse upper case char in textbox
Parse_c = Text.GetSubText(Parse_sBuf, Parse_iBufPtr, 1)
iCode = Text.GetCharacterCode(Parse_c)
If iCode >= UPPERA And iCode <= UPPERZ Then
Parse_bError = "False"
Parse_iBufPtr = Parse_iBufPtr + 1
Else
Parse_bError = "True"
EndIf
EndSub
Sub Parse_Digit
' Game record parse | Parse digit in textbox
Parse_c = Text.GetSubText(Parse_sBuf, Parse_iBufPtr, 1)
iCode = Text.GetCharacterCode(Parse_c)
If iCode >= LETTER0 And iCode <= LETTER9 Then
Parse_bError = "False"
Parse_iBufPtr = Parse_iBufPtr + 1
Else
Parse_bError = "True"
EndIf
EndSub
Sub Debug_DumpXY
' Debug | Dump iX iY
' param iX, iY
TextWindow.WriteLine("iX = " + iX + ", iY= " + iY)
EndSub