SgfParser 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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](;)(;))