pgn 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/pgn/move_calculator.rb +1 -1
- data/lib/pgn/parser.rb +59 -51
- data/lib/pgn/version.rb +1 -1
- data/spec/parser_spec.rb +65 -65
- data/spec/pgn_files/empty_variation_move.pgn +11 -0
- data/spec/pgn_files/nested_comments.pgn +4 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a5c9a8ca0a6c732bd3ec99585b21929c1710976e
|
4
|
+
data.tar.gz: ff812fc594259ffa25370d3e35eed074c56a3c41
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 05e7faa858c9ee725416c0c87021ac2b3440407b41de732ce6049f446ede8736e039c7f0a8658cba5dced9c6d27a07ad50e0c176e04afbede60cb959c2d267a9
|
7
|
+
data.tar.gz: c5d008c3d2d579dd39b3ab76889cf697252d12eac55f5cab69665dd04b2cbc03227de4487325a476a45b1fe9a435e1fb41ad775b456fd5e5b5297fafc4624cbe
|
data/lib/pgn/move_calculator.rb
CHANGED
data/lib/pgn/parser.rb
CHANGED
@@ -5,46 +5,48 @@ module PGN
|
|
5
5
|
# context free grammar.
|
6
6
|
#
|
7
7
|
class Parser < Whittle::Parser
|
8
|
-
rule(:
|
8
|
+
rule(wsp: /\s+/).skip!
|
9
9
|
|
10
|
-
rule(
|
11
|
-
rule(
|
12
|
-
rule(
|
13
|
-
rule(
|
10
|
+
rule('[')
|
11
|
+
rule(']')
|
12
|
+
rule('(')
|
13
|
+
rule(')')
|
14
14
|
|
15
15
|
start(:pgn_database)
|
16
16
|
|
17
17
|
rule(:pgn_database) do |r|
|
18
18
|
r[].as { [] }
|
19
|
-
r[:pgn_game, :pgn_database].as {|game, database| database << game }
|
19
|
+
r[:pgn_game, :pgn_database].as { |game, database| database << game }
|
20
20
|
end
|
21
21
|
|
22
22
|
rule(:pgn_game) do |r|
|
23
|
-
r[:tag_section, :movetext_section].as
|
23
|
+
r[:tag_section, :movetext_section].as do |tags, moves|
|
24
|
+
{ tags: tags, result: moves.pop, moves: moves }
|
25
|
+
end
|
24
26
|
end
|
25
27
|
|
26
28
|
rule(:tag_section) do |r|
|
27
|
-
r[:tag_pair, :tag_section].as {|pair, section| section.merge(pair) }
|
29
|
+
r[:tag_pair, :tag_section].as { |pair, section| section.merge(pair) }
|
28
30
|
r[:tag_pair]
|
29
31
|
end
|
30
32
|
|
31
33
|
rule(:tag_pair) do |r|
|
32
|
-
r[
|
34
|
+
r['[', :tag_name, :tag_value, ']'].as { |_, a, b, _| { a => b } }
|
33
35
|
end
|
34
36
|
|
35
37
|
rule(:tag_value) do |r|
|
36
|
-
r[:string].as {|value| value[1...-1] }
|
38
|
+
r[:string].as { |value| value[1...-1] }
|
37
39
|
end
|
38
40
|
|
39
41
|
rule(:movetext_section) do |r|
|
40
|
-
r[:element_sequence, :game_termination].as {|a, b| a.reverse << b }
|
42
|
+
r[:element_sequence, :game_termination].as { |a, b| a.reverse << b }
|
41
43
|
end
|
42
44
|
|
43
45
|
rule(:element_sequence) do |r|
|
44
|
-
r[:element, :element_sequence].as
|
46
|
+
r[:element, :element_sequence].as do |element, sequence|
|
47
|
+
element.nil? ? sequence : sequence << element
|
48
|
+
end
|
45
49
|
r[].as { [] }
|
46
|
-
#r[:recursive_variation, :element_sequence]
|
47
|
-
#r[:recursive_variation]
|
48
50
|
end
|
49
51
|
|
50
52
|
rule(:element) do |r|
|
@@ -56,34 +58,36 @@ module PGN
|
|
56
58
|
end
|
57
59
|
r[:comment].as { nil }
|
58
60
|
end
|
59
|
-
|
61
|
+
|
60
62
|
rule(:san_move_annotated) do |r|
|
61
63
|
r[:san_move].as { |move| MoveText.new(move) }
|
62
|
-
r[:san_move, :comment].as
|
63
|
-
|
64
|
-
|
64
|
+
r[:san_move, :comment].as do |move, comment|
|
65
|
+
MoveText.new(move, nil, comment)
|
66
|
+
end
|
67
|
+
r[:san_move, :numeric_annotation_glyph].as do |move, annotation|
|
68
|
+
MoveText.new(move, annotation)
|
69
|
+
end
|
70
|
+
r[:san_move, :numeric_annotation_glyph, :comment].as do |move, annotation, comment|
|
71
|
+
MoveText.new(move, annotation, comment)
|
72
|
+
end
|
73
|
+
r[:san_move, :comment, :numeric_annotation_glyph].as do |move, comment, annotation|
|
74
|
+
MoveText.new(move, annotation, comment)
|
75
|
+
end
|
65
76
|
end
|
66
77
|
|
67
78
|
rule(:variation_list) do |r|
|
68
|
-
|
69
|
-
|
79
|
+
r[:variation, :variation_list].as do |variation, sequence|
|
80
|
+
sequence << variation
|
81
|
+
end
|
82
|
+
r[:variation].as { |v| [v] }
|
70
83
|
end
|
71
|
-
|
84
|
+
|
72
85
|
rule(:variation) do |r|
|
73
|
-
r[
|
86
|
+
r['(', :element_sequence, ')'].as { |_, sequence, _| sequence }
|
74
87
|
end
|
75
88
|
|
76
|
-
# rule(:variation_sequence) do |r|
|
77
|
-
# r[:element, :variation_sequence]
|
78
|
-
# r[].as { [] }
|
79
|
-
# end
|
80
|
-
|
81
|
-
#rule(:recursive_variation) do |r|
|
82
|
-
#r["(", :element_sequence, ")"]
|
83
|
-
#end
|
84
|
-
|
85
89
|
rule(
|
86
|
-
:
|
90
|
+
string: /
|
87
91
|
" # beginning of string
|
88
92
|
(
|
89
93
|
[[:print:]&&[^\\"]] | # printing characters except quote and backslash
|
@@ -91,25 +95,28 @@ module PGN
|
|
91
95
|
\\" # escaped quotation marks
|
92
96
|
)* # zero or more of the above
|
93
97
|
" # end of string
|
94
|
-
|
98
|
+
/x
|
95
99
|
)
|
96
100
|
|
97
101
|
rule(
|
98
|
-
:
|
99
|
-
\{ # beginning of comment
|
102
|
+
comment: /
|
100
103
|
(
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
104
|
+
\{ # beginning of comment
|
105
|
+
(
|
106
|
+
[[:print:]&&[^\\\{\}]] | # printing characters except brace and backslash
|
107
|
+
\n |
|
108
|
+
\\\\ | # escaped backslashes
|
109
|
+
\\\{|\\\} | # escaped braces
|
110
|
+
\n | # newlines
|
111
|
+
\g<1> # recursive
|
112
|
+
)* # zero or more of the above
|
113
|
+
\} # end of comment
|
114
|
+
)
|
115
|
+
/x
|
109
116
|
)
|
110
117
|
|
111
118
|
rule(
|
112
|
-
:
|
119
|
+
game_termination: %r{
|
113
120
|
1-0 | # white wins
|
114
121
|
0-1 | # black wins
|
115
122
|
1\/2-1\/2 | # draw
|
@@ -118,14 +125,15 @@ module PGN
|
|
118
125
|
)
|
119
126
|
|
120
127
|
rule(
|
121
|
-
:
|
128
|
+
move_number_indication: /
|
122
129
|
[[:digit:]]+\.* # one or more digits followed by zero or more periods
|
123
|
-
|
130
|
+
/x
|
124
131
|
)
|
125
132
|
|
126
133
|
rule(
|
127
|
-
:
|
134
|
+
san_move: %r{
|
128
135
|
(
|
136
|
+
-- | # "don't care" move (used in variations)
|
129
137
|
[O0](-[O0]){1,2} | # castling (O-O, O-O-O)
|
130
138
|
[a-h][1-8] | # pawn moves (e4, d7)
|
131
139
|
[BKNQR][a-h1-8]?x?[a-h][1-8] | # major piece moves w/ optional specifier
|
@@ -144,16 +152,16 @@ module PGN
|
|
144
152
|
)
|
145
153
|
|
146
154
|
rule(
|
147
|
-
:
|
155
|
+
tag_name: /
|
148
156
|
[A-Za-z0-9_]+ # letters, digits and underscores only
|
149
|
-
|
157
|
+
/x
|
150
158
|
)
|
151
159
|
|
152
160
|
rule(
|
153
|
-
:
|
161
|
+
numeric_annotation_glyph: /
|
154
162
|
\$\d+ | # dollar sign followed by an integer from 0 to 255
|
155
163
|
[\?!][\?!]? # support the most used annotations directly
|
156
|
-
|
164
|
+
/x
|
157
165
|
)
|
158
166
|
end
|
159
167
|
end
|
data/lib/pgn/version.rb
CHANGED
data/spec/parser_spec.rb
CHANGED
@@ -1,84 +1,84 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe PGN do
|
4
|
-
describe
|
5
|
-
it
|
6
|
-
games = PGN.parse(File.read(
|
4
|
+
describe '.parse' do
|
5
|
+
it 'should return a list of games' do
|
6
|
+
games = PGN.parse(File.read('./examples/immortal_game.pgn'))
|
7
7
|
games.length.should == 1
|
8
8
|
game = games.first
|
9
|
-
game.result.should ==
|
10
|
-
game.tags[
|
11
|
-
game.moves.last.should ==
|
9
|
+
game.result.should == '1-0'
|
10
|
+
game.tags['White'].should == 'Adolf Anderssen'
|
11
|
+
game.moves.last.should == 'Be7#'
|
12
12
|
end
|
13
|
-
end
|
14
13
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
game.result.should == "*"
|
22
|
-
game.moves.last.should == "O-O-O"
|
23
|
-
end
|
14
|
+
it 'should handle alternate castling notation' do
|
15
|
+
games = PGN.parse(File.read('./spec/pgn_files/alternate_castling.pgn'))
|
16
|
+
game = games.first
|
17
|
+
game.tags['White'].should == 'Somebody'
|
18
|
+
game.result.should == '*'
|
19
|
+
game.moves.last.should == 'O-O-O'
|
24
20
|
end
|
25
|
-
end
|
26
21
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
game.result.should == "0-1"
|
34
|
-
game.moves.last.should == "Qh4#"
|
35
|
-
end
|
22
|
+
it 'should handle annotations' do
|
23
|
+
games = PGN.parse(File.read('./spec/pgn_files/annotations.pgn'))
|
24
|
+
games.each do |game|
|
25
|
+
game.tags['White'].should == 'Fool'
|
26
|
+
game.result.should == '0-1'
|
27
|
+
game.moves.last.should == 'Qh4#'
|
36
28
|
end
|
37
29
|
end
|
38
30
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
31
|
+
it 'should handle comments' do
|
32
|
+
games = PGN.parse(File.read('./spec/pgn_files/comments.pgn'))
|
33
|
+
game = games.first
|
34
|
+
game.tags['White'].should == 'Scholar'
|
35
|
+
game.result.should == '1-0'
|
36
|
+
game.moves.last.should == 'Qxf7#'
|
37
|
+
end
|
47
38
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
end
|
39
|
+
it 'should handle multiline comments' do
|
40
|
+
games = PGN.parse(File.read('./spec/pgn_files/multiline_comments.pgn'))
|
41
|
+
game = games.first
|
42
|
+
game.tags['White'].should == 'Scholar'
|
43
|
+
game.result.should == '1-0'
|
44
|
+
game.moves.last.should == 'Qxf7#'
|
55
45
|
end
|
56
46
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
game.result.should == "*"
|
63
|
-
game.moves.last.should == "Nf6"
|
64
|
-
end
|
47
|
+
it 'should handle nested comments' do
|
48
|
+
games = PGN.parse(File.read('./spec/pgn_files/nested_comments.pgn'))
|
49
|
+
game = games.first
|
50
|
+
game.result.should == '*'
|
51
|
+
game.moves.last.should == 'Nf6'
|
65
52
|
end
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
53
|
+
|
54
|
+
it 'should handle variations' do
|
55
|
+
games = PGN.parse(File.read('./spec/pgn_files/variations.pgn'))
|
56
|
+
game = games.first
|
57
|
+
game.tags['Black'].should == 'Petrov'
|
58
|
+
game.result.should == '*'
|
59
|
+
game.moves.last.should == 'Nf6'
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should handle empty variation moves' do
|
63
|
+
games = PGN.parse(File.read('./spec/pgn_files/empty_variation_move.pgn'))
|
64
|
+
game = games.first
|
65
|
+
game.result.should == '*'
|
66
|
+
game.moves.last.should == 'Ng5'
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should handle complex files' do
|
70
|
+
games = PGN.parse(File.read('./spec/pgn_files/test.pgn'))
|
71
|
+
game = games.first
|
72
|
+
game.tags['Black'].should == 'Gelfand, Boris'
|
73
|
+
game.result.should == '1-0'
|
74
|
+
game.moves[13].should == 'Nfd7'
|
75
|
+
game.moves[34].should == 'f3'
|
76
|
+
game.moves[35].annotation.should == '$6'
|
77
|
+
game.moves[35].comment.should == "{Gelfand\ndecide tomar medidas.}"
|
78
|
+
game.moves[35].variations.size.should == 1
|
79
|
+
variation = game.moves[35].variations[0]
|
80
|
+
variation.size.should == 2
|
81
|
+
variation[0].should == 'Nxf3'
|
82
82
|
end
|
83
83
|
end
|
84
84
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
[White "Somebody"]
|
2
|
+
[Black "Somebody Else"]
|
3
|
+
|
4
|
+
1. d4 e6 2. c4 d5 3. Nc3 c6 4. Nf3 Nf6 5. Bg5 Nbd7 6. e3 Qa5 7. a3 (7. cxd5
|
5
|
+
Nxd5 8. Rc1 {Analyzer's primary variation: 8... Bb4 9. Qd2 e5 10. e4 Nxc3 11.
|
6
|
+
bxc3 Ba3 12. Rb1 h6 13. Be3 O-O 14. Bc4 exd4 15. cxd4 Qxd2+ 16. Nxd2 a5 17. O-O
|
7
|
+
b5 18. Be2 Rd8 19. d5 cxd5 20. exd5 Nc5 21. Rxb5 Rxd5 {+0.30/21} }) 7... Ne4 8.
|
8
|
+
Rc1 Nxg5 9. Nxg5 dxc4 10. Bxc4 Qxg5 11. O-O Nf6 12. Qf3 Qg4 13. Qxg4 Nxg4 14.
|
9
|
+
Ne4 Be7 15. b4 O-O 16. Rce1 Nf6 17. Ng5 ({Better is} 17. Nxf6+ gxf6 {-4.08/31}
|
10
|
+
(17... Bxf6) (17... gxf6)) (17. Nxf6+) 17... h6 18. Nf3 Ne4 ({Treatening} 18...
|
11
|
+
-- 19. Ra1 b5 {-4.05/31}) 19. Bd3 Ng5 *
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pgn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stacey Touset
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-02-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: whittle
|
@@ -97,7 +97,9 @@ files:
|
|
97
97
|
- spec/pgn_files/alternate_castling.pgn
|
98
98
|
- spec/pgn_files/annotations.pgn
|
99
99
|
- spec/pgn_files/comments.pgn
|
100
|
+
- spec/pgn_files/empty_variation_move.pgn
|
100
101
|
- spec/pgn_files/multiline_comments.pgn
|
102
|
+
- spec/pgn_files/nested_comments.pgn
|
101
103
|
- spec/pgn_files/test.pgn
|
102
104
|
- spec/pgn_files/variations.pgn
|
103
105
|
- spec/position_spec.rb
|
@@ -133,7 +135,9 @@ test_files:
|
|
133
135
|
- spec/pgn_files/alternate_castling.pgn
|
134
136
|
- spec/pgn_files/annotations.pgn
|
135
137
|
- spec/pgn_files/comments.pgn
|
138
|
+
- spec/pgn_files/empty_variation_move.pgn
|
136
139
|
- spec/pgn_files/multiline_comments.pgn
|
140
|
+
- spec/pgn_files/nested_comments.pgn
|
137
141
|
- spec/pgn_files/test.pgn
|
138
142
|
- spec/pgn_files/variations.pgn
|
139
143
|
- spec/position_spec.rb
|