SgfParser 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,29 +1,36 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
- describe "SgfParser::Tree" do
3
+ describe "SGF::Tree" do
4
4
 
5
+ before :each do
6
+ @tree = get_tree_from 'spec/data/ff4_ex.sgf'
7
+ end
5
8
 
6
- it "should load a file properly" do
7
- tree = SGF::Parser.new('spec/data/ff4_ex.sgf').parse
8
- tree.class.should == SGF::Tree
9
- tree.root.children.size.should == 2
10
- tree.root.children[0].children.size.should == 5
9
+ it "should have two gametrees" do
10
+ @tree.games.size.should == 2
11
11
  end
12
12
 
13
- it "should save a simple tree properly" do
14
- tree = SGF::Parser.new('spec/data/simple.sgf').parse
15
- new_file = 'spec/data/simple_saved.sgf'
16
- tree.save :filename => new_file
17
- tree2 = SGF::Parser.new(new_file).parse
18
- tree.should == tree2
13
+ it "should have a decent inspect" do
14
+ inspect = @tree.inspect
15
+ inspect.should match /SGF::Tree/
16
+ inspect.should match /#{@tree.object_id}/
17
+ inspect.should match /2 Games/
18
+ inspect.should match /62 Nodes/
19
19
  end
20
20
 
21
- it "should save the sample SGF properly" do
22
- tree = SGF::Parser.new('spec/data/ff4_ex.sgf').parse
23
- new_file = 'spec/data/ff4_ex_saved.sgf'
24
- tree.save :filename => new_file
25
- tree2 = SGF::Parser.new(new_file).parse
26
- tree2.should == tree
21
+ it "should use preorder traversal for each" do
22
+ @tree = get_tree_from 'spec/data/example1.sgf'
23
+ array = []
24
+ @tree.each {|node| array << node}
25
+ array[0].c.should == "root"
26
+ array[1].c.should == "a"
27
+ array[2].c.should == "b"
28
+ end
29
+
30
+ it "should load a file properly" do
31
+ @tree.class.should == SGF::Tree
32
+ @tree.root.children.size.should == 2
33
+ @tree.root.children[0].children.size.should == 5
27
34
  end
28
35
 
29
36
  end
