Skip to content

Commit

Permalink
Post contest commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
JEG2 committed Jun 29, 2009
0 parents commit 827ceea
Show file tree
Hide file tree
Showing 42 changed files with 1,309 additions and 0 deletions.
23 changes: 23 additions & 0 deletions README
@@ -0,0 +1,23 @@
This code was generated by James Edward Gray II and Edward Livengood (Team J-Ed-I) for the 2009 ICFP programming contest:

http://icfpcontest.org/

We have participated in previous years with the help of our friends:

http://grayproductions.net/icfp08/
http://grayproductions.net/icfp07/
http://grayproductions.net/icfp04/

We had pretty limited time this year and less help, so this solution only works for five of the provided scenarios. You can run those with these commands from the root project directory:

bin/j_ed_i 1001
bin/j_ed_i 1002
bin/j_ed_i 1003
bin/j_ed_i 1004
bin/j_ed_i 2001

Each run generates images and solutions, in the so named directories. This code requires a Ruby 1.8 install (only tested with 1.8.6).

You can also see movies we have recorded of the solutions in the videos directory. These are just animated Gif files that should be viewable in most modern browsers. The two without scenario number names are our best bloopers recorded from buggy runs.

Though we had limited resources this year and didn't do too well, we had a great time and enjoyed the problem. Thanks you organizers for another great challenge!
48 changes: 48 additions & 0 deletions bin/j_ed_i
@@ -0,0 +1,48 @@
#!/usr/bin/env ruby -wKU

$LOAD_PATH << File.join(File.dirname(__FILE__), *%w[.. lib])
require "j_ed_i"

options = {:configuarion => nil, :svg => true, :frequency => 500}
ARGV.options do |opts|
opts.banner = "Usage: #{File.basename($PROGRAM_NAME)} [OPTIONS] CONFIG"
opts.separator ""
opts.separator "Specific Options:"
opts.on( "-s", "--[no-]svg",
"Used to turn off image generation." ) do |svg|
options[:svg] = svg
end
opts.on( "-f", "--frequency TURNS", Integer,
"The turn frequency of image generation." ) do |frequency|
if frequency < 1
options[:svg] = false
else
options[:frequency] = frequency
end
end
opts.separator "Common Options:"
opts.on( "-h", "--help",
"Show this message." ) do
puts opts
exit
end
begin
opts.parse!
raise unless configuarion = ARGV.shift
options[:configuarion] = configuarion.to_i
rescue
puts opts
exit
end
end

if options[:svg] and (JEdI::IMAGES_DIR + "0000000000.svg").exist?
system("rm #{JEdI::IMAGES_DIR + '*.svg'}")
end

unless program_class = JEdI::Program.for_configuration(options[:configuarion])
abort "Error: CONFIG not recognized."
end
program = program_class.new(options[:configuarion], options)
program.run
puts "\aFinal Score: #{program.score}"
Binary file added doc/.DS_Store
Binary file not shown.
Binary file added doc/task-1.7.pdf
Binary file not shown.
35 changes: 35 additions & 0 deletions lib/j_ed_i.rb
@@ -0,0 +1,35 @@
#!/usr/bin/env ruby -wKU

# standarad library
require "pathname"
require "optparse"

module JEdI
DIR = Pathname.new( File.join( File.dirname(__FILE__),
".." ) )
PROBLEMS_DIR = DIR + "problems"
SOLUTIONS_DIR = DIR + "solutions"
IMAGES_DIR = DIR + "images"
PROGRAM_DIR = JEdI::DIR.join(*%w[lib j_ed_i program])

TEAM_ID = 97

X_PORT = 2
Y_PORT = 3
CONFIGURATION_INPUT_PORT = 0x3E80
SCORE_OUTPUT_PORT = 0
FUEL_OUTPUT_PORT = 1
end

# vendored
require JEdI::DIR.join(*%w[vendor svg_image lib svg])

# our code
require "j_ed_i/vm"
require "j_ed_i/opcode"
require "j_ed_i/radar"
require "j_ed_i/program"
JEdI::PROGRAM_DIR.each_entry do |program|
require JEdI::PROGRAM_DIR + program if program.extname == ".rb"
end
require "j_ed_i/solution"
92 changes: 92 additions & 0 deletions lib/j_ed_i/opcode.rb
@@ -0,0 +1,92 @@
#!/usr/bin/env ruby -wKU

module JEdI
class Opcode
attr_reader :r1

def execute(vm)
send(self.class.const_get(:OPS)[@op], vm)
end

private

def read(opcode, pattern)
("%032b" % opcode.unpack("V")).unpack(pattern).map { |n| n.to_i(2) }
end
end

class DTypeOpcode < Opcode
OPS = [nil] + %w[add sub mult div output phi]

def initialize(opcode)
@op, @r1, @r2 = read(opcode, "a4a14a14")
raise "Unexpected DType OP %p (%p)" % [@op, opcode] \
if not @op.between? 1, 6
end

attr_reader :r2

private

def add(vm)
vm.data[@r1] + vm.data[@r2]
end

