-
Notifications
You must be signed in to change notification settings - Fork 0
/
Form1.vb
321 lines (271 loc) · 10.7 KB
/
Form1.vb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
Imports System
Imports System.IO
Imports System.Text
Public Class Form1
Dim b As String
Dim RND As New Random
Dim box() As Integer = {0, 0, 0, 0, 0, 0, 0, 0, 0}
Public Shared Turn As Integer
Dim statistics As New Dictionary(Of String, Single)
Dim movement As String
Dim path As String = "..\data.txt"
Dim found As Boolean
Dim deep As Short = 3
Dim branch As Short = 3
Private Sub Form1_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
b = MsgBox("Are you sure you want to quit?", MsgBoxStyle.YesNo + MsgBoxStyle.Question, "Quit?")
If b = MsgBoxResult.No Then
Form2.Visible = True
End If
End Sub
Private Sub PlayerTurn(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Label1.Click, Label2.Click, Label3.Click, Label4.Click, Label5.Click, Label6.Click, Label7.Click, Label8.Click, Label9.Click
'cast Sender Object into Label
Dim clickedLabel = TryCast(sender, Label)
'check if the label is empty
If clickedLabel IsNot Nothing Then
If clickedLabel.Text = "" Then
clickedLabel.Text = "X"
'switch to computer turn if player havent win
If Not CheckWin() Then
ComputerTurn()
End If
End If
End If
End Sub
Private Sub ResetBtn(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Form2.Visible = True
Reset()
End Sub
Private Sub RecordMovement(ByVal sender As Object, ByVal e As System.EventArgs) Handles Label1.TextChanged, Label2.TextChanged, Label3.TextChanged, Label4.TextChanged, Label5.TextChanged, Label6.TextChanged, Label7.TextChanged, Label8.TextChanged, Label9.TextChanged
'cast Sender Object into Label
Dim ChangedLabel = TryCast(sender, Label)
If ChangedLabel IsNot Nothing Then
Dim label_no = Replace(ChangedLabel.Name, "Label", "")
movement += label_no
If ChangedLabel.Text = "X" Then
box(label_no - 1) = 1
ElseIf ChangedLabel.Text = "O" Then
box(label_no - 1) = 2
End If
End If
End Sub
Public Sub ComputerTurn()
Dim compLabel As Label
Dim potential As Integer
Dim reward As Single = 0
found = False
'check database to find similar record, follow the record with best result
'found: check if found good result(reward > 0)
'reward: result of previous record
'potential: movement of previous record
For Each statistic In statistics
If statistic.Key.Substring(0, statistic.Key.Length - 2).Equals(Turn & movement) And reward <= statistic.Value Then
reward = statistic.Value
potential = Integer.Parse(statistic.Key(movement.Length + 1))
found = True
End If
Next
'add greedy factor to encourage further exploration
Dim greedy As Integer = RND.Next(0, 10)
If Not found Or greedy < 7 Then
potential = Minimax(box, branch, deep, False) + 1
End If
compLabel = Me.Controls("Label" & potential)
compLabel.Text = "O"
CheckWin()
'Reinforcement Learning
If Not CheckWin() Then
''ComputerTurn1()
End If
End Sub
Public Sub ComputerTurn1()
Dim compLabel As Label
Dim potential As Integer
Dim reward As Single = 0
found = False
'check database to find similar record, follow the record with best result
'found: check if found good result(reward > 0)
'reward: result of previous record
'potential: movement of previous record
For Each statistic In statistics
If statistic.Key.Substring(0, statistic.Key.Length - 2).Equals(((Turn + 1) Mod 2) & movement) And reward <= statistic.Value Then
reward = statistic.Value
potential = Integer.Parse(statistic.Key(movement.Length + 1))
found = True
End If
Next
'add greedy factor to encourage further exploration
Dim greedy As Integer = RND.Next(0, 10)
If Not found Or greedy < 7 Then
potential = Minimax(box, branch, deep, True) + 1
End If
compLabel = Me.Controls("Label" & potential)
compLabel.Text = "X"
CheckWin()
'Reinforcement Learning
If Not CheckWin() Then
ComputerTurn()
End If
End Sub
Private Function Minimax(box() As Integer, branch As Short, deep As Short, is_player_turn As Boolean) As Short
Dim reward As Short = GetReward(box)
'end recursive loop if got winner, or reached maximum deep
If reward <> 0 Or deep = 0 Then
Return reward
End If
Dim rewards As New List(Of Short)
Dim max_reward_path As New Dictionary(Of Short, Short)
Dim number As Short = RND.Next(1, 9)
For i = 0 To Len(branch)
'copy array ByVal
Dim tempbox(8) As Integer
Array.Copy(box, tempbox, tempbox.Length)
number = GetRnd(number, tempbox)
'is_player_turn: true = -1, false = 0
tempbox(number) = is_player_turn + 2
'continue running recursive function, and switch turn
rewards.Add(Minimax(tempbox, branch, deep - 1, Not is_player_turn))
If Not max_reward_path.Keys.Contains(number) Then
max_reward_path.Add(number, rewards(i))
End If
Next
'if finished searching, return the value of position of the highest reward
If deep = Me.deep Then
If is_player_turn Then
Return max_reward_path.FirstOrDefault(Function(n) n.Value = max_reward_path.Values.Min()).Key
Else
Return max_reward_path.FirstOrDefault(Function(n) n.Value = max_reward_path.Values.Max()).Key
End If
End If
'apply minimax theory
If is_player_turn Then
Return rewards.Min
Else
Return rewards.Max
End If
End Function
Private Function GetRnd(number As Short, box() As Integer) As Short
For i = 0 To 8
'pick a random label, choose another one if the label is filled
number = ((number + 1) Mod 9)
If box(number) = 0 Then
Return number
End If
Next
End Function
Private Function GetWinner(box() As Integer) As Short
Dim winner As Short = -1
'check diagonal win status
If (box(0) = box(4) And box(4) = box(8)) Or (box(2) = box(4) And box(4) = box(6)) Then
winner = box(4)
Else
For i As Integer = 0 To 2
'check column and row win status
If box(i) = box(i + 3) And box(i + 3) = box(i + 6) Then
winner = box(i)
ElseIf box(3 * i) = box(3 * i + 1) And box(3 * i + 1) = box(3 * i + 2) Then
winner = box(3 * i)
End If
Next
End If
Return winner
End Function
Private Function GetReward(box() As Integer) As Short
Dim winner As Short = GetWinner(box)
Dim reward As Short = 0
If winner = 1 Then
'player wins
reward = -1
'b = MsgBox("You win!", MsgBoxStyle.OkOnly, "Congratulation!")
ElseIf winner = 2 Then
'computer wins
reward = 2
'b = MsgBox("Try again later.", MsgBoxStyle.OkOnly, "You lose!")
ElseIf winner = -1 And Array.IndexOf(box, 0) = -1 Then
'check if no winner and all label is filled
reward = 1
'b = MsgBox("It's a draw!", MsgBoxStyle.OkOnly, "Draw!")
End If
Return reward
End Function
Private Function CheckWin() As Boolean
'set reward for training computer
Dim reward As Single = GetReward(box)
If reward = 0 Then
'continue playing
Return False
End If
'game ended, store record to database
'apply Q-learning
Dim newKey As String = Turn & movement
'make sure the last value is the value made by AI
If Not (newKey.Length + Turn) Mod 2 = 0 Then
newKey = newKey.Remove(newKey.Length - 1)
End If
Dim learn_rate As Single = 0.9
While Not newKey.Length <= 1
If statistics.ContainsKey(newKey) Then
'update database if record exist
reward = (1 - learn_rate) * statistics(newKey) + learn_rate * reward
statistics(newKey) = reward
Else
'otherwise add new record to database
reward = learn_rate * reward
statistics.Add(newKey, reward)
End If
'add record for all of the moves made by AI
newKey = newKey.Remove(newKey.Length - 2)
End While
'store database into file
If statistics.Count > 0 Then
Dim tempstatistics As New List(Of String)
For Each statistic In statistics
tempstatistics.Add(statistic.Key + "," + statistic.Value.ToString)
Next
File.WriteAllLines(path, tempstatistics.ToArray())
End If
Static a As Integer = 0
'a += 1
'If a > 100 Then
' Return False
'End If
'If b = MsgBoxResult.Ok Then
' b = 0
' Reset()
'End If
Reset()
Return True
End Function
Public Sub Reset()
Dim Label As Label
For i = 1 To 9
Label = Me.Controls("Label" & i)
Label.Text = ""
Label.Visible = True
Next
box = {0, 0, 0, 0, 0, 0, 0, 0, 0}
movement = ""
statistics.Clear()
'retrive previous playing records from database
Dim tempstatistics As New List(Of String)
tempstatistics.AddRange(File.ReadAllLines(path))
For Each i In tempstatistics
'store playing movements and points into statistics
'statistics Key: movements; Value: reward
Dim s As String() = i.Split(",")
statistics.Add(s(0), s(1))
Next
'check whos turn before start game
If Turn = 2 Then
ComputerTurn()
Else
''ComputerTurn1()
End If
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'create database if databases not exist
If Not File.Exists(path) Then
File.WriteAllText(path, "")
End If
End Sub
End Class