@@ -0,0 +1,97 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "SGF::Writer" do
4
+
5
+ TEMP_FILE = 'spec/data/temp.sgf'
6
+
7
+ after :each do
8
+ FileUtils.rm_f TEMP_FILE
9
+ end
10
+
11
+ it "should save a simple tree properly" do
12
+ sgf = File.read('spec/data/simple.sgf')
13
+ parse_save_load_and_compare_to_saved sgf
14
+ end
15
+
16
+ it "should save an SGF with two gametrees properly" do
17
+ parse_save_load_and_compare_to_saved "(;FF[4])(;FF[4])"
18
+ end
19
+
20
+ it "should save the one-line simplified sample" do
21
+ parse_save_load_and_compare_to_saved ONE_LINE_SIMPLE_SAMPLE_SGF
22
+ end
23
+
24
+ it "should save the simplified SGF properly" do
25
+ parse_save_load_and_compare_to_saved SIMPLIFIED_SAMPLE_SGF
26
+ end
27
+
28
+ it "should save the sample SGF properly" do
29
+ sgf = File.read('spec/data/ff4_ex.sgf')
30
+ parse_save_load_and_compare_to_saved sgf
31
+ end
32
+
33
+ it "should indent a simple SGF nicely" do
34
+ sgf = save_to_temp_file_and_read '(;FF[4])'
35
+ sgf.should == "\n(\n ;FF[4]\n)"
36
+ end
37
+
38
+ it "should indent a one-node SGF with two properties" do
39
+ sgf = save_to_temp_file_and_read '(;FF[4]PW[Cho Chikun])'
40
+ sgf.should == "\n(\n ;FF[4]\n PW[Cho Chikun]\n)"
41
+ end
42
+
43
+ it "should indent two nodes on same column" do
44
+ sgf = save_to_temp_file_and_read '(;FF[4];PB[qq])'
45
+ sgf.should == "\n(\n ;FF[4]\n ;PB[qq]\n)"
46
+ end
47
+
48
+ it "should indent branches further" do
49
+ string = '(;FF[4](;PB[qq])(;PB[qa]))'
50
+ sgf = save_to_temp_file_and_read string
51
+ expected = %Q{
52
+ (
53
+ ;FF[4]
54
+ (
55
+ ;PB[qq]
56
+ )
57
+ (
58
+ ;PB[qa]
59
+ )
60
+ )}
61
+ sgf.should == expected
62
+ end
63
+
64
+ it "should indent two gametrees" do
65
+ string = '(;FF[4];PB[qq])(;FF[4];PB[dd])'
66
+ sgf = save_to_temp_file_and_read string
67
+ expected = %Q{
68
+ (
69
+ ;FF[4]
70
+ ;PB[qq]
71
+ )
72
+ (
73
+ ;FF[4]
74
+ ;PB[dd]
75
+ )}
76
+ sgf.should == expected
77
+ end
78
+
79
+ private
80
+
81
+ def parse_save_load_and_compare_to_saved string
82
+ parser =SGF::Parser.new
83
+ tree = parser.parse string
84
+ tree.save TEMP_FILE
85
+ tree2 = get_tree_from TEMP_FILE
86
+ tree2.should == tree
87
+ end
88
+
89
+
90
+ def save_to_temp_file_and_read sgf_string
91
+ tree = SGF::Parser.new.parse sgf_string
92
+ tree.save TEMP_FILE
93
+ sgf = File.read TEMP_FILE
94
+ sgf
95
+ end
96
+
97
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: SgfParser
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,12 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-08-01 00:00:00.000000000 -04:00
13
- default_executable:
12
+ date: 2011-08-01 00:00:00.000000000 Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
- name: jeweler
17
- requirement: &76820790 !ruby/object:Gem::Requirement
15
+ name: rspec
16
+ requirement: &84169490 !ruby/object:Gem::Requirement
18
17
  none: false
19
18
  requirements:
20
19
  - - ! '>='
@@ -22,10 +21,10 @@ dependencies:
22
21
  version: '0'
23
22
  type: :development
24
23
  prerelease: false
25
- version_requirements: *76820790
24
+ version_requirements: *84169490
26
25
  - !ruby/object:Gem::Dependency
27
26
  name: rcov
28
- requirement: &76820540 !ruby/object:Gem::Requirement
27
+ requirement: &84169230 !ruby/object:Gem::Requirement
29
28
  none: false
30
29
  requirements:
31
30
  - - ! '>='
@@ -33,10 +32,10 @@ dependencies:
33
32
  version: '0'
34
33
  type: :development
35
34
  prerelease: false
36
- version_requirements: *76820540
35
+ version_requirements: *84169230
37
36
  - !ruby/object:Gem::Dependency
38
- name: rdoc
39
- requirement: &76820300 !ruby/object:Gem::Requirement
37
+ name: rake
38
+ requirement: &84168780 !ruby/object:Gem::Requirement
40
39
  none: false
41
40
  requirements:
42
41
  - - ! '>='
@@ -44,28 +43,31 @@ dependencies:
44
43
  version: '0'
45
44
  type: :development
46
45
  prerelease: false
47
- version_requirements: *76820300
46
+ version_requirements: *84168780
48
47
  - !ruby/object:Gem::Dependency
49
- name: rspec
50
- requirement: &76820030 !ruby/object:Gem::Requirement
48
+ name: rdoc
49
+ requirement: &84168450 !ruby/object:Gem::Requirement
51
50
  none: false
52
51
  requirements:
53
52
  - - ! '>='
54
53
  - !ruby/object:Gem::Version
55
- version: 1.2.9
54
+ version: '0'
56
55
  type: :development
57
56
  prerelease: false
