-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmain.go
150 lines (142 loc) · 3.88 KB
/
main.go
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
package main
import (
"fmt"
"os"
"time"
"github.com/gonum/plot"
"github.com/gonum/plot/plotter"
"github.com/gonum/plot/plotutil"
"github.com/gonum/plot/vg"
)
func nbWins(wins []entry, c boardCase) int {
count := 0
for _, e := range wins {
if e.Value == c {
count++
}
}
return count
}
type entry struct {
Timestamp int64 `json:"timestamp"`
Value boardCase `json:"value"`
}
func (e entry) String() string {
return fmt.Sprintf("%v, %v\n", e.Timestamp, e.Value)
}
func main() {
start := time.Now().UnixNano()
plot := len(os.Args) > 1 && os.Args[1] == "--plot"
// Create the board and two agent
var b board
a1 := agent{history: make(map[string]*state), gameMoves: make(map[string]*state), sign: x}
a2 := agent{history: make(map[string]*state), gameMoves: make(map[string]*state), sign: o}
// Set the number of games to play and when a1 forget and stop to learn
loopNb := 3000
wins := make([]entry, 0, loopNb)
interWins := make([]entry, 0, loopNb/2)
for i := 0; i < loopNb; i++ {
b = newBoard()
if i >= loopNb/2 {
// After half, always make a1 forget
// At half, reset the agent's win count
if i == loopNb/2 {
a2.history = make(map[string]*state)
// Display stats
fmt.Println("-------------")
fmt.Println("Both learning")
fmt.Println("-------------")
fmt.Printf("%v wins %v%% times\n", a1.sign, float64(nbWins(interWins, a1.sign))/float64(i)*100)
fmt.Printf("%v wins %v%% times\n", a2.sign, float64(nbWins(interWins, a2.sign))/float64(i)*100)
fmt.Println("====================================")
interWins = make([]entry, 0, loopNb/2)
}
}
// Play the game until the board is full or there is a winner
// Alternate who begin to play
for true {
if i%2 == 0 {
if b.isFull() || b.getWinnerSign() != e {
break
}
a1.play(b)
if b.isFull() || b.getWinnerSign() != e {
break
}
a2.play(b)
} else {
if b.isFull() || b.getWinnerSign() != e {
break
}
a2.play(b)
if b.isFull() || b.getWinnerSign() != e {
break
}
a1.play(b)
}
}
// Get the winner and give rewards
winnerSign := b.getWinnerSign()
if winnerSign == a1.sign {
a1.feed(1)
a2.feed(0)
wins = append(wins, entry{time.Now().UnixNano() - start, winnerSign})
interWins = append(interWins, entry{time.Now().UnixNano() - start, winnerSign})
} else if winnerSign == a2.sign {
a1.feed(0)
a2.feed(1)
wins = append(wins, entry{time.Now().UnixNano() - start, winnerSign})
interWins = append(interWins, entry{time.Now().UnixNano() - start, winnerSign})
} else {
a1.feed(0)
a2.feed(0)
}
}
// Display new stats
fmt.Println("------------------")
fmt.Println("x forget, o learns")
fmt.Println("------------------")
fmt.Printf("%v wins %v%% times\n", a1.sign, float64(nbWins(interWins, a1.sign))/float64(loopNb/2)*100)
fmt.Printf("%v wins %v%% times\n", a2.sign, float64(nbWins(interWins, a2.sign))/float64(loopNb/2)*100)
if plot {
generateFigure(wins, loopNb, a1, a2)
}
}
// Generate figure from the wins array
func generateFigure(wins []entry, loopNb int, a1 agent, a2 agent) {
// Create plot
p, err := plot.New()
if err != nil {
panic(err)
}
// Set plot meta data
p.Title.Text = "Both learn then O forget"
p.X.Label.Text = "Time"
p.Y.Label.Text = "Number of wins"
// Build plot data
ptsX := make(plotter.XYs, nbWins(wins, a1.sign)+1)
ptsO := make(plotter.XYs, nbWins(wins, a2.sign)+1)
countX := 0
countO := 0
for _, w := range wins[:loopNb] {
if w.Value == x {
countX++
ptsX[countX].Y = float64(countX)
ptsX[countX].X = float64(w.Timestamp)
} else if w.Value == o {
countO++
ptsO[countO].Y = float64(countO)
ptsO[countO].X = float64(w.Timestamp)
}
}
// Add data to plot
err = plotutil.AddLines(p, "X", ptsX, "O", ptsO)
if err != nil {
panic(err)
}
// Save the plot to a PNG file.
err = p.Save(4*vg.Inch, 4*vg.Inch, "points.png")
if err != nil {
panic(err)
}
}