# balance.rb # 2006 David Baird # License: Public Domain ^_^ # # This program tries various combinations of instructions # to execute on the Balance computer architecture. The # goal is to bring Balance from some given initial state # to a desired final state. But doing this is kind of # like solving the rubics cube. # # The $weasel and $rabbites global variables are just some # data used to initialize the search process (so it doesn't # have to search *all* possibilities). # # This program really needs to be re-written to make more # complicated searches easier to perform. require 'scanf' require 'weasel' $rabbites = [[1, 2, 28, 1], [1, 4, 29, 1], [1, 5, 29, 1], [1, 6, 29, 1], [1, 27, 5, 31], [1, 27, 7, 31], [1, 27, 9, 30], [1, 27, 11, 30], [1, 27, 13, 30], [1, 27, 15, 30], [1, 29, 2, 28], [1, 29, 3, 28], [1, 29, 31, 1], [1, 29, 31, 5], [1, 29, 31, 9], [1, 29, 31, 13], [1, 29, 31, 17], [1, 29, 31, 21], [1, 29, 31, 25], [1, 29, 31, 29], [2, 4, 4, 24], [2, 4, 5, 24], [2, 8, 8, 20], [2, 8, 9, 20], [2, 8, 12, 20], [2, 8, 13, 20], [2, 12, 4, 16], [2, 12, 5, 16], [2, 28, 1, 28], [18, 1, 28, 28]] class Execute end class Instruction @@NAMES = [:science, :math, :logic, :physics, :die, :die, :die, :die] attr_accessor :opcode, :imm, :d, :s1, :s2, :raw def Instruction.math(d, s1, s2) x = new; x.opcode = 1; x.d = d; x.s1 = s1; x.s2 = s2; return x end def Instruction.logic(d, s1, s2) x = new; x.opcode = 2; x.d = d; x.s1 = s1; x.s2 = s2; return x end def Instruction.science(imm) x = new; x.opcode = 0; x.imm = imm; return x end def Instruction.physics(imm) x = new; x.opcode = 3; x.imm = imm; return x end def Instruction.die x = new; x.opcode = 4; x.d = d; x.s1 = s1; x.s2 = s2; return x end def name() @@NAMES[opcode] end def imm?() [:science, :physics].include? name end def d1() (d + 1) % 2 end def s11() (s1 + 1) % 4 end def s21() (s2 + 1) % 4 end def raw p name return opcode << 5 | imm if imm? return opcode << 5 | d << 4 | s1 << 2 | s2 end def raw=(x) opcode = x >> 5 imm = x & 31 d = (x >> 4) & 1 s1 = (x >> 2) & 3 s2 = (x >> 0) & 3 end def to_i() raw end end class Fixnum def as_int5 return self if self < 0x10 or self < 0 return -(32 - self) end end class Array def to_hex_s flatten.map { |x| '%02x' % x.to_i }.join('') end def to_umodem(filename) ("rm %s\n" % filename) + ("/bin/umodem %s STOP\n" % filename) + to_hex_s + "\nSTOP" end def mask_select(mask) select { |x| x = ((mask & 1) == 1); mask >>= 1; x } end def physics_prerotate(i) x = self[1..-1].mask_select(i) y = [self[0]] y + x end def physics_rotate(i) x = self[1..-1].mask_select(i) y = [self[0]] x + y end end class Register attr_accessor :d0, :d1, :s0, :s1, :s2, :s3 include Comparable def to_a [@s0, @d1, @d0, @s3, @s2, @s1] end def a=(x) @s0, @d1, @d0, @s3, @s2, @s1 = x end def dR=(x) @d0, @d1 = x end def dR [@d0, @d1] end def sR=(x) @s0, @s1, @s2, @s3 = x end def sR [@s0, @s1, @s2, @s3] end def <=>(other) to_a <=> other.to_a end def physics(i) x = [0, 1, 2, 3, 4, 5] a = x.physics_rotate i b = x.physics_prerotate i t1 = self.to_a t2 = self.to_a t1[0] += i.as_int5 a.each_index do |j| t2[a[j]] = t1[b[j]] end y = Register.new y.a = t2 y end def to_s "{ %s, %s, %s, %s } { %s, %s }" % [@s0, @s1, @s2, @s3, @d0, @d1] end def swap?(other) x = self.to_a y = other.to_a (0..4).each do |a| ((a+1)..5).each do |b| return true if x[a] == y[b] and x[b] == y[a] end end return false end end x = Register.new x.sR, x.dR = [0, 1, 2, 3], [4, 5] y = x.dup y.s0 = 44 p y == x puts x.physics(31).physics(31).physics(31).physics(2) def bruteforce_swapreg(foo = [0,1,2,3,4,5]) x = Register.new x.sR, x.dR = foo[0..3], foo[4..5] x.dR = [4, 5] result = [] (1..31).each do |a| #puts "%d..." % [a] (1..31).each do |b| #(1..31).each do |c| #(1..31).each do |d| y = x.physics(a).physics(b) #.physics(c).physics(d) #puts 'yay %d %d %s %s' % [a, b, x, y] if x.swap?(y) result << [a, b] if x.swap?(y) #end #end end end result end def bruteforce_swapreg3(foo = [0,1,2,3,4,5], combos=nil) x = Register.new x.sR, x.dR = foo[0..3], foo[4..5] result = [] if combos == nil then puts "Constructing combos" combos = [] (1..31).each do |a| #puts "%d..." % [a] (1..31).each do |b| (1..31).each do |c| (1..31).each do |d| combos << [a,b,c,d] end end end end puts "Done constructing combos" end combos.each do |(a,b,c,d)| y = x.physics(a).physics(b).physics(c).physics(d) #puts 'yay %d %d %s %s' % [a, b, x, y] if x.swap?(y) result << [a, b, c, d] if x.swap?(y) end result end def bruteforce_addmem2(foo = [0,1,2,3,4,5], combos=nil) x = Register.new x.sR, x.dR = foo[0..3], foo[4..5] result = [] if combos == nil then puts "Constructing combos" combos = [] (1..31).each do |a| #puts "%d..." % [a] (1..31).each do |b| (1..31).each do |c| (1..31).each do |d| combos << [a,b,c,d] end end end end puts "Done constructing combos" end combos.each do |(a,b,c,d)| y = x.physics(a).physics(b).physics(c).physics(d) #puts 'yay %d %d %s %s' % [a, b, x, y] if x.swap?(y) result << [a, b, c, d, y] if (y.sR.include? 0 and y.sR.include? 1 and y.dR.include? 2 and y.dR[0] == 2 and y.dR[1] == 2) end result end def bruteforce_swapmem(foo = [0,1,2,3,4,5], combos=nil) x = Register.new x.sR, x.dR = foo[0..3], foo[4..5] result = [] if combos == nil then puts "Constructing combos" combos = [] (1..31).each do |a| #puts "%d..." % [a] (1..31).each do |b| (0..0).each do |c| (0..0).each do |d| combos << [a,b,c,d] end end end end puts "Done constructing combos" end combos.each do |(a,b,c,d)| y = x.physics(a).physics(b).physics(c).physics(d) #puts 'yay %d %d %s %s' % [a, b, x, y] if x.swap?(y) result << [a, b, c, d, y] if (y.sR.include? 1 and y.sR.include? 3 and y.dR[0] != y.dR[1]) end result end def swapreg2_hackt result = bruteforce_swapreg3 [0,1,2,3,4,5], $weasel p result.size (1..5).each do |foo| p foo v = (0..5).map { |x| rand 100 } result &= bruteforce_swapreg3 v, result p result.size end p result[0] end #p bruteforce_swapreg()[0] #swapreg2_hackt #x = bruteforce_addmem2()[0] #p x #puts x[4] # >>> # [2, 28, 0, 0, #] # { 1, 2, 3, 0 } { 2, 5 } #x = bruteforce_addmem2([0,1,2,3,4,5], $rabbites)[0] #p x #puts x[4] # >>> #[2, 28, 1, 28, #] #{ 2, 3, 0, 1 } { 2, 2 } #x = bruteforce_swapmem() #p x #puts x[0][4] # >>> # [1, 30, 0, 0, #] # { 1, 2, 3, 4 } { 3, 1 } #getc rotate_madness = ['sR[0]', 'dR[1]', 'dR[0]', 'sR[3]', 'sR[2]', 'sR[1]'] (0..31).each do |x| puts "%2d: %s" % [x, rotate_madness.physics_prerotate(x)] puts " %s" % [rotate_madness.physics_rotate(x)] end I = Instruction tight_loop = I.science 0 # ...only if M[ sR[0] ] == 0 p_stop = [ (I.physics 16), tight_loop, ] puts p_stop.to_umodem "p_stop" " rm p_stop /bin/umodem p_stop STOP 7000 STOP step_balance stop p_stop certify stop p_stop " p_stop127 = [ (I.physics 1), tight_loop, ] puts p_stop127.to_umodem "p_stop127" " rm p_stop127 /bin/umodem p_stop127 STOP 6100 STOP certify stop127 p_stop127 " #p_copymem = [ #] #puts p_stopmem.to_umodem "p_copymem" #" #" p_copyreg = [ (I.physics 1), (I.physics 2), tight_loop, ] puts p_copyreg.to_umodem "p_copyreg" " " p_swapmem = [ (I.physics 1), (I.physics 30), #(I.logic 1), tight_loop, ] puts p_swapmem.to_umodem "p_swapmem" " " p_swapreg = [ (I.physics 1), (I.physics 19), tight_loop, ] puts p_swapreg.to_umodem "p_swapreg" " rm p_swapreg /bin/umodem p_swapreg STOP 617300 STOP " p_swapreg2 = [ (I.physics 1), (I.physics 1), (I.physics 31), (I.physics 7), tight_loop, ] puts p_swapreg2.to_umodem "p_swapreg2" " rm p_swapreg2 /bin/umodem p_swapreg2 STOP 61617f6700 STOP " p_addmem2 = [ (I.physics 2), (I.physics 28), (I.physics 1), (I.physics 28), (I.math 0, 2, 3), tight_loop, ] puts p_addmem2.to_umodem "p_addmem2" " rm p_addmem2 /bin/umodem p_addmem2 STOP 627c617c2b00 STOP "