ludy 0.0.7 → 0.0.8

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/CHANGES CHANGED
@@ -1,6 +1,26 @@
1
1
 
2
2
  ==============================
3
- ludy 0.0.7
3
+ ludy TODO
4
+ Proc#bind
5
+ multi
6
+ chain travel
7
+ method hook
8
+
9
+ ==============================
10
+ ludy 0.0.8, 2007.12.06
11
+
12
+ 1. ludy_ext:
13
+ added:
14
+ 1. Array#untranspose!
15
+ 2. Array#unzip!
16
+
17
+ changed:
18
+ 1. Kernel#curry support Symbol
19
+
20
+ 2. puzzle_generator added...
21
+
22
+ ==============================
23
+ ludy 0.0.7, 2007.10.08
4
24
 
5
25
  1. ludy_ext:
6
26
  added:
data/lib/ludy/ludy_ext.rb CHANGED
@@ -85,7 +85,9 @@ class Array
85
85
  }
86
86
  result
87
87
  end
88
- def unzip; self.untranspose.first; end
88
+ def untranspose!; replace untranspose; end
89
+ def unzip; untranspose.first; end
90
+ def unzip!; replace unzip; end
89
91
  end
90
92
 
91
93
  class Proc
@@ -113,7 +115,8 @@ end
113
115
  module Kernel
114
116
  def id a = nil; a.nil? ? self : a; end
115
117
  def curry
116
- class << self
118
+ result = self.kind_of?(Symbol) ? self.to_proc : self
119
+ class << result
117
120
  alias_method :orig_call, :call
118
121
  def call *args, &block
119
122
  if self.arity == -1
@@ -137,6 +140,6 @@ module Kernel
137
140
  end
138
141
  alias_method :[], :call
139
142
  end
140
- self
143
+ result
141
144
  end
142
145
  end