def sub(vm)
vm.data[@r1] - vm.data[@r2]
end

def mult(vm)
vm.data[@r1] * vm.data[@r2]
end

def div(vm)
return 0.0 if vm.data[@r2] == 0.0
vm.data[@r1] / vm.data[@r2]
end

def output(vm)
vm.write_output(@r1, vm.data[@r2])
nil # don't update data
end

def phi(vm)
vm.data[vm.status? ? @r1 : @r2]
end
end

class STypeOpcode < Opcode
OPS = %w[noop cmpz sqrt copy input]
IMMS = %w[< <= == >= >]

def initialize(opcode)
@op, @imm, @r1 = read(opcode, "x4a4a3x7a14")
raise "Unexpected SType OP %p (%p)" % [@op, opcode] if @op > 4
raise "Unexpected SType IMM %p (%p)" % [@imm, opcode] \
if @op == 1 and @imm > 4
end

private

def noop(vm)
nil # don't update data
end

def cmpz(vm)
vm.status = vm.data[@r1].send(IMMS[@imm], 0.0)
nil # don't update data
end

def sqrt(vm)
Math.sqrt(vm.data[@r1].abs)
end

def copy(vm)
vm.data[@r1]
end

def input(vm)
vm.input_ports[@r1]
end
end
end
120 changes: 120 additions & 0 deletions lib/j_ed_i/program.rb
@@ -0,0 +1,120 @@
#!/usr/bin/env ruby -wKU

module JEdI
class Program
G = 6.67428 * 10 ** -11
M = 6 * 10 ** 24
GM = G * M

def self.subclasses
@subclasses ||= Array.new
end

def self.inherited(program)
subclasses << program
end

def self.for_configuration(configuration)
subclasses.find { |program|
configuration / 1000 == program::CONFIGURATION
}
end

def self.binary_path
PROBLEMS_DIR + "bin#{const_get(:CONFIGURATION)}.obf"
end

def initialize(configuration, options = Hash.new)
@vm = VM.new(self.class.binary_path, options)
@configuration = configuration
@score = nil
@fuel = nil
@x = nil
@y = nil

@initial_radius = nil
@delta_v = nil
@delta_v_prime = nil
@time_to_prime = nil
end

attr_reader :score

def run
@vm.configure(@configuration)
loop do
@vm.loop
update_satellite_statistics
break if @score.nonzero?
adjust_actuators
@vm.update
end
@vm.finish
end

private

def update_satellite_statistics
@score = @vm.output_ports[SCORE_OUTPUT_PORT]
@fuel = @vm.output_ports[FUEL_OUTPUT_PORT]
@x = @vm.output_ports[X_PORT]
@y = @vm.output_ports[Y_PORT]
end

def thrust(x, y)
@vm.write_input(X_PORT, x)
@vm.write_input(Y_PORT, y)
end

def calculate_hohmann_transfer
return if @delta_v and @delta_v_prime

@initial_radius = Math.sqrt(@x ** 2 + @y ** 2)

@delta_v = Math.sqrt(GM / @initial_radius) *
( Math.sqrt( 2 * @target_radius /
(@initial_radius + @target_radius) ) - 1 )
@delta_v_prime = Math.sqrt(GM / @target_radius) *
( 1 - Math.sqrt( 2 * @initial_radius /
(@initial_radius + @target_radius) ) )
@time_to_prime = ( Math::PI *
Math.sqrt( (@initial_radius + @target_radius) ** 3 /
(8 * GM) ) ).round
end

def fire_delta_v
calculate_hohmann_transfer
# thrust(*apply_thrust(@delta_v))
delta_x, delta_y = apply_thrust(@delta_v)
thrust(-delta_x, -delta_y)
@mode = :fire_delta_v_prime
end

def apply_thrust(delta)
if @x.zero?
raise "x = #{@x}, y = #{@y}"
else
radius_slope = @y / @x
tangent_slope = -1 / radius_slope
delta_x = Math.sqrt(delta ** 2 / (1 + tangent_slope ** 2))
delta_y = tangent_slope * delta_x
end
[delta_x, delta_y]
end

def fire_delta_v_prime
if (@time_to_prime -= 1) <= 0
# delta_x, delta_y = apply_thrust(@delta_v_prime)
# thrust(-delta_x, -delta_y)
thrust(*apply_thrust(@delta_v_prime))
@mode = :coast
else
coast
end
end

def coast
thrust(0.0, 0.0)
end
end
end
25 changes: 25 additions & 0 deletions lib/j_ed_i/program/hohmann.rb
@@ -0,0 +1,25 @@
#!/usr/bin/env ruby -wKU

module JEdI
class Program
class Hohmann < Program
CONFIGURATION = 1

def initialize(configuration, options = Hash.new)
super
@mode = :fire_delta_v
end

def adjust_actuators
update_target_radius
send(@mode)
end

private

def update_target_radius
@target_radius ||= @vm.output_ports[4]
end
end
end
end

0 comments on commit 827ceea

Please sign in to comment.