Skip to content

Commit

Permalink
Partial implementation of cleanup_distance
Browse files Browse the repository at this point in the history
  • Loading branch information
Vaguery committed May 17, 2012
1 parent 4706601 commit 7d7e8c9
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 6 deletions.
8 changes: 2 additions & 6 deletions examples/evaluating_random_scripts.rb
Expand Up @@ -72,7 +72,7 @@ def min_moves_to_replace(wanted_color,config,missing_penalty=100)

# Let's see how this error measure does at finding "close" solutions
setup = [[:b, :r, :b, :b], [], [], [:r, :b, :r, :r]]
target = [[],[:b, :b, :b, :b],[:r, :r, :r, :r],[]]
target = [[],[:b, :b, :b, :r],[:r, :r, :r, :b],[]]


guesses = 10000.times.collect do
Expand All @@ -91,8 +91,4 @@ def min_moves_to_replace(wanted_color,config,missing_penalty=100)
best.each do |good_one|
good_one[:dude].show_off
puts "\n"
end


# here are some that came up randomly:
# "claw R R claw R L call2 prog_2 call3 L prog_1 call1 R_r R claw L L R_g R R prog_2 call1_b claw_b L prog_4 R call1 claw claw R"
end
101 changes: 101 additions & 0 deletions features/cleanup_distance.feature
@@ -0,0 +1,101 @@
Feature: Cleanup distance
In order to evaluate how well a particular outcome matches a target
As a Cargo-Botter
I want to count the number of moves needed to 'fix' each crate

Scenario: score is +0 if the target and observed boxes are the same
Given the target is [[:r],[]]
And the observed is [[:r],[]]
When I calculate the cleanup distance for box 1 of stack 1 of the target
Then the score for that box should be 0

Scenario: score is +1 when target wants box that's on top of some other stack
Given the target is [[:r],[]]
And the observed is [[],[:r]]
When I calculate the cleanup distance for box 1 of stack 1 of the target
Then the score for that box should be 2

Given the target is [[:r,:b],[]]
And the observed is [[:r],[:b]]
When I calculate the cleanup distance for box 2 of stack 1 of the target
Then the score for that box should be 2


Scenario: score is +100 when target wants a box that's missing completely in the observed setup
Given the target is [[:r]]
And the observed is [[]]
When I calculate the cleanup distance for box 1 of stack 1 of the target
Then the score for that box should be 100

Scenario: score is number of blocks moved when target lacks a box that's inside some other stack
Given the target is [[:r], [:b,:b]]
And the observed is [[],[:r,:b,:b]]
When I calculate the cleanup distance for box 1 of stack 1 of the target
Then the score for that box should be 4

Scenario: score is MIN number of blocks moved when target lacks a box that's inside 2+ other stacks
Given the target is [[:r], [:r, :b, :b], [:g, :r, :g]]
And the observed is [[],[:r,:r,:b,:b], [:g,:r,:g]]
When I calculate the cleanup distance for box 1 of stack 1 of the target
Then the score for that box should be 3

Scenario: score is TOTAL blocks moved to replace a block from within a stack
Given the target is [[:g, :r, :r, :r]]
And the observed is [[:r, :r, :r, :g]]
When I calculate the cleanup distance for box 1 of stack 1 of the target
Then the score for that box should be 5

Scenario: score is MIN TOTAL blocks moved to replace a block from another stack
Given the target is [[:g, :r, :r, :r], [:b, :b], [:g, :y, :y, :y]]
And the observed is [[:b, :r, :r, :r], [:g, :b], [:g, :y, :y, :y]]
When I calculate the cleanup distance for box 1 of stack 1 of the target
Then the score for that box should be 6

Scenario: score for a block missing supports
Given the target is [[:r, :r, :b], []]
And the observed is [[:r], [:b, :r]]
When I calculate the cleanup distance for box 3 of stack 1 of the target
Then the score for that box should be 4

Scenario: score is number of blocks moved when target lacks a box that's inside some other stack
Given the target is [[:y, :y, :y, :r], [:b, :b]]
And the observed is [[], [:y, :y, :y, :r, :b, :b]]
When I calculate the cleanup distance for box 4 of stack 1 of the target
Then the score for that box should be 7

Scenario: score for wrong position in same stack
Given the target is [[:r, :r, :r, :r, :b, :r]]
And the observed is [[:b, :r, :r, :r, :r, :r]]
When I calculate the cleanup distance for box 5 of stack 1 of the target
Then the score for that box should be 11

Given the target is [[:r, :r, :b, :r, :r]]
And the observed is [[:b, :r, :r, :r, :r]]
When I calculate the cleanup distance for box 3 of stack 1 of the target
Then the score for that box should be 8


Scenario: score for a stack sums error for each crate
Given the target is [[:r, :r, :r, :r, :b, :r]]
And the observed is [[:b, :r, :r, :r, :r, :r]]
When I calculate the cleanup distance for stack 1 of the target
Then the score for that stack should be 18

Scenario: score for a stack counts cost to remove extra stuff
Given the target is [[], [:r, :r, :r, :r, :b, :r]]
And the observed is [[:r, :r, :r, :r, :b, :r], []]
When I calculate the cleanup distance for stack 1 of the target
Then the score for that stack should be 21













16 changes: 16 additions & 0 deletions features/step_definitions/cleanup_distance_steps.rb
@@ -0,0 +1,16 @@
Given /^the target is (\[.+\])$/ do |arg1|
@target = CrateStacks.new eval(arg1)
end

Given /^the observed is (\[.+\])$/ do |arg1|
@observed = CrateStacks.new eval(arg1)
end

When /^I calculate the cleanup distance for box (\d+) of stack (\d+) of the target$/ do |arg1, arg2|
@distance = @observed.crate_cleanup_distance(@target, arg2.to_i, arg1.to_i)
end

Then /^the score for that box should be (\d+)$/ do |arg1|
@distance.should == arg1.to_i
end

49 changes: 49 additions & 0 deletions lib/cargobot.rb
Expand Up @@ -177,4 +177,53 @@ def show_off
puts " topples: #{@topples}"
puts "stack_trace_depth: #{@stack_trace.length}"
end


end


class CrateStacks
attr_accessor :stacks

def initialize(arrangement = [[]])
@stacks = arrangement
end

def crate_cleanup_distance(target, stack_number, box_number)
stack = stack_number - 1
box = box_number - 1

expected_box = target.stacks[stack][box]
observed_box = @stacks[stack][box]


if expected_box == observed_box
return 0
else
possible_replacements = topmost_matches(expected_box)
return 100 if possible_replacements.empty?

this_stack_replacement = @stacks[stack].rindex(expected_box).nil? ?
nil :
@stacks[stack].length - @stacks[stack].rindex(expected_box)
adding_missing_boxes = @stacks[stack].length-1 < box ? (box + 1 - @stacks[stack].length) : 0
shifting_extra_boxes = @stacks[stack].length-1 > box ? (@stacks[stack].length - box) : 0
grabbing_a_replacement = possible_replacements.min
if this_stack_replacement == grabbing_a_replacement
if this_stack_replacement < shifting_extra_boxes
return shifting_extra_boxes + 1
else
return 2*this_stack_replacement - (@stacks[stack].length-box) + 1
end
else
return shifting_extra_boxes + adding_missing_boxes + grabbing_a_replacement
end
end
end


def topmost_matches(crate)
@stacks.collect {|s| (s.length - s.rindex(crate)) unless s.rindex(crate).nil?}.compact
end

end

0 comments on commit 7d7e8c9

Please sign in to comment.