@@ -0,0 +1,33 @@
1
+
2
+ require File.join(File.dirname(__FILE__), 'misc')
3
+
4
+ module PuzzleGenerator
5
+
6
+ class Chain
7
+ include Enumerable
8
+ def initialize position = [0, 0], direct = Up, invoke = DefaultOption[:invoke]
9
+ @direct = direct
10
+ x, y = position
11
+ @data = case @direct
12
+ when Up : ([x]*invoke).zip((y...y+invoke).to_a)
13
+ when Right: (x...x+invoke).to_a.zip([y]*invoke)
14
+ when Left : (x-invoke+1..x).to_a.zip([y]*invoke)
15
+ end
16
+ end
17
+ def <=> rhs; @data <=> rhs.instance_variable_get('@data'); end
18
+ def == rhs; (self <=> rhs) == 0; end
19
+ def each &block; @data.each &block; self end
20
+ def [] index; @data[index]; end
21
+ def to_a; @data.clone; end
22
+ def up?; @direct == Up; end
23
+ def bound_ok? max_width, max_height
24
+ not @data.find{ |i|
25
+ i.first >= max_width ||
26
+ i.last >= max_height ||
27
+ i.first < 0 ||
28
+ i.last < 0
29
+ }
30
+ end
31
+ end
32
+
33
+ end
@@ -0,0 +1,116 @@
1
+
2
+ pwd = File.dirname __FILE__
3
+
4
+ require File.join(pwd, 'misc')
5
+ require File.join(pwd, 'chain')
6
+ require File.join(pwd, 'map')
7
+
8
+ require 'rubygems'
9
+
10
+ gem 'ludy', '>=0.0.7' # for Array#combine
11
+ require 'ludy/ludy_ext'
12
+
13
+ gem 'facets', '>=2.0.0' # for lots of things
14
+ require 'facets/random' # for Array#pick
15
+
16
+ module PuzzleGenerator
17
+
18
+ # 1. put a chain
19
+ # 2. destroy a chain by chain
20
+ # 2. a. choose a position by last map
21
+ # 2. b. choose a direct from 3 direct (memo p+d)
22
+ # 2. c. check if the position + direct is ok? ok pass, failed choose again
23
+ # 2. d. goto 2
24
+
25
+ class ChainedMap
26
+ include DisplayMap, MapUtils
27
+ attr_reader :maps, :option
28
+ def initialize option = {}
29
+ @option = DefaultOption.merge option
30
+ raise_if_bad_argument
31
+ init_map
32
+ @result_map = begin next_level until @maps.size >= @option[:level]; put_fire_point
33
+ rescue GenerationFailed; $! end
34
+ end
35
+
36
+ private
37
+ def raise_if_bad_argument
38
+ msg = []
39
+ @option.each{ |name, value| msg << "#{name} should be greater than 1." if value <= 1 }
40
+ raise ArgumentError.new(msg.join("\n")) unless msg.empty?
41
+ end
42
+ def make_map; Map.new @option; end
43
+ def init_map
44
+ @maps = [make_map]
45
+ @result_map = make_map_array
46
+ @picked_chain = make_init_chains([(0..@option[:width]-@option[:invoke]), [0]].combos).pick
47
+ put_picked_chain_on @maps
48
+ resolve_map
49
+ end
50
+ # please make this init chain to variable length chain
51
+ def make_init_chains positions
52
+ positions.inject([]){ |result, pos| result << Chain.new(pos, Right, @option[:invoke]) }
53
+ end
54
+
55
+ def chain_ok?
56
+ raise GenerationFailed.new("ChainedMap: last result_map: #{@result_map.inspect}") if @picked_chain.nil?
57
+ @maps_preview = @maps.deep_clone
58
+ put_picked_chain_on @maps_preview
59
+
60
+ result = check_overlap_and_resolve_it &&
61
+ check_broken_except_last &&
62
+ check_answer_correctness(@result_map_preview) # need this if you gen variable length chain
63
+
64
+ @maps_preview = nil
65
+ @result_map_preview = nil
66
+ result
67
+ end
68
+ def next_level new_map = nil
69
+ @maps << (new_map || make_map)
70
+ chains = @maps[-1].break_chains @maps[-2], @result_map
71
+
72
+ @picked_chain = chains.pick!
73
+ @picked_chain = chains.pick! until chain_ok?
74
+
75
+ put_picked_chain_on @maps
76
+ @picked_chain = nil
77
+ resolve_map
78
+ end
79
+ def put_fire_point; next_level Map.new(@option.merge(:invoke => 1, :invoke_max => 1)); end
80
+ def put_picked_chain_on maps
81
+ maps.last.chains << @picked_chain
82
+ @picked_chain.each{ |pos|
83
+ x, y = pos
84
+ maps.each{ |map|
85
+ column = map[x]
86
+ column.replace(column[0...y] + column[y..-1].rotate)
87
+ }
88
+ maps.last[x, y] = maps.size
89
+ }
90
+ end
91
+ def check_overlap_and_resolve_it
92
+ @result_map_preview = @maps_preview.body.inject(make_map_array){ |result, map|
93
+ result.each_with_index{ |column, x|
94
+ column.each_with_index{ |value, y|
95
+ # assert one of them is zero or they are all zero
96
+ return false unless value * map[x, y] == 0
97
+ }
98
+ }
99
+ combine_map result, map
100
+ }
101
+ end
102
+ def check_broken_except_last
103
+ @maps_preview.body.all?{ |map|
104
+ result = true
105
+ map.each_with_index_2d{ |i, x, y|
106
+ result &&= !check_left_chain( map, x, y) &&
107
+ !check_right_chain(map, x, y) &&
108
+ !check_up_chain( map, x, y) &&
109
+ !check_down_chain( map, x, y)
110
+ }
111
+ result
112
+ }
113
+ end
114
+ end
115
+
116
+ end
@@ -0,0 +1,59 @@
1
+
2
+ require File.join(File.dirname(__FILE__), 'misc')
3
+
4
+ module PuzzleGenerator
5
+ class ColoredMap
6
+ include DisplayMap, MapUtils
7
+ def initialize chained_map, colors = (1..chained_map.option[:colors]).to_a
8
+ @result_map = []
9
+ @maps = []
10
+ @chained_map = chained_map
11
+ @option = @chained_map.option
12
+
13
+ debug_init if PuzzleGenerator.debug
14
+
15
+ chained_map.maps.each_with_index{ |map, index|
16
+ @maps << map.clone_with_map{ |color|
17
+ color == 0 ? 0 : colors[index % @option[:colors]]
18
+ }
19
+ }
20
+ resolve_map
21
+ @result_map = if check_no_invoke && strip_answer && check_answer_correctness
22
+ put_answer_back; @result_map
23
+ else
24
+ GenerationFailed.new("ColoredMap: last result_map: #{@result_map.inspect}")
25
+ end
26
+ end
27
+
28
+ private
29
+ def debug_init
30
+ @debug_answer = @chained_map.maps.last.each_with_index_2d{ |i, x, y| break i if i != 0 }
31
+ end
32
+ def check_no_invoke
33
+ m = Map.new :data => @result_map, :option => @option
34
+ m.each_with_index_2d{ |i, x, y|
35
+ return false if check_left_chain( m, x, y) ||
36
+ check_right_chain(m, x, y) ||
37
+ check_up_chain( m, x, y) ||
38
+ check_down_chain( m, x, y)
39
+ }
40
+ true
41
+ end
42
+ def strip_answer
43
+ @x, @y = @chained_map.maps.last.each_with_index_2d{ |i, x, y| break [x, y] if i != 0 }
44
+ # map = Map.new :data => @result_map, :option => @option
45
+ # return false unless !check_left_chain( map, @x, @y) &&
46
+ # !check_right_chain(map, @x, @y) &&
47
+ # !check_up_chain( map, @x, @y) &&
48
+ # !check_down_chain( map, @x, @y)
49
+ @answer_color = @result_map[@x][@y]
50
+ @result_map[@x][@y] = 0
51
+ true
52
+ end
53
+ def put_answer_back
54
+ @result_map[@x][@y] = @debug_answer || @answer_color
55
+ @x, @y, @answer_color = nil
56
+ end
57
+ end
58
+
59
+ end
@@ -0,0 +1,135 @@
1
+
2
+ pwd = File.dirname __FILE__
3
+
4
+ require File.join(pwd, 'misc')
5
+ require File.join(pwd, 'chain')
6
+
7
+ require 'rubygems'
8
+
9
+ gem 'ludy', '>=0.0.7' # for Array#untranspose
10
+ require 'ludy/ludy_ext'
11
+
12
+ gem 'facets', '>=2.0.0' # for lots of things
13
+ require 'facets' # for Array#combos
14
+ require 'facets/random' # for Kernel#maybe
15
+
16
+ # a = [[1,2],[3,4],[5,6]]
17
+ # [a, [1,2,3]].combos
18
+ # => [[[1, 2], 1], [[1, 2], 2], [[1, 2], 3], [[3, 4], 1], [[3, 4], 2], [[3, 4], 3], [[5, 6], 1], [[5, 6], 2], [[5, 6], 3]]
19
+
20
+ module PuzzleGenerator
21
+
22
+ class Map
23
+ include DisplayMap, Enumerable
24
+ attr_reader :chains
25
+ def result_map; @data; end
26
+ def initialize option = {}
27
+ @option = DefaultOption.merge option
28
+ @data = @option[:data] || (Array.new(@option[:width])).map{ [0]*@option[:height] }
29
+ @chains = @option[:chains] || []
30
+ end
31
+ # TRAP!! view is not view, it's clone!!
32
+ # def [] x, y = (0..-1); @data[x][y]; end
33
+
34
+ # NOTICE!! this is not view (reference)
35
+ def [] x, y = nil
36
+ if y.nil?
37
+ @data[x]
38
+ else
39
+ if x.kind_of? Range
40
+ @data[x].transpose[y]
41
+ else
42
+ @data[x][y]
43
+ end
44
+ end
45
+ end
46
+ def []= x, y, v; @data[x][y] = v; end
47
+ def each_column_with_index; @data.each_with_index{ |column, index| yield column, index }; end
48
+ def each_column; @data.each{ |column| yield column }; end
49
+ def clone_with_map
50
+ Map.new @option.merge(
51
+ :data => @data.transpose.map{ |row| row.map{ |i| yield i } }.untranspose,
52
+ :chains => chains
53
+ )
54
+ end
55
+ def to_a; @data.clone; end
56
+ def each; @data.flatten.each{ |i| yield i }; end
57
+ def each_with_index_2d
58
+ @data.transpose.each_with_index{ |row, y| row.each_with_index{ |i, x| yield i, x, y } }
59
+ end
60
+ def break_chains map, result_map
61
+ @temp_map = map
62
+ @temp_result_map = result_map
63
+ result = []
64
+ map.each_column_with_index{ |column, ix|
65
+ column.each_with_index{ |y, iy| result << [ix, iy] if y != 0 }
66
+ } # e.g., [[0, 0], [1, 1]]
67
+ result = transform result,
68
+ :with_belows,
69
+ :with_directs,
70
+ :to_chains,
71
+ :strip_duplicated_chain,
72
+ :strip_out_bounded_chain,
73
+ :strip_overflow_chain,
74
+ :strip_floating_chain
75
+
76
+ @temp_result_map = nil
77
+ @temp_map = nil
78
+ result
79
+ end
80
+
81
+ private
82
+ def transform target, *funs; target = method(funs.shift)[target] until funs.empty?; target; end
83
+ def with_belows target
84
+ result = []
85
+ up_hack = 0 # @temp_map.chains.last.up? ? 1 : 0
86
+ target.each{ |pos|
87
+ x, y = pos
88
+ result.concat( ([x]*(y+1)).zip((up_hack..y).to_a) )
89
+ }
90
+ result.uniq
91
+ # e.g., [[0, 0], [[1, 0], [1, 1]]] =>
92
+ # [[0, 0], [1, 0], [1, 1]]
93
+ end
94
+ def with_directs target
95
+ # [target, [Up] + [Right, Left]*10].combos
96
+ [target, [Up, Right, Left]].combos
97
+ # e.g., [[[0, 0], Up], [[0, 0], Right], [[0, 0], Left], [[1, 0], Up], ...]
98
+ end
99
+ def to_chains target
100
+ target.map{ |pos| Chain.new pos.first, pos.last, gen_chain_length }
101
+ # e.g., [Chain#0x000, Chain#0x001, ...]
102
+ end
103
+ def gen_chain_length
104
+ @option[:invoke] + (maybe ? 0 : rand(@option[:invoke_max] - @option[:invoke] + 1))
105
+ end
106
+ def strip_duplicated_chain target
107
+ # target.uniq never works for non-num nor non-string :(
108
+ # target.sort.inject([]){ |r, i| r.last == i ? r : r<<i }
109
+ target.uniq_by{|i|i}
110
+ end
111
+ def strip_out_bounded_chain target
112
+ target.select{ |chain| chain.bound_ok? @option[:width], @option[:height] }
113
+ end
114
+ def strip_overflow_chain target
115
+ target.select{ |chain|
116
+ xs = Hash.new 0
117
+ chain.to_a.transpose.first.each{ |x| xs[x] += 1 }
118
+ xs.all?{ |pair|
119
+ x, count = pair
120
+ height(@temp_result_map[x]) + count <= @option[:height]
121
+ }
122
+ }
123
+ end
124
+ def strip_floating_chain target
125
+ target.select{ |chain|
126
+ chain.all?{ |pos|
127
+ x, y = pos # if the direct is up, then it's impossible floating.
128
+ chain.up? || !@temp_result_map[x][0...y].include?(0)
129
+ }
130
+ }
131
+ end
132
+ def height column; @option[:height] - column.count(0); end
133
+ end
134
+
135
+ end
@@ -0,0 +1,132 @@
1
+
2
+ require 'rubygems'
3
+ require 'facets' # for Array#deep_clone
4
+ # require 'ludy/ludy_ext' # for Kernel#curry
5
+
6
+ module PuzzleGenerator
7
+ Up, Right, Left = (0..2).to_a
8
+ DefaultOption = {:width => 6, :height => 10, :level => 4, :colors => 4,
9
+ :invoke => 3, :invoke_max => 5, :timeout => 5}
10
+ class GenerationFailed < RuntimeError; end
11
+ class << self
12
+ attr_writer :debug
13
+ def debug; @debug || false; end
14
+ end
15
+
16
+ module DisplayMap
17
+ attr_reader :result_map
18
+ def display_map
19
+ result_map.transpose.reverse_each{ |row| puts row.map{ |color| '%2d' % color }.join(' ') }
20
+ end
21
+ end
22
+
23
+ module MapUtils
24
+ def make_map_array; (Array.new(@option[:width])).map{ [0]*@option[:height] }; end
25
+ def resolve_map result_map = @result_map, maps = @maps
26
+ result_map.replace maps.inject(make_map_array){ |result, map|
27
+ combine_map result, map
28
+ }
29
+ end
30
+ def combine_map result, map
31
+ result.zip(map.to_a).map{ |columns|
32
+ orig, last = columns
33
+ orig.combine last
34
+ }
35
+ end
36
+ def check_answer_correctness result_map = @result_map
37
+ map = Map.new @option.merge(:data => result_map.deep_clone)
38
+ drop_blocks map # because of answer is stripped
39
+
40
+ @chained = true
41
+ while @chained
42
+ @chained = false
43
+ destory_chains map
44
+ drop_blocks map
45
+ end
46
+ @chained = nil
47
+
48
+ map.all?{ |i| i == 0 }
49
+ end
50
+ def destory_chains map
51
+ map.each_column_with_index{ |column, x|
52
+ column.each_with_index{ |value, y|
53
+ next if value == 0
54
+
55
+ left = check_left_chain map, x, y
56
+ right = check_right_chain map, x, y
57
+ up = check_up_chain map, x, y
58
+ down = check_down_chain map, x, y
59
+
60
+ # left.fill 0 unless left.nil?
61
+ # right.fill 0 unless right.nil?
62
+ # up.fill 0 unless up.nil?
63
+ # down.fill 0 unless down.nil?
64
+ left.size.times{ |offset|
65
+ map[x-offset, y] = 0
66
+ } unless left.nil?
67
+ right.size.times{ |offset|
68
+ map[x+offset, y] = 0
69
+ } unless right.nil?
70
+ up.size.times{ |offset|
71
+ map[x, y+offset] = 0
72
+ } unless up.nil?
73
+ down.size.times{ |offset|
74
+ map[x, y-offset] = 0
75
+ } unless down.nil?
76
+
77
+ @chained ||= left || right || up || down
78
+ }
79
+ }
80
+ end
81
+ def drop_blocks map
82
+ map.each_column{ |column| column.map!{ |i| i==0 ? nil : i }.compact!.pad!(@option[:height], 0) }
83
+ end
84
+ def check_left_chain map, x, y
85
+ # this should be rewrited
86
+ return nil if map[x, y] == 0
87
+ left = x - @option[:invoke] + 1
88
+ return nil if left < 0
89
+ # chain = map[left..x, y]
90
+ # chain if chain.all?{ |i| i == map[x, y] }
91
+ # map[0..x, y].inject([]){ |result, value| result << value if value == map[x, y] }
92
+ do_check_chain map[0..x, y].reverse, map[x, y]
93
+ end
94
+ def check_right_chain map, x, y
95
+ return nil if map[x, y] == 0
96
+ right = x + @option[:invoke] - 1
97
+ return nil if right >= @option[:width]
98
+ # chain = map[x..right, y]
99
+ # chain if chain.all?{ |i| i == map[x, y] }
100
+ do_check_chain map[x...@option[:width], y], map[x, y]
101
+ end
102
+ def check_up_chain map, x, y
103
+ return nil if map[x, y] == 0
104
+ up = y + @option[:invoke] - 1
105
+ return nil if up >= @option[:height]
106
+ # chain = map[x, y..up]
107
+ # chain if chain.all?{ |i| i == map[x, y] }
108
+ do_check_chain map[x, y...@option[:height]], map[x, y]
109
+ end
110
+ def check_down_chain map, x, y
111
+ return nil if map[x, y] == 0
112
+ down = y - @option[:invoke] - 1
113
+ return nil if down < 0
114
+ # chain = map[x, down..y]
115
+ # chain if chain.all?{ |i| i == map[x, y] }
116
+ do_check_chain map[x, 0..y].reverse, map[x, y]
117
+ end
118
+ # def check_chain target_color, result, value; result << value if value == target_color; end
119
+ def do_check_chain target, target_color
120
+ # target.inject([], &method(:check_chain).curry[target_color])
121
+ chain = target.inject([]){ |result, value|
122
+ if value == target_color
123
+ result << value
124
+ else
125
+ break result
126
+ end
127
+ }
128
+ chain.size >= @option[:invoke] ? chain : nil
129
+ end
130
+ end
131
+
132
+ end
@@ -0,0 +1,64 @@
1
+
2
+ require File.join(File.dirname(__FILE__), 'misc')
3
+ require File.join(File.dirname(__FILE__), 'chained_map')
4
+ require File.join(File.dirname(__FILE__), 'colored_map')
5
+
6
+ require 'rubygems'
7
+ require 'facets' # for Array#rotate
8
+ require 'facets/timer'
9
+
10
+ module PuzzleGenerator
11
+
12
+ class Puzzle
13
+ include DisplayMap
14
+ attr_reader :tried_times, :tried_duration
15
+ def initialize option = {}
16
+ @option = DefaultOption.merge option
17
+ @tried_times, @tried_duration = [0, 0], [0, 0]
18
+ end
19
+ def generate
20
+ raw_colors = (1..@option[:colors]).to_a
21
+ step_colors = raw_colors.rotate
22
+
23
+ make_chain
24
+ make_color raw_colors
25
+ until @result_color.result_map.kind_of? Array
26
+ if step_colors == raw_colors
27
+ make_chain
28
+ make_color raw_colors
29
+ step_colors = raw_colors.rotate
30
+ else
31
+ make_color step_colors
32
+ step_colors.rotate!
33
+ end
34
+ end
35
+
36
+ @result_map = @result_color.result_map
37
+ end
38
+
39
+ private
40
+ Chain, Color = 0, 1
41
+ def make_chain
42
+ begin
43
+ @result_chain =
44
+ PuzzleGenerator::generate(
45
+ @option[:timeout] - @tried_duration[Chain]){ ChainedMap.new @option }
46
+ ensure
47
+ update_info Chain, LastTriedInfo
48
+ end
49
+ end
50
+ def make_color colors
51
+ start = Time.now
52
+ begin
53
+ @result_color = ColoredMap.new @result_chain, colors
54
+ ensure
55
+ update_info Color, {:tried_times => 1, :tried_duration => Time.now - start}
56
+ end
57
+ end
58
+ def update_info index, info
59
+ @tried_times[index] += info[:tried_times]
60
+ @tried_duration[index] += info[:tried_duration]
61
+ end
62
+ end
63
+
64
+ end
@@ -0,0 +1,35 @@
1
+
2
+ # alpha at 2007.10.14
3
+
4
+ require File.join(File.dirname(__FILE__), 'puzzle_generator', 'puzzle')
5
+
6
+ require 'rubygems'
7
+ require 'facets' # for Hash#reverse_merge
8
+ require 'facets/timer'
9
+
10
+ module PuzzleGenerator
11
+
12
+ def self.generate_chained_map option = {}; generate_klass ChainedMap, option; end
13
+ def self.generate_klass klass, option = {}
14
+ option.reverse_merge! :timeout => 5
15
+ generate(option[:timeout]){ klass.new option }
16
+ end
17
+
18
+ LastTriedInfo = {}
19
+ def self.generate timeout = 5, &generator
20
+ timer = Timer.new(timeout).start
21
+ tried_times = 1
22
+ begin
23
+ result = generator.call
24
+ until result.result_map.kind_of? Array
25
+ tried_times += 1
26
+ result = generator.call
27
+ end
28
+ ensure
29
+ timer.stop
30
+ LastTriedInfo.merge! :tried_times => tried_times, :tried_duration => timer.total_time
31
+ end
32
+ result
33
+ end
34
+
35
+ end
data/ludy.gemspec CHANGED
@@ -18,7 +18,7 @@ require 'rubygems'
18
18
 
