'Test application to tes the minmax algorithm, as well as alpha-beta pruning inside of it. A tic-tac--toe program that will never lose. By Keegan Parker Public Class Form1 Public Const PLAYER_PIECE As String = "X" Public Const COMPUTER_PIECE As String = "O" Public Const HUMAN_WIN As Integer = -1 Public Const COMPUTER_WIN As Integer = 1 Public Const TIE As Integer = 0 Public Const COMPUTER As Boolean = True Public Const HUMAN As Boolean = False Public Game_Ended As Boolean = False Public Turn As String = "Human" Public Board(2, 2) As Board 'Sets all objects up (mostly labels, and the board) Private Sub On_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim intindex As Integer Dim intindex2 As Integer For intindex = 0 To 2 For intindex2 = 0 To 2 Dim Label As New Label Label.Name = "lbl" & intindex & intindex2 Label.AutoSize = False Label.TextAlign = ContentAlignment.MiddleCenter Label.Font = New Font("Arial", 48, FontStyle.Bold) Label.Size = New System.Drawing.Size(100, 100) Label.Location = New System.Drawing.Point(intindex * 100, intindex2 * 100) Label.BorderStyle = Windows.Forms.BorderStyle.FixedSingle Board(intindex, intindex2).lbl = Label Board(intindex, intindex2).posX = intindex Board(intindex, intindex2).posY = intindex2 Me.Controls.Add(Label) AddHandler Board(intindex, intindex2).lbl.Click, AddressOf Player_Move Next Next End Sub 'If a player clicks on one of the labels, it will attmpt to put a player piece on that tile, and direct the game to the computer's turn. Sub Player_Move(ByVal sender As System.Object, ByVal e As System.EventArgs) Dim Current_Board As Board = GetBoard(sender) Dim Best As Best If Current_Board.owner = Nothing Then Board(Current_Board.posX, Current_Board.posY).owner = PLAYER_PIECE Board(Current_Board.posX, Current_Board.posY).lbl.Text = PLAYER_PIECE Call Check_Board(Board, False) If Game_Ended = False Then Turn = "Computer" Best = Get_Computer_Move(COMPUTER, Board) Board(Best.MovePosX, Best.MovePosY).owner = COMPUTER_PIECE Board(Best.MovePosX, Best.MovePosY).lbl.Text = COMPUTER_PIECE Call Check_Board(Board, False) End If Game_Ended = False Turn = "Human" End If End Sub 'Checks win/tie conditions. If it is a simulation (for ai), then it will return a number. If it is for legitimate checking, it will call the win function, or tie. Function Check_Board(ByVal opBoard(,) As Board, ByVal simulation As Boolean) Dim intindex As Integer Dim intindex2 As Integer 'Vertical Check For intindex = 0 To 2 If opBoard(intindex, 0).owner = opBoard(intindex, 1).owner And opBoard(intindex, 1).owner = opBoard(intindex, 2).owner And opBoard(intindex, 0).owner <> Nothing Then If simulation = False Then Win() Else Return 1 End If End If Next 'Horizantal Check For intindex = 0 To 2 If opBoard(0, intindex).owner = opBoard(1, intindex).owner And opBoard(1, intindex).owner = opBoard(2, intindex).owner And opBoard(0, intindex).owner <> Nothing Then If simulation = False Then Win() Else Return 1 End If End If Next 'Diagonal Check Dim intoppindex As Integer Dim intoppindex2 As Integer For intindex = 0 To 2 Step 2 For intindex2 = 0 To 2 Step 2 If intindex = 0 Then intoppindex = 2 Else intoppindex = 0 End If If intindex2 = 0 Then intoppindex2 = 2 Else intoppindex2 = 0 End If If opBoard(intindex, intindex2).owner = opBoard(1, 1).owner And opBoard(1, 1).owner = opBoard(intoppindex, intoppindex2).owner And opBoard(intindex, intindex2).owner <> Nothing Then If simulation = False Then Win() Else Return 1 End If End If Next Next 'Full Board Dim movedcount As Integer For intindex = 0 To 2 For intindex2 = 0 To 2 If opBoard(intindex, intindex2).owner <> Nothing Then movedcount += 1 End If Next Next If movedcount = 9 Then If simulation = False Then MessageBox.Show("It is a tie. Resetting the board.") For intindex = 0 To 2 For intindex2 = 0 To 2 Board(intindex, intindex2).owner = Nothing Board(intindex, intindex2).lbl.Text = Nothing Next Next Game_Ended = True Else Return 0 End If End If Return Nothing End Function 'Allows labels to be processed in to the board Public Function GetBoard(ByVal sender As Label) Dim intindex As Integer Dim intindex2 As Integer For intindex = 0 To 2 For intindex2 = 0 To 2 If Board(intindex, intindex2).lbl.Name = sender.Name Then Return Board(intindex, intindex2) End If Next Next Return Nothing End Function 'If a player wins, it will display a message box and reset the board Sub Win() MessageBox.Show(Turn & " has won. Resetting the board.") Dim intindex As Integer Dim intindex2 As Integer For intindex = 0 To 2 For intindex2 = 0 To 2 Board(intindex, intindex2).owner = Nothing Board(intindex, intindex2).lbl.Text = Nothing Next Next Game_Ended = True End Sub 'Minmax algorithm that tries to get best possible move by accessing every possible scenario in the game tree. NOT WORKING. Returns a "best" object, that is then used to place the computer's piece. Public Function Get_Computer_Move(ByVal side As Boolean, ByVal opBoard(,) As Board) Dim mybest As New Best Dim reply As Best Dim LegalMoves As New List(Of LegalMove) LegalMoves = Get_Legal_Moves(opBoard) Dim oppside As Boolean If side = COMPUTER Then oppside = HUMAN Else oppside = COMPUTER End If If Check_Board(opBoard, True) <> Nothing Then mybest.Score = Check_Board(opBoard, True) Return mybest End If If side = COMPUTER Then mybest.Score = -2 Else mybest.Score = 2 End If For Each LegalMove In LegalMoves If side = COMPUTER Then opBoard(LegalMove.posX, LegalMove.posY).owner = COMPUTER_PIECE Else opBoard(LegalMove.posX, LegalMove.posY).owner = PLAYER_PIECE End If reply = Get_Computer_Move(oppside, opBoard) opBoard(LegalMove.posX, LegalMove.posY).owner = Nothing If (side = COMPUTER And reply.Score > mybest.Score) Or (side = HUMAN And reply.Score < mybest.Score) Then mybest.MovePosX = LegalMove.posX mybest.MovePosY = LegalMove.posY mybest.Score = reply.Score End If Next Return mybest End Function 'Returns potential legal moves on the board Public Function Get_Legal_Moves(ByVal opboard(,) As Board) Dim intindex As Integer Dim intindex2 As Integer Dim legalmoves As New List(Of LegalMove) For intindex = 0 To 2 For intindex2 = 0 To 2 If opboard(intindex, intindex2).owner = Nothing Then Dim legalmove As New LegalMove legalmove.posX = intindex legalmove.posY = intindex2 legalmoves.Add(legalmove) End If Next Next Return legalmoves End Function End Class Public Structure Board Public lbl As Label Public owner As String Public posX As Integer Public posY As Integer End Structure Public Structure LegalMove Public posX As Integer Public posY As Integer End Structure Public Structure Best Public MovePosX As Integer Public MovePosY As Integer Public Score As Integer End Structure