working to compute a single program that meets the target output
This commit is contained in:
parent
78b45a84cc
commit
69784ff0de
55
genetic.rb
55
genetic.rb
@ -1,3 +1,58 @@
|
|||||||
#!/usr/bin/env ruby
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
require_relative "program"
|
require_relative "program"
|
||||||
|
|
||||||
|
NUM_PROGRAMS = 100
|
||||||
|
EXPECTED_OUTPUT = "HELLOWORLD"
|
||||||
|
|
||||||
|
def ord(chr)
|
||||||
|
chr.unpack("C").first
|
||||||
|
end
|
||||||
|
|
||||||
|
def grade_program(p)
|
||||||
|
output = p.execute
|
||||||
|
grade = (EXPECTED_OUTPUT.size - output.size).abs * 100
|
||||||
|
[EXPECTED_OUTPUT.size, output.size].min.times do |i|
|
||||||
|
grade += (ord(EXPECTED_OUTPUT[i]) - ord(output[i])).abs
|
||||||
|
end
|
||||||
|
grade
|
||||||
|
end
|
||||||
|
|
||||||
|
def main
|
||||||
|
programs = NUM_PROGRAMS.times.map do
|
||||||
|
p = Program.new
|
||||||
|
[grade_program(p), p]
|
||||||
|
end
|
||||||
|
generation = 0
|
||||||
|
begin
|
||||||
|
last_best = nil
|
||||||
|
while true
|
||||||
|
generation += 1
|
||||||
|
programs += programs.map do |grade, p|
|
||||||
|
p2 = p.clone
|
||||||
|
p2.mutate
|
||||||
|
[grade_program(p2), p2]
|
||||||
|
end
|
||||||
|
programs.sort! do |a, b|
|
||||||
|
a.first <=> b.first
|
||||||
|
end
|
||||||
|
programs = programs.take(NUM_PROGRAMS)
|
||||||
|
if last_best.nil? or programs.first.first < last_best
|
||||||
|
last_best = programs.first.first
|
||||||
|
$stdout.write("\rGrade: #{last_best}, output: #{programs.first.last.execute.inspect} ")
|
||||||
|
end
|
||||||
|
if programs.first.first == 0
|
||||||
|
puts "Program found after #{generation} generations:"
|
||||||
|
puts programs.first.last
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
rescue Interrupt
|
||||||
|
puts
|
||||||
|
puts "Canceled at #{generation} generations"
|
||||||
|
puts "The best program (grade #{programs.first.first}) is:"
|
||||||
|
puts programs.first.last
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
main
|
||||||
|
60
program.rb
60
program.rb
@ -6,15 +6,8 @@ class Program
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
def initialize_copy(other)
|
||||||
|
@instructions = Marshal.load(Marshal.dump(@instructions))
|
||||||
def random_instruction
|
|
||||||
case rand(2)
|
|
||||||
when 0
|
|
||||||
[:load, (65 + rand(26)).chr]
|
|
||||||
when 1
|
|
||||||
[:output]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
@ -29,5 +22,54 @@ class Program
|
|||||||
end
|
end
|
||||||
|
|
||||||
def execute
|
def execute
|
||||||
|
output = ""
|
||||||
|
register = "A"
|
||||||
|
@instructions.each do |instruction, *params|
|
||||||
|
case instruction
|
||||||
|
when :load
|
||||||
|
register = params.first
|
||||||
|
when :output
|
||||||
|
output += register
|
||||||
|
end
|
||||||
|
end
|
||||||
|
output
|
||||||
|
end
|
||||||
|
|
||||||
|
def mutate
|
||||||
|
case rand(4)
|
||||||
|
when 0 # remove an instruction
|
||||||
|
if @instructions.size > 1
|
||||||
|
i = rand(@instructions.size)
|
||||||
|
@instructions.delete_at(i)
|
||||||
|
end
|
||||||
|
when 1 # insert an instruction
|
||||||
|
i = rand(@instructions.size + 1)
|
||||||
|
@instructions.insert(i, random_instruction)
|
||||||
|
when 2 # replace an instruction
|
||||||
|
i = rand(@instructions.size)
|
||||||
|
@instructions[i] = random_instruction
|
||||||
|
when 3 # modify parameter
|
||||||
|
i = rand(@instructions.size)
|
||||||
|
if @instructions[i].first == :load
|
||||||
|
@instructions[i][1] = mutate_param(@instructions[i][1])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def random_instruction
|
||||||
|
case rand(2)
|
||||||
|
when 0
|
||||||
|
[:load, (65 + rand(26)).chr]
|
||||||
|
when 1
|
||||||
|
[:output]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def mutate_param(old_value)
|
||||||
|
chr = old_value.unpack("C").first
|
||||||
|
chr = (chr + (rand(2) + 1) * [-1, 1][rand(2)]) % 26
|
||||||
|
chr.chr
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user