19
19
  spec = Gem::Specification.new{|s|
20
20
  s.name = 'ludy'
21
- s.version = '0.0.7'
21
+ s.version = '0.0.8'
22
22
  s.author = 'Lin Jen-Shin(a.k.a. godfat)'
23
23
  s.email = 'strip number: 135godfat7911@246godfat.890org'
24
24
  s.homepage = 'http://ludy.rubyforge.org/'
data/test/tc_ludy_ext.rb CHANGED
@@ -76,6 +76,12 @@ class TestLudyExt < Test::Unit::TestCase
76
76
  assert_equal (0..4).to_a, lambda{|a,b,c,d,e|[a,b,c,d,e]}.curry[0][1][2][3][4]
77
77
  end
78
78
 
79
+ def test_symbol_curry
80
+ a = [1,2,3]
81
+ assert_equal nil, a.find(&:==.curry[0])
82
+ assert_equal 2, a.find(&:==.curry[2])
83
+ end
84
+
79
85
  def test_proc_chain
80
86
  f1 = lambda{|v| v+1}
81
87
  assert_equal 5, f1[4]
@@ -0,0 +1,177 @@
1
+
2
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'puzzle_generator')
3
+
4
+ PuzzleGenerator.debug = true
5
+ p = PuzzleGenerator::Puzzle.new :level => 15, :timeout => 600, :invoke_max => 5
6
+ begin
7
+ p.generate
8
+ p.display_map
9
+ rescue Timeout::Error
10
+ puts 'Timeout!!'
11
+ ensure
12
+ p p.tried_times
13
+ p p.tried_duration
14
+ end
15
+
16
+ # level => 7
17
+ # 0 0 0 0 0 0
18
+ # 0 0 0 0 0 0
19
+ # 0 0 3 0 0 0
20
+ # 0 0 1 0 0 0
21
+ # 1 3 4 0 0 0
22
+ # 2 1 1 0 0 0
23
+ # 2 3 2 0 0 0
24
+ # 3 4 3 0 0 0
25
+ # 3 1 2 4 0 0
26
+ # 2 4 2 1 0 0
27
+
28
+ # level => 15
29
+ # 0 0 1 0 0 0
30
+ # 2 0 2 1 0 0
31
+ # 1 0 4 1 0 0
32
+ # 2 0 3 3 1 0
33
+ # 2 4 1 4 4 0
34
+ # 3 2 4 2 2 1
35
+ # 4 1 1 3 3 2
36
+ # 3 3 2 3 4 3
37
+ # 3 1 3 4 1 2
38
+ # 2 3 4 1 4 2
39
+
40
+ # level => 7
41
+ # 0 0 0 0 0 0
42
+ # 0 0 0 0 0 0
43
+ # 0 0 0 0 0 0
44
+ # 0 0 0 0 0 0
45
+ # 0 0 1 0 0 0
46
+ # 0 0 2 2 0 0
47
+ # 0 1 3 4 4 0
48
+ # 1 2 4 1 1 0
49
+ # 3 3 2 2 3 1
50
+ # 2 2 3 3 4 3
51
+ # [20, 9]
52
+ # [1.630587, 0.151272]
53
+
54
+ # level => 10
55
+ # 0 0 1 1 0 0
56
+ # 0 0 1 2 0 0
57
+ # 0 0 2 3 0 0
58
+ # 0 0 2 3 0 0
59
+ # 0 0 3 4 0 0
60
+ # 0 1 4 1 0 0
61
+ # 0 2 1 3 4 0
62
+ # 2 2 2 2 1 0
63
+ # 2 3 1 3 2 4
64
+ # 4 4 1 4 3 2
65
+ # [28, 1]
66
+ # [3.26917, 0.020366]
67
+
68
+ # level => 12
69
+ # 0 2 1 0 0 0
70
+ # 0 2 2 0 0 0
71
+ # 0 3 3 1 0 0
72
+ # 0 4 3 2 0 0
73
+ # 0 4 4 2 0 4
74
+ # 0 1 4 3 1 1
75
+ # 0 4 1 1 2 1
76
+ # 0 3 2 2 1 2
77
+ # 0 3 4 4 3 1
78
+ # 2 3 4 3 4 1
79
+ # [68, 1]
80
+ # [6.194671, 0.055699]
81
+
82
+ # level => 13
83
+ # 0 3 1 0 0 0
84
+ # 0 2 1 1 0 0
85
+ # 0 3 3 2 1 2
86
+ # 0 3 2 1 1 4
87
+ # 0 4 2 3 3 4
88
+ # 0 1 3 3 2 1
89
+ # 0 4 2 4 3 1
90
+ # 0 4 2 1 4 2
91
+ # 0 3 1 4 4 1
92
+ # 2 3 2 2 1 1
93
+ # [10, 1]
94
+ # [1.97002, 0.030499]
95
+
96
+ # level => 7
97
+ # 0 0 0 0 0 0
98
+ # 0 0 0 2 0 0
99
+ # 0 0 0 3 0 0
100
+ # 0 0 0 4 0 0
101
+ # 0 0 0 1 0 0
102
+ # 0 0 0 2 0 0
103
+ # 0 1 1 3 0 0
104
+ # 0 2 2 4 3 0
105
+ # 0 4 4 3 4 3
106
+ # 1 2 2 3 1 1
107
+ # [53, 17]
108
+ # [4.614123, 0.264156]
109
+
110
+ # level => 14
111
+ # 0 0 0 0 0 0
112
+ # 0 0 1 0 0 0
113
+ # 1 0 4 0 2 0
114
+ # 1 0 2 4 3 0
115
+ # 2 1 3 2 3 0
116
+ # 2 3 1 4 4 1
117
+ # 3 1 4 3 3 2
118
+ # 2 4 1 4 3 2
119
+ # 3 2 2 1 1 3
120
+ # 2 4 4 1 1 2
121
+ # [123, 1]
122
+ # [14.940386, 0.077763]
123
+
124
+ # level => 15
125
+ # 0 0 0 0 1 0
126
+ # 0 0 2 0 2 0
127
+ # 0 0 1 0 3 0
128
+ # 0 4 4 1 4 1
129
+ # 2 2 4 2 3 3
130
+ # 3 2 2 3 1 1
131
+ # 3 3 1 4 4 2
132
+ # 4 3 1 3 4 2
133
+ # 2 4 2 1 1 3
134
+ # 3 3 1 1 4 2
135
+ # [3650, 17]
136
+ # [464.755704, 1.220837]
137
+
138
+ # level => 15
139
+ # 0 2 0 0 1 0
140
+ # 0 4 2 1 3 0
141
+ # 4 3 3 2 2 0
142
+ # 2 4 3 3 2 0
143
+ # 1 2 2 3 3 0
144
+ # 1 1 4 2 3 0
145
+ # 2 1 3 4 16 0
146
+ # 1 2 2 1 3 1
147
+ # 4 1 4 4 2 3
148
+ # 1 1 3 4 1 1
149
+ # [1626, 1]
150
+ # [159.004594, 0.035997]
151
+
152
+ # level => 17 => broken...
153
+ # 0 2 0 1 1 0
154
+ # 0 4 2 2 3 0
155
+ # 4 <3 3 3> 2 1
156
+ # 2 4 3 3 2 2
157
+ # 1 2 2 2 3 3
158
+ # 1 1 4 4 3 2
159
+ # 2 1 3 1 1 2
160
+ # 1 2 2 1 3 1
161
+ # 4 1 4 4 2 3
162
+ # 1 1 3 4 1 1
163
+ # hacked from above XD
164
+
165
+ # level => 15
166
+ # 1 0 0 0 0 0
167
+ # 3 1 1 0 3 0
168
+ # 4 2 4 4 1 0
169
+ # 4 3 2 2 4 0
170
+ # 1 3 2 3 2 0
171
+ # 1 2 3 1 2 0
172
+ # 2 4 2 4 3 0
173
+ # 1 3 3 2 3 0
174
+ # 1 3 1 1 16 4
175
+ # 4 1 2 2 3 1
176
+ # [1139, 1]
177
+ # [115.270095, 0.031929]
metadata CHANGED
@@ -1,33 +1,26 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.4
3
- specification_version: 1
4
2
  name: ludy
