SgfParser 0.8.0 → 0.9.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.
data/.document CHANGED
@@ -1,5 +1,5 @@
1
- README.rdoc
2
- lib/**/*.rb
3
- bin/*
4
- features/**/*.feature
5
- LICENSE
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore CHANGED
@@ -1,25 +1,25 @@
1
- ## MAC OS
2
- .DS_Store
3
-
4
- ## TEXTMATE
5
- *.tmproj
6
- tmtags
7
-
8
- ## EMACS
9
- *~
10
- \#*
11
- .\#*
12
-
13
- ## VIM
14
- *.swp
15
-
16
- ## PROJECT::GENERAL
17
- coverage
18
- rdoc
19
- pkg
20
-
21
- ## PROJECT::SPECIFIC
22
-
23
-
24
- ## Rubymine
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
22
+
23
+
24
+ ## Rubymine
25
25
  .idea/*
@@ -1,24 +1,34 @@
1
+ =INFORMATION
2
+ Author: Aldric Giacomoni
3
+
4
+ Email : aldric~at~trevoke.net (feedback very welcome!)
5
+
1
6
  SGF: all formats (but untested with FF < 4)
2
- Ruby: >1.8.7 (may work with 1.8.6)
3
7
 
8
+ Ruby: >=1.8.7 (may work with 1.8.6)
9
+
10
+ =QUICK HOWTO
4
11
  Example:
5
- require 'sgf_parser'
6
- tree = SgfParser::Tree.new :filename => File
7
- tree = SgfParser::Tree.new :sgf_string => String
12
+ require 'sgf_parser'
13
+ tree = SgfParser::Tree.new :filename => File
14
+ tree = SgfParser::Tree.new :string => String
8
15
 
9
16
  All trees begin with an empty node ( @root) which allows a simple support of multiple gametrees.
17
+
10
18
  Most games will just care about, say,
11
- tree.root.children[0] which is the first node of the first gametree.
19
+ tree.root.children[0] which is the first node of the first gametree.
12
20
 
13
21
  For any node, one can summon the properties as such:
14
- node.properties # => returns a hash of the properties.
22
+ node.properties # => returns a hash of the properties.
15
23
  A single property can be called, like the comments, for instance, like so:
16
- node.C # => returns the comments for this node.
24
+ node.C # => returns the comments for this node.
17
25
 
18
26
  The library currently uses method_missing to painlessly return the data. I must admit that this is both clever coding and laziness on my part.
19
27
 
20
- The 'SGF Indenter', the purpose of which is to make the actual SGF file more
21
- human readable, is working.
28
+ There is also a SGF Indenter. Its purpose is to make SGF files more readable to humans at a glance.
29
+ require 'sgf_parser/sgfindent' # Done automatically if you require 'sgf_parser'
30
+ sgf = SgfParser::Indenter.new 'some_ugly_file.sgf' # Will output to the console
31
+ sgf = SgfParser::Indenter.new 'some_ugly_file.sgf' 'pretty.sgf' # Sends the result to a new file.
22
32
 
23
33
  ___
24
34
 
@@ -1,66 +1,67 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
- # -*- encoding: utf-8 -*-
5
-
6
- Gem::Specification.new do |s|
7
- s.name = %q{SgfParser}
8
- s.version = "0.8.0"
9
-
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Aldric Giacomoni"]
12
- s.date = %q{2010-01-05}
13
- s.description = %q{SGFParser is a library that parses and saves SGF (Smart Game Format) files.}
14
- s.email = %q{aldric@trevoke.net}
15
- s.extra_rdoc_files = [
16
- "LICENSE",
17
- "README.rdoc"
18
- ]
19
- s.files = [
20
- ".document",
21
- ".gitignore",
22
- "LICENSE",
23
- "README.rdoc",
24
- "Rakefile",
25
- "SgfParser.gemspec",
26
- "VERSION",
27
- "lib/sgf/parser/node.rb",
28
- "lib/sgf/parser/properties.rb",
29
- "lib/sgf/parser/tree.rb",
30
- "lib/sgf/parser/tree_parse.rb",
31
- "lib/sgf/sgfindent.rb",
32
- "lib/sgf_parser.rb",
33
- "sample_sgf/ff4_ex.sgf",
34
- "sample_sgf/ff4_ex_saved.sgf",
35
- "sample_sgf/redrose-tartrate.sgf",
36
- "sample_usage/parsing_files.rb",
37
- "spec/node_spec.rb",
38
- "spec/spec.opts",
39
- "spec/spec_helper.rb",
40
- "spec/tree_spec.rb"
41
- ]
42
- s.homepage = %q{http://github.com/Trevoke/SGFParser}
43
- s.rdoc_options = ["--charset=UTF-8"]
44
- s.require_paths = ["lib"]
45
- s.rubygems_version = %q{1.3.5}
46
- s.summary = %q{A library for working with SGF files.}
47
- s.test_files = [
48
- "spec/node_spec.rb",
49
- "spec/spec_helper.rb",
50
- "spec/tree_spec.rb"
51
- ]
52
-
53
- if s.respond_to? :specification_version then
54
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
55
- s.specification_version = 3
56
-
57
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
58
- s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
59
- else
60
- s.add_dependency(%q<rspec>, [">= 1.2.9"])
61
- end
62
- else
63
- s.add_dependency(%q<rspec>, [">= 1.2.9"])
64
- end
65
- end
66
-
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{SgfParser}
8
+ s.version = "0.9.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Aldric Giacomoni"]
12
+ s.date = %q{2010-04-30}
13
+ s.description = %q{SGFParser is a library that parses and saves SGF (Smart Game Format) files.}
14
+ s.email = %q{aldric@trevoke.net}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "SgfParser.gemspec",
26
+ "VERSION",
27
+ "lib/sgf/parser/node.rb",
28
+ "lib/sgf/parser/properties.rb",
29
+ "lib/sgf/parser/tree.rb",
30
+ "lib/sgf/parser/tree_parse.rb",
31
+ "lib/sgf/sgf_indent.rb",
32
+ "lib/sgf_parser.rb",
33
+ "sample_sgf/ff4_ex.sgf",
34
+ "sample_sgf/redrose-tartrate.sgf",
35
+ "sample_usage/parsing_files.rb",
36
+ "spec/node_spec.rb",
37
+ "spec/spec.opts",
38
+ "spec/spec_helper.rb",
39
+ "spec/tree_spec.rb",
40
+ "tryme.rb"
41
+ ]
42
+ s.homepage = %q{http://github.com/Trevoke/SGFParser}
43
+ s.rdoc_options = ["--charset=UTF-8"]
44
+ s.require_paths = ["lib"]
45
+ s.rubygems_version = %q{1.3.6}
46
+ s.summary = %q{A library for working with SGF files.}
47
+ s.test_files = [
48
+ "spec/node_spec.rb",
49
+ "spec/spec_helper.rb",
50
+ "spec/tree_parser_spec.rb",
51
+ "spec/tree_spec.rb"
52
+ ]
53
+
54
+ if s.respond_to? :specification_version then
55
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
56
+ s.specification_version = 3
57
+
58
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
59
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
60
+ else
61
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
62
+ end
63
+ else
64
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
65
+ end
66
+ end
67
+
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.8.0
1
+ 0.9.0
@@ -23,8 +23,11 @@ module SgfParser
23
23
  # list or an array of node children. Will raise an error if one of the
24
24
  # arguments is not of class Node.
25
25
  def add_children *nodes
26
+ nodes.flatten!
26
27
  raise "Non-node child given!" if nodes.find { |node| node.class != Node }
27
- @children.concat nodes.flatten
28
+ # This node becomes the proud parent of one or more node!
29
+ nodes.each { |node| node.parent = self }
30
+ @children.concat nodes
28
31
  end
29
32
 
30
33
  # Adds one or more properties to the node.
@@ -13,20 +13,19 @@ module SgfParser
13
13
  # options: \n
14
14
  # :filename => filename \n
15
15
  # !!! OR !!! \n
16
- # :sgf_string => string \n
16
+ # :string => string \n
17
17
  def initialize args={}
18
18
  @root = Node.new
19
19
  @sgf = ""
20
- raise ArgumentError, "Both file and string provided" if args[:filename] &&
21
- args[:sgf_string]
22
- if !args[:filename].nil?
20
+ raise ArgumentError, "Both file and string provided" if args[:filename] && args[:string]
21
+ if args[:filename]
23
22
  load_file args[:filename]
24
- elsif !args[:sgf_string].nil?
25
- load_string args[:sgf_string]
23
+ elsif args[:string]
24
+ load_string args[:string]
26
25
  end
27
26
 
28
- end # initialize
29
-
27
+ parse unless @sgf.empty?
28
+ end
30
29
 
31
30
  # Iterates over the tree, node by node, in preorder fashion.
32
31
  # Does not support other types of iteration, but may in the future.
@@ -36,70 +35,65 @@ module SgfParser
36
35
  when :preorder
37
36
  preorder @root, &block
38
37
  end
39
- end # each
38
+ end
40
39
 
41
40
  # Compares a tree to another tree, node by node.
42
- # Nodes must by the same (same properties, parents and children).
41
+ # Nodes must be the same (same properties, parents and children).
43
42
  def == other_tree
44
43
  one = []
45
44
  two = []
46
45
  each { |node| one << node }
47
46
  other_tree.each { |node| two << node }
48
47
  one == two
49
- end # ==
48
+ end
50
49
 
51
50
  # Saves the tree as an SGF file. raises an error if a filename is not given.
52
51
  # tree.save :filename => file_name
53
52
  def save args={}
54
53
  raise ArgumentError, "No file name provided" if args[:filename].nil?
55
54
  # SGF files are trees stored in pre-order traversal.
56
- @sgf_string = "("
55
+ @savable_sgf = "("
57
56
  @root.children.each { |child| write_node child }
58
57
  # write_node @root
59
- @sgf_string << ")"
58
+ @savable_sgf << ")"
60
59
 
61
- File.open(args[:filename], 'w') { |f| f << @sgf_string }
62
- end #save
60
+ File.open(args[:filename], 'w') { |f| f << @savable_sgf }
61
+ end
63
62
 
64
63
  private
65
64
 
66
- # Adds a stringified node to the variable @sgf_string - for saving purposes.
65
+ # Adds a stringified node to the variable @savable_sgf.
67
66
  def write_node node=@root
68
- @sgf_string << ";"
67
+ @savable_sgf << ";"
69
68
  unless node.properties.empty?
70
69
  properties = ""
71
70
  node.properties.each do |k, v|
72
71
  v_escaped = v.gsub("]", "\\]")
73
72
  properties += "#{k.to_s}[#{v_escaped}]"
74
73
  end
75
- @sgf_string << "#{properties}"
74
+ @savable_sgf << "#{properties}"
76
75
  end
77
76
 
78
77
  case node.children.size
79
78
  when 0
80
- @sgf_string << ")"
79
+ @savable_sgf << ")"
81
80
  when 1
82
81
  write_node node.children[0]
83
82
  else
84
83
  node.each_child do |child|
85
- @sgf_string << "("
84
+ @savable_sgf << "("
86
85
  write_node child
87
86
  end
88
87
  end
89
88
  end
90
89
 
91
- # Used to load and parse a string if a string was given.
92
90
  def load_string string
93
91
  @sgf = string
94
- parse unless @sgf.empty?
95
- end # load_string
92
+ end
96
93
 
97
- # Used to load and parse a file if a file was given.
98
94
  def load_file filename
99
- @sgf = ""
100
95
  File.open(filename, 'r') { |f| @sgf = f.read }
101
- parse unless @sgf.empty?
102
- end # load_file
96
+ end
103
97
 
104
98
  # Traverse the tree in preorder fashion, starting with the @root node if
105
99
  # no node is given, and activating the passed block on each.
@@ -1,111 +1,97 @@
1
+ require 'stringio'
2
+
1
3
  module SgfParser
2
4
  class Tree
3
5
 
4
6
  private
5
7
 
6
- # This function parses a SGF string into a linked list, or tree.
8
+ # Creates a tree (truly, a linked list) from @sgf.
7
9
  def parse
10
+ while char = next_character
11
+ case char
12
+ when '(' then store_branch
13
+ when ')' then fetch_branch
14
+ when ';' then store_node_and_create_new_node
15
+ when '[' then get_and_store_property
16
+ else store_character(char)
17
+ end
18
+ end
19
+ end
20
+
21
+ def next_character
22
+ character_available? && @stream.sysread(1)
23
+ end
24
+
25
+ def character_available?
26
+ @stream ||= StringIO.new clean_string, 'r'
27
+ !@stream.eof?
28
+ end
29
+
30
+ def clean_string
8
31
  @sgf.gsub! "\\\\n\\\\r", ""
9
32
  @sgf.gsub! "\\\\r\\\\n", ""
10
33
  @sgf.gsub! "\\\\r", ""
11
34
  @sgf.gsub! "\\\\n", ""
12
- #@sgf.gsub! "\n", ""
13
- branches = [] # This stores where new branches are open
14
- current_node = @root # Let's start at the beginning, shall we?
15
- identprop = false # We are not in the middle of an identprop value.
16
- # An identprop is an identity property - a value.
17
- content = Hash.new # Hash holding all the properties
18
- param, property = "", "" # Variables holding the idents and props
19
- end_of_a_series = false # To keep track of params with multiple properties
20
-
21
- sgf_array = @sgf.split(//)
22
- iterator = 0
23
- array_length = sgf_array.size
24
-
25
- while iterator < array_length
26
- char = sgf_array[iterator]
27
- case char
28
- =begin
29
- Basically, if we're inside an identprop, it's a normal character (or a closing
30
- character).
31
- If we're not, it's either a property or a special SGF character so we have
32
- to handle that properly.
33
- =end
34
- when '(' # Opening a new branch
35
- if identprop
36
- property << char
37
- else
38
- branches.unshift current_node
39
- end
40
- when ')' # Closing a branch
41
- if identprop
42
- property << char
43
- else
44
- current_node = branches.shift
45
- param, property = "", ""
46
- content.clear
47
- end
48
- when ';' # Opening a new node
49
- if identprop
50
- property << char
51
- else
52
- # Make the current node the old node, make new node, store data
53
- parent = current_node
54
- current_node = Node.new :parent => parent
55
- parent.add_properties content
56
- parent.add_children current_node
57
- param, property = "", ""
58
- content.clear
59
- end
60
- when '[' # Open identprop?
61
- if identprop
62
- property << char
63
- else # If we're not inside an identprop, then now we are.
64
- identprop = true
65
- end_of_a_series = false
66
- end
67
- when ']' # Close identprop
68
- # Cleverness : checking for this first, then for the backslash.
69
- # This means that if we encounter this, it must be closing an identprop.
70
- # Because the "\\" code handles the logic to see if we're inside an identprop,
71
- # And for skipping the bracket if necessary.
72
- end_of_a_series = true # Maybe end of a series of identprop.
73
- identprop = false # That's our cue to close an identprop.
74
- content[param] = property
75
- property = ""
76
- when "\\"
77
- # If we're inside a comment, then maybe we're about to escape a ].
78
- # This is the whole reason we need this ugly loop.
79
- if identprop
80
- # If the next character is a closing bracket, then it's just
81
- # escaped and the identprop continues.
82
- if sgf_array[iterator + 1] == "]"
83
- property << "]"
84
- # On the next pass through, we will skip that bracket.
85
- iterator += 1
86
- else
87
- property << "\\"
88
- end
89
- else
90
- #This should never happen - a backslash outside an identprop ?!
91
- #But let's not have it be told that I'm not prepared.
92
- param << "\\"
93
- end
94
- when "\n"
95
- property << "\n" if identprop
96
-
97
- else
98
- # Well, I guess it's "just" a character after all.
99
- if end_of_a_series
100
- end_of_a_series = false
101
- param, property = "", ""
102
- end
103
- identprop ? (property << char) : param << char
104
- end
105
- iterator += 1
35
+ @sgf
36
+ end
37
+
38
+ def store_branch
39
+ @branches ||= []
40
+ @branches.unshift @current_node
41
+ end
42
+
43
+ def current_node
44
+ @current_node ||= @root
45
+ end
46
+
47
+ def fetch_branch
48
+ @current_node = @branches.shift
49
+ clear_temporary_data
50
+ end
51
+
52
+ def store_node_and_create_new_node
53
+ parent = current_node
54
+ @current_node = Node.new :parent => parent
55
+ parent.add_properties content
56
+ parent.add_children @current_node
57
+ clear_temporary_data
58
+ end
59
+
60
+ def get_and_store_property
61
+ @content[@identity] ||= ""
62
+ @content[@identity] << get_property
63
+ @identity = ""
64
+ end
65
+
66
+ def get_property
67
+ buffer = ""
68
+ while true
69
+ next_bit = @stream.sysread(1)
70
+ break if next_bit == "]"
71
+ next_bit << @stream.sysread(1) if next_bit == "\\"
72
+ next_bit = "]" if next_bit == "\\]"
73
+ buffer << next_bit
106
74
  end
75
+ buffer
76
+ end
107
77
 
78
+ def store_character(char)
79
+ @identity << char unless char == "\n"
80
+ end
81
+
82
+ def clear_temporary_data
83
+ @content.clear
84
+ @identity = ""
85
+ end
86
+
87
+ def content
88
+ @content ||= {}
89
+ end
90
+
91
+ def identity
92
+ @identity ||= ""
108
93
  end
109
94
 
110
95
  end
111
- end
96
+ end
97
+
@@ -0,0 +1,108 @@
1
+ require 'stringio'
2
+
3
+ module SgfParser
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
+
@@ -5,4 +5,4 @@ require 'sgf/parser/properties'
5
5
  require 'sgf/parser/node'
6
6
  require 'sgf/parser/tree'
7
7
  require 'sgf/parser/tree_parse'
8
- require 'sgf/sgfindent'
8
+ require 'sgf/sgf_indent'
@@ -0,0 +1,13 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "SgfParser::Tree.parse" do
4
+
5
+ before :each do
6
+ @tree = SgfParser::Tree.new :filename => 'sample_sgf/ff4_ex.sgf'
7
+ end
8
+
9
+ it "should return true" do
10
+ true
11
+ end
12
+
13
+ end
@@ -16,7 +16,6 @@ describe "SgfParser::Tree" do
16
16
  @new = 'sample_sgf/ff4_ex_saved.sgf'
17
17
  @tree.save :filename => @new
18
18
  @tree2 = SgfParser::Tree.new :filename => @new
19
-
20
19
  @tree2.should == @tree
21
20
  end
22
21
 
@@ -0,0 +1,3 @@
1
+ require 'irb/completion'
2
+ require 'lib/sgf_parser'
3
+ sgf = SgfParser::Tree.new :filename => 'sample_sgf/ff4_ex.sgf'
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: SgfParser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 9
8
+ - 0
9
+ version: 0.9.0
5
10
  platform: ruby
6
11
  authors:
7
12
  - Aldric Giacomoni
@@ -9,19 +14,23 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2010-01-05 00:00:00 -05:00
17
+ date: 2010-04-30 00:00:00 -04:00
13
18
  default_executable:
14
19
  dependencies:
15
20
  - !ruby/object:Gem::Dependency
16
21
  name: rspec
17
- type: :development
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
20
24
  requirements:
21
25
  - - ">="
22
26
  - !ruby/object:Gem::Version
27
+ segments:
28
+ - 1
29
+ - 2
30
+ - 9
23
31
  version: 1.2.9
24
- version:
32
+ type: :development
33
+ version_requirements: *id001
25
34
  description: SGFParser is a library that parses and saves SGF (Smart Game Format) files.
26
35
  email: aldric@trevoke.net
27
36
  executables: []
@@ -43,16 +52,16 @@ files:
43
52
  - lib/sgf/parser/properties.rb
44
53
  - lib/sgf/parser/tree.rb
45
54
  - lib/sgf/parser/tree_parse.rb
46
- - lib/sgf/sgfindent.rb
55
+ - lib/sgf/sgf_indent.rb
47
56
  - lib/sgf_parser.rb
48
57
  - sample_sgf/ff4_ex.sgf
49
- - sample_sgf/ff4_ex_saved.sgf
50
58
  - sample_sgf/redrose-tartrate.sgf
51
59
  - sample_usage/parsing_files.rb
52
60
  - spec/node_spec.rb
53
61
  - spec/spec.opts
54
62
  - spec/spec_helper.rb
55
63
  - spec/tree_spec.rb
64
+ - tryme.rb
56
65
  has_rdoc: true
57
66
  homepage: http://github.com/Trevoke/SGFParser
58
67
  licenses: []
@@ -66,22 +75,25 @@ required_ruby_version: !ruby/object:Gem::Requirement
66
75
  requirements:
67
76
  - - ">="
68
77
  - !ruby/object:Gem::Version
78
+ segments:
79
+ - 0
69
80
  version: "0"
70
- version:
71
81
  required_rubygems_version: !ruby/object:Gem::Requirement
72
82
  requirements:
73
83
  - - ">="
74
84
  - !ruby/object:Gem::Version
85
+ segments:
86
+ - 0
75
87
  version: "0"
76
- version:
77
88
  requirements: []
78
89
 
79
90
  rubyforge_project:
80
- rubygems_version: 1.3.5
91
+ rubygems_version: 1.3.6
81
92
  signing_key:
82
93
  specification_version: 3
83
94
  summary: A library for working with SGF files.
84
95
  test_files:
85
96
  - spec/node_spec.rb
86
97
  - spec/spec_helper.rb
98
+ - spec/tree_parser_spec.rb
87
99
  - spec/tree_spec.rb
@@ -1,118 +0,0 @@
1
- module SgfParser
2
-
3
- # This indents an SGF file to make it more readable. It outputs to the screen
4
- # by default, but can be given a file as output.
5
- # Usage: SgfParser::Indenter.new infile, outfile
6
- class Indenter
7
-
8
- def initialize file, out=$stdout
9
- sgf = ""
10
- File.open(file) { |f| sgf = f.read }
11
- @new_string = ""
12
- sgf.gsub! "\\\\n\\\\r", ""
13
- sgf.gsub! "\\\\r\\\\n", ""
14
- sgf.gsub! "\\\\r", ""
15
- sgf.gsub! "\\\\n", ""
16
- #sgf.gsub! "\n", ""
17
-
18
- end_of_a_series = false
19
- identprop = false # We are not in the middle of an identprop value.
20
- # An identprop is an identity property - a value.
21
-
22
- sgf_array = sgf.split(//)
23
- iterator = 0
24
- array_length = sgf_array.size
25
- indent = 0
26
-
27
- while iterator < array_length - 1
28
- char = sgf_array[iterator]
29
-
30
- case char
31
- when '(' # Opening a new branch
32
- if !identprop
33
- @new_string << "\n"
34
- indent += 2
35
- #tabulate indent
36
- @new_string << " " * indent
37
- end
38
- @new_string << char
39
-
40
- when ')' # Closing a branch
41
- @new_string << char
42
- if !identprop
43
- @new_string << "\n"
44
- indent -= 2
45
- @new_string << " " * indent
46
- #tabulate indent
47
- end
48
-
49
- when ';' # Opening a new node
50
- if !identprop
51
- @new_string << "\n"
52
- @new_string << " " * indent
53
- #tabulate indent
54
- end
55
- @new_string << char
56
-
57
- when '[' # Open comment?
58
- if !identprop #If we're not inside a comment, then now we are.
59
- identprop = true
60
- end_of_a_series = false
61
- end
62
- @new_string << char
63
-
64
- when ']' # Close comment
65
- end_of_a_series = true # Maybe end of a series of comments.
66
- identprop = false # That's our cue to close a comment.
67
- @new_string << char
68
-
69
- when "\\" # If we're inside a comment, then maybe we're about to escape a ].
70
- # This is the whole reason we need this ugly charade of a loop.
71
- if identprop
72
- if sgf_array[iterator + 1] == "]"
73
- @new_string << "\\]"
74
- iterator += 1
75
- else
76
- @new_string << "\\"
77
- end
78
- else
79
- #This should never happen - a backslash outside a comment ?!
80
- #But let's not have it be told that I'm not prepared.
81
- @new_string << "\\"
82
- end
83
-
84
- when "\n"
85
- @new_string << "\n"
86
- @new_string << " " * indent
87
- #tabulate indent
88
-
89
- else
90
- # Well, I guess it's "just" a character after all.
91
- if end_of_a_series
92
- end_of_a_series = false
93
- end
94
- @new_string << char
95
- end
96
-
97
- iterator += 1
98
- end
99
-
100
- if out == $stdout
101
- $stdout << @new_string
102
- else
103
- File.open(out, 'w') { |file| file << @new_string }
104
- end
105
-
106
- end
107
-
108
- private
109
-
110
- def tabulate indent
111
- indent.times { print " " }
112
- end
113
- end
114
- end
115
-
116
-
117
-
118
-
@@ -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]C[Marked as "Good for White"]GW[1];B[pp]C[Marked as "Very good for Black"]GB[2];W[dc]C[Marked as "Very good for White"]GW[2];B[pj]C[Marked as "Even position"]DM[1];W[ci]UC[1]C[Marked as "Unclear position"];B[jd]C[Marked as "Tesuji" or "Good move"]TE[1];BM[2]W[jp]C[Marked as "Very bad move"];DO[]B[gd]C[Marked as "Doubtful move"];IT[]W[de]C[Marked as "Interesting move"];B[jj];W[]C[White "Pass" move];)(;AB[do:gq]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.] AW[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.]AE[pn:pq];AW[pp]AB[pd]C[Added two stones.
8
-
9
- Node marked with "Black to play".]PL[B];)(;AW[er]AB[mr]N[Markup]C[Position set up without compressed point lists.]; SL[kh:kj] TW[lr:ns] TB[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)] CR[pd:pf]TR[fd:ff] SQ[ph:pj] MA[fh:fj];LB[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]OB[10]BL[105.6];W[qq]C[White time left: 200 sec
37
- White stones left: 2]OW[2]WL[200];B[sr]C[Black time left: 87 sec
38
- Black stones left: 9]OB[9]BL[87.00];W[qs]C[White time left: 13.2 sec
39
- White stones left: 1]OW[1]WL[13.20];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]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.]AP[Primiview:3.1]GM[1]SZ[19];B[pd](;)(;)(;W[ep];B[pp](;)(;))