SgfParser 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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](;)(;))