5
3
  version: !ruby/object:Gem::Version
6
- version: 0.0.7
7
- date: 2007-10-08 00:00:00 +08:00
8
- summary: Aims to extend Ruby standard library, providing some useful tools that's not existed in the standard library.
9
- require_paths:
10
- - lib
11
- email: "strip number: 135godfat7911@246godfat.890org"
12
- homepage: http://ludy.rubyforge.org/
13
- rubyforge_project:
14
- description:
15
- autorequire: ludy
16
- default_executable:
17
- bindir: bin
18
- has_rdoc: false
19
- required_ruby_version: !ruby/object:Gem::Version::Requirement
20
- requirements:
21
- - - ">"
22
- - !ruby/object:Gem::Version
23
- version: 0.0.0
24
- version:
4
+ version: 0.0.8
25
5
  platform: ruby
26
- signing_key:
27
- cert_chain:
28
- post_install_message:
29
6
  authors:
30
7
  - Lin Jen-Shin(a.k.a. godfat)
8
+ autorequire: ludy
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2007-12-06 00:00:00 +08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: "strip number: 135godfat7911@246godfat.890org"
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
31
24
  files:
32
25
  - lib/lib
33
26
  - lib/lib/amulti.rb
@@ -46,6 +39,14 @@ files:
46
39
  - lib/ludy/y_combinator.rb
