/
parse.go
124 lines (106 loc) · 2.66 KB
/
parse.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
package fetch
import (
"compress/bzip2"
"log"
"math/rand"
"net/http"
"time"
"github.com/notnil/chess"
"github.com/srom/chessbot/common"
"gopkg.in/freeeve/pgn.v1"
)
const DIMENSION = 768 // 8 * 8 squares * 12 piece types
const CHAN_BUFFER = 1e4
func YieldTriplets(urls <-chan string) <-chan *common.ChessBotTriplet {
rand.Seed(time.Now().UnixNano())
features := make(chan *common.ChessBotTriplet, CHAN_BUFFER)
go func() {
defer close(features)
for url := range urls {
log.Printf("Reading data from %v", url)
response, err := http.Get(url)
if err != nil {
log.Printf("Error reading url %v: %v", url, err)
continue
}
scanGames(response, features)
}
}()
return features
}
func scanGames(response *http.Response, features chan *common.ChessBotTriplet) {
defer func() {
if r := recover(); r != nil {
log.Printf("Recovered: %v", r)
}
}()
reader := bzip2.NewReader(response.Body)
ps := pgn.NewPGNScanner(reader)
for ps.Next() {
scanGame(ps, features)
}
}
func scanGame(ps *pgn.PGNScanner, features chan *common.ChessBotTriplet) {
game, err := ps.Scan()
if err != nil {
log.Printf("Error reading game: %v", err)
return
}
parseGame(game, features)
}
func parseGame(game *pgn.Game, features chan *common.ChessBotTriplet) {
board := pgn.NewBoard()
var parent *common.BoardBits
for i, move := range game.Moves {
if i == 0 {
parent = getBoardBits(board)
}
pgnBoard := pgn.FENFromBoard(board).String()
randomNextBoard, err := getRandomNextBoard(pgnBoard)
if err != nil {
log.Printf("Error getting random board: %v", err)
return
}
random := getBoardBits(randomNextBoard)
board.MakeMove(move)
observed := getBoardBits(board)
features <- getTriplet(parent, observed, random)
}
}
func getBoardBits(board *pgn.Board) *common.BoardBits {
pieces := make([]uint32, 0, DIMENSION)
for _, piece := range common.PIECES {
for _, position := range common.POSITIONS {
if board.GetPiece(position) == piece {
pieces = append(pieces, 1)
} else {
pieces = append(pieces, 0)
}
}
}
return &common.BoardBits{
Pieces: pieces,
}
}
func getTriplet(parent, observed, random *common.BoardBits) *common.ChessBotTriplet {
return &common.ChessBotTriplet{
Parent: parent,
Observed: observed,
Random: random,
}
}
func getRandomNextBoard(boardFen string) (*pgn.Board, error) {
fen, err := chess.FEN(boardFen)
if err != nil {
return nil, err
}
chessGame := chess.NewGame(fen)
moves := chessGame.ValidMoves()
move := randomMove(moves)
chessGame.Move(move)
return pgn.NewBoardFEN(chessGame.FEN())
}
func randomMove(moves []*chess.Move) *chess.Move {
index := rand.Intn(len(moves))
return moves[index]
}