anoff
Andreas Offenhaeuser
: anoff
anoff |
this documentation is autogenerated. Add a README.adoc
to your solution to take over the control of this :-)
Hello world for Advent of Code 2019
This year I want to refurbish my python skills..and maybe try some Ruby.
Run the solution with python solution.py
print("hello world")
The biggest struggle was to configure VScode to allow me adding the "math"
package to my solution.
I also did not read the manual correctly and forgot to subtract minus 2 at first.
I solved the fuel needs more fuel dilemma by creating a requiredFuelRecursive
function that takes its intermediate result and calls itself again.
To prevent an endless loop it checks the intermediate result to be positive before recursion.
package main
import (
"fmt"
"math"
)
func main() {
input := readInput("./input.txt")
part1(StringSlice2IntSlice(input))
part2(StringSlice2IntSlice(input))
}
func part1(massInventory []int) {
var fuelSum int = 0
for _, mass := range massInventory {
fuelSum += requiredFuel(mass)
}
fmt.Println("Solution for part1:", fuelSum)
}
func part2(massInventory []int) {
var fuelSum int = 0
for _, mass := range massInventory {
fuelSum += requiredFuelRecursive(mass)
}
fmt.Println("Solution for part2:", fuelSum)
}
func requiredFuel(mass int) int {
var massFloat = float64(mass)
var fuelFloat = math.Floor(massFloat / 3)
return int(fuelFloat) - 2
}
func requiredFuelRecursive(mass int) int {
var massFloat = float64(mass)
var fuelFloat = math.Floor(massFloat/3) - 2
var fuelInt = int(math.Max(fuelFloat, 0))
if fuelInt > 0 {
var additionalFuel = requiredFuelRecursive(fuelInt)
fuelInt += additionalFuel
}
return fuelInt
}
package main
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestRequiredFuel(t *testing.T) {
m := make(map[int]int)
m[12] = 2
m[14] = 2
m[1969] = 654
m[100756] = 33583
for mass, fuel := range m {
res := requiredFuel(mass)
assert.Equal(t, fuel, res, "Wrong result for mass=%d", mass)
}
}
func TestRequiredFuelRecursive(t *testing.T) {
m := make(map[int]int)
m[12] = 2
m[14] = 2
m[1969] = 966
m[100756] = 50346
for mass, fuel := range m {
res := requiredFuelRecursive(mass)
assert.Equal(t, fuel, res, "Wrong result for mass=%d", mass)
}
}
First program in ruby. Had to figure out how to layout the main file to allow multiple methods and running tests. Solution is pretty straight forward. Way shorter than go 😲
Decided to do a loop instead of a recursion to find the total amount of fuel.
#!/usr/bin/ruby
def required_fuel(mass)
(mass / 3) - 2
end
def part1(massInventory)
fuelSum = massInventory
.map { |mass| required_fuel(mass) }
.reduce(0) { |sum, num| sum + num }
end
def part2(massInventory)
fuelSum = 0
massInventory.each{ |mass|
fuel = required_fuel(mass)
while fuel > 0 do
fuelSum += fuel
fuel = required_fuel(fuel)
end
}
fuelSum
end
if caller.length == 0
input = File.read("./input.txt")
massInventory = input.split("\n").map(&:to_i)
puts "Solution for part1: %d" % part1(massInventory)
puts "Solution for part2: %d" % part2(massInventory)
end
require "test/unit"
require_relative './solution'
class TestSolution < Test::Unit::TestCase
def test_required_fuel
d = {
12 => 2,
14 => 2,
1969 => 654,
100756 => 33583
}
d.each{ |mass, fuel|
assert_equal fuel, required_fuel(mass), "Incorrect fuel for mass=%d" % mass
}
end
end
Puzzle: 1202 Program Alarm
At first I was reminded of last years puzzle. But thinking about it for a while it seemed to be the best approach to just manipulate the program in memory. After figuring out how ruby passes data - by argument - the implementation was rather straight forward.
However I forgot to RTFM again and did not configure my program prior to start and was wondering why test cases passed and the program failed.
The major challenge for part 2 was to figure out how I can clone a list in ruby to make sure that each program execution really starts with a clean memory.
def op(program, ptr)
opcode = program[ptr]
# puts "Running opcode:%d on pos:%d" % [opcode, ptr]
case opcode
when 99
return 1
when 1..2
if (program.length - 1) <= ptr + 3
return -2
end
in1 = program[ptr+1]
in2 = program[ptr+2]
out = program[ptr+3]
if opcode == 1
program[out] = program[in1] + program[in2]
elsif opcode == 2
program[out] = program[in1] * program[in2]
end
return 0
else
return -1
end
end
def run_to_termination(program)
ptr = 0
while op(program, ptr) == 0
ptr += 4
end
return program[0]
end
def try_parameter(program, arg1, arg2)
prog_copy = Array.new(program)
prog_copy[1] = arg1
prog_copy[2] = arg2
res = run_to_termination(prog_copy)
# puts "Ran %d, %d = %d" % [arg1, arg2, res]
res
end
def part1(program)
program[1] = 12
program[2] = 2
run_to_termination(program)
end
def part2(program)
noun = 0
verb = 0
while try_parameter(program, noun, verb) != 19690720
noun += 1
if noun > 99
noun = 0
verb += 1
end
if noun == 99 && verb == 99
puts "No solution found"
exit(1)
end
end
return 100 * noun + verb
end
if caller.length == 0
input = File.read("./input.txt")
program = input.split(",").map(&:to_i)
puts "Solution for part1: %d" % part1(Array.new(program))
puts "Solution for part2: %d" % part2(Array.new(program))
end
require "test/unit"
require_relative './solution'
class TestSolution < Test::Unit::TestCase
def test_required_fuel
d = {
3500 => [1,9,10,3,2,3,11,0,99,30,40,50],
30 => [1,1,1,4,99,5,6,0,99]
}
d.each{ |result, program|
assert_equal result, run_to_termination(program), "Incorrect result for input" % program
}
end
end
Puzzle: Crossed Wires
This was another challenge where having participated previously makes the solution process a lot easier. Having thought about similar problems I quickly decided to create a write:
a parser for the wire paths
create a hashmap with key=gridpoint and value=wires passing
after parsing all wires, check the entire hashmaps for keys where multiple wires passed
identify crossing with smallest manhattan distance
Playing around with classes in Ruby I learned a lot of interesting things:
you can overload +
and ==
operators which allows you to define the behavior of simple additions and comparisons
class properties do not have accessory by default
when put
(printing) a class instance it is automatically turned to a string if the to_s
method is implemented
#!/usr/bin/ruby
require_relative './geom'
# take a wire and return a hash with Point->wire ID for each point the wire crossed
# if a hash was passed it will be modified in place, otherwise a blank one will be created
def parseWire(wire, wireID, map = Hash.new)
pos = Point.new(0, 0)
steps = 0
for instruction in wire
delta = Point.new(0, 0)
dir = instruction[0]
length = instruction[1..-1].to_i
case dir
when 'R'
delta.x = 1
when 'D'
delta.y = -1
when 'L'
delta.x = -1
when 'U'
delta.y = 1
else
raise "Unexpected direction instruction %s" % dir
end
while length > 0
map[pos.to_s] = [wireID + "-" + steps.to_s].concat(map[pos.to_s] || Array.new())
pos = pos + delta
length -= 1
steps += 1
end
end
return map
end
def part1(wires)
map = Hash.new
wireID = 1
for wire in wires
parseWire(wire, wireID.to_s, map)
wireID += 1
end
closestPoint = nil
shortestDistance = 1/0.0 # infinity
origin = Point.new(0, 0)
map.each do |key, value|
if value.find {|item| item.include?("1-")} && value.find {|item| item.include?("2-")}
p1 = Point.from_s(key)
distance = p1.manhattan(origin)
if distance < shortestDistance && p1 != origin
closestPoint = p1
shortestDistance = distance
end
end
end
shortestDistance
end
def part2(wires)
map = Hash.new
wireID = 1
for wire in wires
parseWire(wire, wireID.to_s, map)
wireID += 1
end
closestPoint = nil
shortestDistance = 1/0.0 # infinity
origin = Point.new(0, 0)
map.each do |key, value|
if value.find {|item| item.include?("1-")} && value.find {|item| item.include?("2-")}
p1 = Point.from_s(key)
steps1 = value.select {|item| item.include?("1-")}.map{|item| item[2..-1].to_i}.reduce(1/0.0){|prev, cur| prev = cur if cur < prev}
steps2 = value.select {|item| item.include?("2-")}.map{|item| item[2..-1].to_i}.reduce(1/0.0){|prev, cur| prev = cur if cur < prev}
distance = steps1 + steps2
if distance < shortestDistance && p1 != origin
closestPoint = p1
shortestDistance = distance
end
end
end
shortestDistance
end
if caller.length == 0
input = File.read("./input.txt")
wires = input.split("\n").map{ |wire| wire.split(",") }
puts "Solution for part1: %d" % part1(wires)
puts "Solution for part2: %d" % part2(wires)
end
To calculate the length of the wires until they cross I simply added the wire length to the Hash map from part 1. That way at each position on the grid I can identify if a wire is there and how many steps the wire took to get there. Using the same method to identify crossings I simply changed the selection logic to take into account the wire length instead of the manhattan distance.
#!/usr/bin/ruby
require_relative './geom'
# take a wire and return a hash with Point->wire ID for each point the wire crossed
# if a hash was passed it will be modified in place, otherwise a blank one will be created
def parseWire(wire, wireID, map = Hash.new)
pos = Point.new(0, 0)
steps = 0
for instruction in wire
delta = Point.new(0, 0)
dir = instruction[0]
length = instruction[1..-1].to_i
case dir
when 'R'
delta.x = 1
when 'D'
delta.y = -1
when 'L'
delta.x = -1
when 'U'
delta.y = 1
else
raise "Unexpected direction instruction %s" % dir
end
while length > 0
map[pos.to_s] = [wireID + "-" + steps.to_s].concat(map[pos.to_s] || Array.new())
pos = pos + delta
length -= 1
steps += 1
end
end
return map
end
def part1(wires)
map = Hash.new
wireID = 1
for wire in wires
parseWire(wire, wireID.to_s, map)
wireID += 1
end
closestPoint = nil
shortestDistance = 1/0.0 # infinity
origin = Point.new(0, 0)
map.each do |key, value|
if value.find {|item| item.include?("1-")} && value.find {|item| item.include?("2-")}
p1 = Point.from_s(key)
distance = p1.manhattan(origin)
if distance < shortestDistance && p1 != origin
closestPoint = p1
shortestDistance = distance
end
end
end
shortestDistance
end
def part2(wires)
map = Hash.new
wireID = 1
for wire in wires
parseWire(wire, wireID.to_s, map)
wireID += 1
end
closestPoint = nil
shortestDistance = 1/0.0 # infinity
origin = Point.new(0, 0)
map.each do |key, value|
if value.find {|item| item.include?("1-")} && value.find {|item| item.include?("2-")}
p1 = Point.from_s(key)
steps1 = value.select {|item| item.include?("1-")}.map{|item| item[2..-1].to_i}.reduce(1/0.0){|prev, cur| prev = cur if cur < prev}
steps2 = value.select {|item| item.include?("2-")}.map{|item| item[2..-1].to_i}.reduce(1/0.0){|prev, cur| prev = cur if cur < prev}
distance = steps1 + steps2
if distance < shortestDistance && p1 != origin
closestPoint = p1
shortestDistance = distance
end
end
end
shortestDistance
end
if caller.length == 0
input = File.read("./input.txt")
wires = input.split("\n").map{ |wire| wire.split(",") }
puts "Solution for part1: %d" % part1(wires)
puts "Solution for part2: %d" % part2(wires)
end
require "test/unit"
require_relative './solution'
class TestSolution < Test::Unit::TestCase
def test_manhattan
assert_equal 3, Point.new(0,0).manhattan(Point.new(3, 0))
assert_equal 5, Point.new(0,-2).manhattan(Point.new(3, 0))
assert_equal 7+4, Point.new(10,4).manhattan(Point.new(3, 0))
end
def test_point_add
assert Point.new(3,3) == Point.new(1, 1) + Point.new(2, 2)
end
def test_point_from_s
assert Point.from_s("(x:3,y:4)") == Point.new(3, 4)
assert Point.from_s("(x:153,y:246)") == Point.new(153, 246)
end
def test_part1
d = {
6 => [['R8','U5','L5','D3'], ['U7','R6','D4','L4']],
159 => [['R75','D30','R83','U83','L12','D49','R71','U7','L72'],
['U62','R66','U55','R34','D71','R55','D58','R83']],
135 => [['R98','U47','R26','D63','R33','U87','L62','D20','R33','U53','R51'],
['U98','R91','D20','R16','D67','R40','U7','R15','U6','R7']]
}
d.each{ |score, input|
assert_equal score, part1(input)
}
end
def test_part2
d = {
30 => [['R8','U5','L5','D3'], ['U7','R6','D4','L4']],
610 => [['R75','D30','R83','U83','L12','D49','R71','U7','L72'],
['U62','R66','U55','R34','D71','R55','D58','R83']],
410 => [['R98','U47','R26','D63','R33','U87','L62','D20','R33','U53','R51'],
['U98','R91','D20','R16','D67','R40','U7','R15','U6','R7']]
}
d.each{ |score, input|
assert_equal score, part2(input)
}
end
end
Puzzle: Secure Container
AHHHHHHHH! Forgot to add the .length
and always tried to fix my code but the problem was in outputting the length of solutions correctly 😨
To run the solution use
#!/usr/bin/ruby
def is_decreasing(number)
diff = diff_vector(number)
return diff.find{|e| e < 0} != nil
end
def is_valid(number)
diff = diff_vector(number)
has_dupe = diff.find{|e| e == 0} != nil
has_dupe && !is_decreasing(number)
end
def has_real_dupes(number)
map = Hash.new()
digits = number.to_s.split("")
for digit in digits
if map[digit] == nil
map[digit] = 1
else
map[digit] += 1
end
end
for digit in digits
if map[digit] == 2
return true
end
end
return false
end
def is_valid_p2(number)
diff = diff_vector(number)
is_decreasing = diff.find{|e| e < 0} != nil
has_real_dupes(number) && !is_decreasing
end
def diff_vector(number)
arr = number.to_s.split("").map(&:to_i)
arr[1..-1].map.with_index{|e,ix| e - arr[ix]} # arr[ix] = previous element because index in map starts with an offset
end
def part1(start, stop)
(start..stop).select{|n| is_valid(n)}.length
end
def part2(start, stop)
(start..stop).select{|n| !is_decreasing(n) && has_real_dupes(n)}.length
end
if caller.length == 0
puts "Solution for part1: %d" % part1(245318, 765747)
puts "Solution for part2: %d" % part2(245318, 765747)
end
require "test/unit"
require_relative './solution'
class TestSolution < Test::Unit::TestCase
def test_is_decreasing
d = {
321 => true,
123456 => false,
222222 => false,
412341 => true,
65555 => true,
12345 => false
}
d.each{ |input, result|
assert_equal result, is_decreasing(input), "for input %d" % input
}
end
def test_is_valid
d = {
111111 => true,
223450 => false,
123789 => false
}
d.each{ |input, result|
assert_equal result, is_valid(input)
}
end
def test_is_valid_p2
d = {
111111 => false,
223450 => false,
112233 => true,
22 => true,
444 => false,
123789 => false,
111122 => true,
1111222447789 => true,
1111 => false,
123444 => false
}
d.each{ |input, result|
assert_equal result, is_valid_p2(input), "wrong result for input %d" % input
}
end
def test_has_real_dupes
d = {
111111 => false,
223450 => true,
112233 => true,
22 => true,
444 => false,
123789 => false,
111122 => true,
1111222447789 => true,
1111 => false,
123444 => false
}
d.each{ |input, result|
assert_equal result, has_real_dupes(input), "wrong result for input %d" % input
}
end
end
Puzzle: Sunny with a Chance of Asteroids
Luckily I could re-use a lot of day2 code. The main changes were adding new opcodes and initially splitting the opcode and modes from the command instruction.
Another minor tweak was to modify my op(program, ptr)
method to return a variable pointer offset.
During day02 I used the return value of op()
and treated it like a program return code in bash - meaning 0 = ok and everything else leads to an error.
With day05 every return code >= 0 is a valid return code, where the returned number equals the steps the pointer needs to take.
Negative return codes result in errors caused by unknown opcodes or parsing errors - happened a few times during building this solution 🙄
This was not really a challenge and only meant implementing a few more instructions into my op()
method.
To run the solution use ruby solution.rb
def op(program, ptr)
cmd = program[ptr]
opcode = cmd % 100
modes = Array.new()
modes[2] = cmd / 10000
modes[1] = cmd % 10000 / 1000
modes[0] = cmd % 1000 / 100
puts "Running opcode:%d on pos:%d with modes:%s from cmd:%d" % [opcode, ptr, modes.map(&:to_s).join(","), cmd]
case opcode
when 99
return 0
when 1..8
if opcode == 1
in1 = modes[0] == 1 ? program[ptr+1] : program[program[ptr+1]] # switch between position mode (0) and immediate/value mode (1)
in2 = modes[1] == 1 ? program[ptr+2] : program[program[ptr+2]]
out = program[ptr+3]
program[out] = in1 + in2
return 4
elsif opcode == 2
in1 = modes[0] == 1 ? program[ptr+1] : program[program[ptr+1]] # switch between position mode (0) and immediate/value mode (1)
in2 = modes[1] == 1 ? program[ptr+2] : program[program[ptr+2]]
out = program[ptr+3]
program[out] = in1 * in2
return 4
elsif opcode == 3
out = program[ptr+1]
puts "Please provide numeric input:"
in1 = gets.to_i
puts "Storing %d at position %d" % [in1, out]
program[out] = in1
return 2
elsif opcode == 4
in1 = modes[0] == 1 ? program[ptr+1] : program[program[ptr+1]] # switch between position mode (0) and immediate/value mode (1)
puts "Running output for ptr:%d mode:%d at:%d" % [ptr, modes[0], program[ptr+1]]
puts "Output: %d" % in1
return 2
elsif opcode == 5
in1 = modes[0] == 1 ? program[ptr+1] : program[program[ptr+1]] # switch between position mode (0) and immediate/value mode (1)
in2 = modes[1] == 1 ? program[ptr+2] : program[program[ptr+2]]
if in1 > 0
return in2 - ptr
else
return 3
end
elsif opcode == 6
in1 = modes[0] == 1 ? program[ptr+1] : program[program[ptr+1]] # switch between position mode (0) and immediate/value mode (1)
in2 = modes[1] == 1 ? program[ptr+2] : program[program[ptr+2]]
if in1 == 0
return in2 - ptr
else
return 3
end
elsif opcode == 7
in1 = modes[0] == 1 ? program[ptr+1] : program[program[ptr+1]] # switch between position mode (0) and immediate/value mode (1)
in2 = modes[1] == 1 ? program[ptr+2] : program[program[ptr+2]]
out = program[ptr+3]
if in1 < in2
program[out] = 1
else
program[out] = 0
end
return 4
elsif opcode == 8
in1 = modes[0] == 1 ? program[ptr+1] : program[program[ptr+1]] # switch between position mode (0) and immediate/value mode (1)
in2 = modes[1] == 1 ? program[ptr+2] : program[program[ptr+2]]
out = program[ptr+3]
if in1 == in2
program[out] = 1
else
program[out] = 0
end
return 4
end
else
puts "Unknown opcode: %d" % opcode
return -1 # unknown opcode (not 1..4)
end
end
def run_to_termination(program)
puts program.length
ptr = 0
step = op(program, ptr)
while step > 0
ptr += step
step = op(program, ptr)
end
if step < 0
throw "Unexpected error occured: %d" % step
end
end
def part1(program)
run_to_termination(program)
end
if caller.length == 0
input = File.read("./input.txt")
program = input.split(",").map(&:to_i)
puts "Running part1.."
part1(Array.new(program))
puts "..Done"
# puts "Solution for part2: %d" % part2(Array.new(program))
end
Unresolved directive in ../../../../../../day05/ruby/anoff/README.adoc - include::solution_test.rb[]
Puzzle: Universal Orbit Map
At first I thought this would require implementing a full graph solution again. However after studying the first part of the challenge I thought a simple hash map could also do the trick so I tried. Going from method to method in my head I built them using TDD on a unit test level to make sure the piece do their job correctly. Finally I implemented the overall testcase of check the overall functionality (excluding parsing the input file).
def test_total_orbit_count
d = {
["COM)B",
"B)C",
"C)D",
"D)E",
"E)F",
"B)G",
"G)H",
"D)I",
"E)J",
"J)K",
"K)L"] => 42
}
d.each{ |input, result|
map = build_map(input)
assert_equal result, total_orbit_count(map), "for input %s" % input
}
end
For part two I thought about how to implement this with my one-way graph implementation that only allows me to go from satellite to its center of orbit. My approach for this explicit problem was to just start with me and walk through my orbital path back to the center of mass. For each orbit I pass I check if this is also on santas way to the COM. If there is an overlap, that is the intermediate destination I need to go to before following SANta.
The actual result is calcualted by using array operations to identify the intersection of mine and santas path.
Using the .each_with_index
array operation in Ruby it is easy to get the index (count) of array elements that are in between me and the common orbit.
def part2(map_data)
orbit_map = build_map(map_data)
target_center = orbit_map["SAN"] # the object we want to orbit as well
santas_orbits = get_orbit_centers(orbit_map, "SAN")
my_orbits = get_orbit_centers(orbit_map, "YOU")
first_common_center = my_orbits.each_with_index.find{|(center, ix)| santas_orbits.include?(center)}
my_hops_to_common_center = first_common_center[1] # the index of the array
hops_from_common_to_santa = santas_orbits.each_with_index.find{|(center, ix)| center == first_common_center[0]}[1]
my_hops_to_common_center + hops_from_common_to_santa
end
To run the solution use ruby solution.py
#!/usr/bin/ruby
# the orbit map points from satellite to its orbit center
def build_map(map_data)
map = Hash.new()
for entry in map_data
parts = entry.split(")")
center = parts[0]
satellite = parts[1]
map[satellite] = center
end
map
end
# calculate how many orbits a single satellite has in relation to the center of mass
def orbit_count(orbit_map, satellite)
count = 0
while satellite = orbit_map[satellite]
count += 1
end
count
end
# total sum of orbits of all satellites in the system
def total_orbit_count(orbit_map)
count = 0
orbit_map.each{|satellite, _|
central_objects = orbit_count(orbit_map, satellite)
# puts "Satellite %s orbits %d objects" % [satellite, central_objects]
count += central_objects
}
count
end
def part1(map_data)
map = build_map(map_data)
total_orbit_count(map)
end
def get_orbit_centers(orbit_map, satellite)
centers = []
while satellite = orbit_map[satellite]
centers.push(satellite)
end
centers
end
# tag::p2[]
def part2(map_data)
orbit_map = build_map(map_data)
target_center = orbit_map["SAN"] # the object we want to orbit as well
santas_orbits = get_orbit_centers(orbit_map, "SAN")
my_orbits = get_orbit_centers(orbit_map, "YOU")
first_common_center = my_orbits.each_with_index.find{|(center, ix)| santas_orbits.include?(center)}
my_hops_to_common_center = first_common_center[1] # the index of the array
hops_from_common_to_santa = santas_orbits.each_with_index.find{|(center, ix)| center == first_common_center[0]}[1]
my_hops_to_common_center + hops_from_common_to_santa
end
# end::p2[]
if caller.length == 0
input = File.read("./input.txt")
data = input.split("\n")
puts "Solution for part1: %d" % part1(data)
puts "Solution for part2: %d" % part2(data)
end
require "test/unit"
require_relative './solution'
class TestSolution < Test::Unit::TestCase
def test_build_map
d = {
["COM)B",
"B)C",
"C)D"] => { "D"=>"C", "C"=>"B", "B"=>"COM"},
["COM)B",
"B)C",
"C)D",
"B)E"] => { "E"=>"B", "D"=>"C", "C"=>"B", "B"=>"COM"}
}
d.each{ |input, result|
assert_equal result, build_map(input), "for input %s" % input
}
end
def test_orbit_count
map_data = ["COM)B",
"B)C",
"C)D",
"D)E",
"E)F",
"B)G",
"G)H",
"D)I",
"E)J",
"J)K",
"K)L"]
d = {
"B" => 1,
"D" => 3,
"L" => 7,
"COM" => 0
}
map = build_map(map_data)
d.each{ |input, result|
assert_equal result, orbit_count(map, input), "for input %s" % input
}
end
# tag::full_tdd[]
def test_total_orbit_count
d = {
["COM)B",
"B)C",
"C)D",
"D)E",
"E)F",
"B)G",
"G)H",
"D)I",
"E)J",
"J)K",
"K)L"] => 42
}
d.each{ |input, result|
map = build_map(input)
assert_equal result, total_orbit_count(map), "for input %s" % input
}
end
# end::full_tdd[]
end