47
40
  - lib/ludy/z_combinator.rb
48
41
  - lib/ludy.rb
42
+ - lib/puzzle_generator
43
+ - lib/puzzle_generator/chain.rb
44
+ - lib/puzzle_generator/chained_map.rb
45
+ - lib/puzzle_generator/colored_map.rb
46
+ - lib/puzzle_generator/map.rb
47
+ - lib/puzzle_generator/misc.rb
48
+ - lib/puzzle_generator/puzzle.rb
49
+ - lib/puzzle_generator.rb
49
50
  - test/tc_callstack.rb
50
51
  - test/tc_curry.rb
51
52
  - test/tc_dice.rb
@@ -56,6 +57,7 @@ files:
56
57
  - test/tc_variable.rb
57
58
  - test/tc_y_combinator.rb
58
59
  - test/tc_z_combinator.rb
60
+ - test/test_puzzle.rb
59
61
  - test/ts_ludy.rb
60
62
  - CHANGES
61
63
  - lib
@@ -64,17 +66,31 @@ files:
64
66
  - NOTICE
65
67
  - README
66
68
  - test
67
- test_files:
68
- - test/ts_ludy.rb
69
+ has_rdoc: false
70
+ homepage: http://ludy.rubyforge.org/
71
+ post_install_message:
69
72
  rdoc_options: []
70
73
 
71
- extra_rdoc_files: []
72
-
73
- executables: []
74
-
75
- extensions: []
76
-
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: "0"
81
+ version:
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: "0"
87
+ version:
77
88
  requirements: []
78
89
 
79
- dependencies: []
80
-
90
+ rubyforge_project:
91
+ rubygems_version: 0.9.5
92
+ signing_key:
93
+ specification_version: 2
94
+ summary: Aims to extend Ruby standard library, providing some useful tools that's not existed in the standard library.
95
+ test_files:
96
+ - test/ts_ludy.rb