58
- version_requirements: *76820030
59
- description: SGFParser is a library that parses and saves SGF (Smart Game Format)
60
- files.
61
- email: aldric@trevoke.net
62
- executables: []
57
+ version_requirements: *84168450
58
+ description: SGF::Parser does standard stream parsing of the SGF file, instead of
59
+ using an AG or some other auto-generated newfangled parser stuff. It is therefore
60
+ faster to use, and hopefully will also be easier to use. Feedback helps :)
61
+ email: trevoke@gmail.com
62
+ executables:
63
+ - sgf_indent.rb
63
64
  extensions: []
64
65
  extra_rdoc_files:
65
66
  - LICENSE
66
67
  - README.rdoc
67
68
  files:
68
69
  - .document
70
+ - .gitignore
69
71
  - .rspec
70
72
  - .rvmrc
71
73
  - Gemfile
@@ -74,24 +76,27 @@ files:
74
76
  - README.rdoc
75
77
  - Rakefile
76
78
  - SgfParser.gemspec
77
- - VERSION
79
+ - bin/sgf_indent.rb
80
+ - examples/simple_iteration_of_games_in_a_directory.rb
78
81
  - lib/sgf.rb
79
- - lib/sgf/indenter.rb
82
+ - lib/sgf/error.rb
83
+ - lib/sgf/game.rb
80
84
  - lib/sgf/node.rb
81
85
  - lib/sgf/parser.rb
82
86
  - lib/sgf/properties.rb
83
87
  - lib/sgf/tree.rb
84
- - sample_usage/parsing_files.rb
88
+ - lib/sgf/version.rb
89
+ - lib/sgf/writer.rb
90
+ - spec/data/example1.sgf
85
91
  - spec/data/ff4_ex.sgf
86
- - spec/data/ff4_ex_saved.sgf
87
92
  - spec/data/redrose-tartrate.sgf
88
93
  - spec/data/simple.sgf
89
- - spec/data/simple_saved.sgf
94
+ - spec/game_spec.rb
90
95
  - spec/node_spec.rb
91
96
  - spec/parser_spec.rb
92
97
  - spec/spec_helper.rb
93
98
  - spec/tree_spec.rb
94
- has_rdoc: true
99
+ - spec/writer_spec.rb
95
100
  homepage: http://github.com/Trevoke/SGFParser
96
101
  licenses: []
97
102
  post_install_message:
@@ -112,8 +117,18 @@ required_rubygems_version: !ruby/object:Gem::Requirement
112
117
  version: '0'
113
118
  requirements: []
114
119
  rubyforge_project:
115
- rubygems_version: 1.6.2
120
+ rubygems_version: 1.8.10
116
121
  signing_key:
117
122
  specification_version: 3
118
- summary: A library for working with SGF files.
119
- test_files: []
123
+ summary: A library that parses and saves SGF (Smart Game Format) files.
124
+ test_files:
125
+ - spec/data/example1.sgf
126
+ - spec/data/ff4_ex.sgf
127
+ - spec/data/redrose-tartrate.sgf
128
+ - spec/data/simple.sgf
129
+ - spec/game_spec.rb
130
+ - spec/node_spec.rb
131
+ - spec/parser_spec.rb
132
+ - spec/spec_helper.rb
133
+ - spec/tree_spec.rb
134
+ - spec/writer_spec.rb
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 1.0.0
@@ -1,108 +0,0 @@
1
- require 'stringio'
2
-
3
- module SGF
4
-
5
- # This indents an SGF file to make it more readable. It outputs to the screen
6
- # by default, but can be given a file as output.
7
- # Usage: SgfParser::Indenter.new infile, outfile
8
- class Indenter
9
-
10
- def initialize file, out=$stdout
11
- @stream = load_file_to_stream(file)
12
- @new_string = ""
13
- @indentation = 0
14
- @out = (out == $stdout) ? $stdout : File.open(out, 'w')
15
- parse
16
- end
17
-
18
- def next_character
19
- !@stream.eof? && @stream.sysread(1)
20
- end
21
-
22
- def parse
23
- while char = next_character
24
- case char
25
- when '(' then open_branch
26
- when ')' then close_branch
27
- when ';' then new_node
28
- when '[' then add_property
29
- else add_identity(char)
30
- end
31
- end
32
-
33
- @out << @new_string
34
- @out.close unless @out == $stdout
35
- #if out == $stdout
36
- # $stdout << @new_string
37
- #else
38
- # File.open(out, 'w') { |file| file << @new_string }
39
- #end
40
- end
41
-
42
- def open_branch
43
- next_line
44
- @indentation += 2
45
- @new_string << " " * @indentation
46
- @new_string << "("
47
- end
48
-
49
- def close_branch
50
- @new_string << ")"
51
- next_line
52
- @indentation -= 2
53
- @indentation = 0 if @indentation < 0
54
- @new_string << " " * @indentation
55
- end
56
-
57
- def new_node
58
- next_line
59
- @new_string << " " * @indentation
60
- @new_string << ";"
61
- end
62
-
63
- def next_line
64
- @new_string << "\n"
65
- end
66
-
67
- #TODO Fix it more. Add _ONE_ set of indentation if there are newlines,
68
- #TODO Not one set for every newline.
69
- def add_property
70
- buffer = "["
71
- while true
72
- next_bit = @stream.sysread(1)
73
- next_bit << @stream.sysread(1) if next_bit == "\\"
74
- buffer << next_bit
75
- buffer << " " * @indentation if next_bit == "\n"
76
- break if next_bit == "]"
77
- end
78
- buffer << "\n"
79
- buffer << " " * @indentation
80
- @new_string << buffer
81
- end
82
-
83
- def add_identity(char)
84
- @new_string << char unless char == "\n"
85
- end
86
-
87
- private
88
-
89
- def load_file_to_stream(file)
90
- sgf = ""
91
- File.open(file) { |f| sgf = f.read }
92
- clean_string(sgf)
93
- return StringIO.new(sgf, 'r')
94
- end
95
-
96
- def clean_string(sgf)
97
- sgf.gsub! "\\\\n\\\\r", ""
98
- sgf.gsub! "\\\\r\\\\n", ""
99
- sgf.gsub! "\\\\r", ""
100
- sgf.gsub! "\\\\n", ""
101
- end
102
-
103
- end
104
- end
105
-
106
-
107
-
108
-
@@ -1,19 +0,0 @@
1
- # With this code, we will display info on all files within a directory:
2
- # "Black_player-White_player.sgf"
3
-
4
- require '../lib/sgf_parser'
5
-
6
-
7
- Dir.glob('../data/*').each do |file|
8
- next if File.directory? file # Let's not touch directories.
9
- next if File.extname(file) != ".sgf" # If it's not an SGF file, let's not touch it.
10
- sgf = SgfParser::Tree.new :filename => file
11
- # The "root" is an empty node, always, so we can support SGF collections painlessly:
12
- # Whole trees simply become branches from the root.
13
-
14
- black = sgf.root.children[0].PB rescue "Black" # Alright, so this isn't particularly elegant.
15
- white = sgf.root.children[0].PW rescue "White" # It's a work in progress !
16
-
17
- puts "#{black}-#{white}.sgf"
18
-
19
- end
@@ -1,45 +0,0 @@
1
- (;FF[4]AP[Primiview:3.1]GM[1]SZ[19]GN[Gametree 1: properties]US[Arno Hollosi](;B[pd]N[Moves, comments, annotations]C[Nodename set to: "Moves, comments, annotations"];W[dp]GW[1]C[Marked as "Good for White"];B[pp]GB[2]C[Marked as "Very good for Black"];W[dc]GW[2]C[Marked as "Very good for White"];B[pj]DM[1]C[Marked as "Even position"];W[ci]UC[1]C[Marked as "Unclear position"];B[jd]TE[1]C[Marked as "Tesuji" or "Good move"];W[jp]BM[2]C[Marked as "Very bad move"];B[gd]DO[]C[Marked as "Doubtful move"];W[de]IT[]C[Marked as "Interesting move"];B[jj];C[White "Pass" move]W[];)(;AB[dd][de][df][dg][do:gq] AW[jd][je][jf][jg][kn:lq][pn:pq]N[Setup]C[Black & white stones at the top are added as single stones.
2
-
3
- Black & white stones at the bottom are added using compressed point lists.];AE[ep][fp][kn][lo][lq][pn:pq]C[AddEmpty
4
-
5
- Black stones & stones of left white group are erased in FF[3\] way.
6
-
7
- White stones at bottom right were erased using compressed point list.];AB[pd]AW[pp]PL[B]C[Added two stones.
8
-
9
- Node marked with "Black to play".];)(;AB[dd][de][df][dg][dh][di][dj][nj][ni][nh][nf][ne][nd][ij][ii][ih][hq][gq][fq][eq][dr][ds][dq][dp][cp][bp][ap][iq][ir][is][bo][bn][an][ms][mr]AW[pd][pe][pf][pg][ph][pi][pj][fd][fe][ff][fh][fi][fj][kh][ki][kj][os][or][oq][op][pp][qp][rp][sp][ro][rn][sn][nq][mq][lq][kq][kr][ks][fs][gs][gr][er]N[Markup]C[Position set up without compressed point lists.];TR[dd][de][df][ed][ee][ef][fd:ff] MA[dh][di][dj][ej][ei][eh][fh:fj] CR[nd][ne][nf][od][oe][of][pd:pf] SQ[nh][ni][nj][oh][oi][oj][ph:pj] SL[ih][ii][ij][jj][ji][jh][kh:kj] TW[pq:ss][so][lr:ns] TB[aq:cs][er:hs][ao]C[Markup at top partially using compressed point lists (for markup on white stones); listed clockwise, starting at upper left:
10
- - TR (triangle)
11
- - CR (circle)
12
- - SQ (square)
13
- - SL (selected points)
14
- - MA ('X')
15
-
16
- Markup at bottom: black & white territory (using compressed point lists)];LB[dc:1][fc:2][nc:3][pc:4][dj:a][fj:b][nj:c][pj:d][gs:ABCDEFGH][gr:ABCDEFG][gq:ABCDEF][gp:ABCDE][go:ABCD][gn:ABC][gm:AB][mm:12][mn:123][mo:1234][mp:12345][mq:123456][mr:1234567][ms:12345678]C[Label (LB property)
17
-
18
- Top: 8 single char labels (1-4, a-d)
19
-
20
- Bottom: Labels up to 8 char length.];)(;B[qd]N[Style & text type]C[There are hard linebreaks & soft linebreaks.
21
- Soft linebreaks are linebreaks preceeded by '\\' like this one >o\
22
- k<. Hard line breaks are all other linebreaks.
23
- Soft linebreaks are converted to >nothing<, i.e. removed.
24
-
25
- Note that linebreaks are coded differently on different systems.
26
-
27
- Examples (>ok< shouldn't be split):
28
-
29
- linebreak 1 "": >o\
30
- k<
31
- linebreak 2 "": >o\
32
-
33
- linebreak 3 "": >o\
34
- k<
35
- linebreak 4 "": >o\
36
- Black stones left (in this byo-yomi period): 10];W[qq]WL[200]OW[2]C[White time left: 200 sec
37
- White stones left: 2];B[sr]BL[87.00]OB[9]C[Black time left: 87 sec
38
- Black stones left: 9];W[qs]WL[13.20]OW[1]C[White time left: 13.2 sec
39
- White stones left: 1];B[rs]C[One white stone at s2 captured];W[ps];B[pr];W[or]MN[2]C[Set move number to 2];B[os]C[Two white stones captured
40
- (at q1 & r1)];MN[112]W[pq]C[Set move number to 112];B[sq];W[rp];B[ps];W[ns];B[ss];W[nr];B[rr];W[sp];);FF[4]AP[Primiview:3.1]GM[1]SZ[19]C[Gametree 2: game-info
41
-
42
- Game-info properties are usually stored in the root node.
43
- If games are merged into a single game-tree, they are stored in the node\
44
- where the game first becomes distinguishable from all other games in\
45
- the tree.];B[pd](;)(;)(;W[ep];B[pp](;)(;))