ICFP Contest 2006
Team: Abstraction Anonymous

balance.rb

Download

  1. # balance.rb
  2. # 2006 David Baird
  3. # License: Public Domain ^_^
  4. #
  5. # This program tries various combinations of instructions
  6. # to execute on the Balance computer architecture. The
  7. # goal is to bring Balance from some given initial state
  8. # to a desired final state. But doing this is kind of
  9. # like solving the rubics cube.
  10. #
  11. # The $weasel and $rabbites global variables are just some
  12. # data used to initialize the search process (so it doesn't
  13. # have to search *all* possibilities).
  14. #
  15. # This program really needs to be re-written to make more
  16. # complicated searches easier to perform.
  17.  
  18. require 'scanf'
  19. require 'weasel'
  20.  
  21. $rabbites = [[1, 2, 28, 1], [1, 4, 29, 1], [1, 5, 29, 1], [1, 6, 29, 1],
  22. [1, 27, 5, 31], [1, 27, 7, 31], [1, 27, 9, 30], [1, 27, 11, 30], [1, 27,
  23. 13, 30], [1, 27, 15, 30], [1, 29, 2, 28], [1, 29, 3, 28], [1, 29, 31,
  24. 1], [1, 29, 31, 5], [1, 29, 31, 9], [1, 29, 31, 13], [1, 29, 31, 17],
  25. [1, 29, 31, 21], [1, 29, 31, 25], [1, 29, 31, 29], [2, 4, 4, 24], [2,
  26. 4, 5, 24], [2, 8, 8, 20], [2, 8, 9, 20], [2, 8, 12, 20], [2, 8, 13, 20],
  27. [2, 12, 4, 16], [2, 12, 5, 16], [2, 28, 1, 28], [18, 1, 28, 28]]
  28.  
  29. class Execute
  30. end
  31.  
  32. class Instruction
  33. @@NAMES = [:science, :math, :logic, :physics, :die, :die, :die, :die]
  34. attr_accessor :opcode, :imm, :d, :s1, :s2, :raw
  35. def Instruction.math(d, s1, s2)
  36. x = new; x.opcode = 1; x.d = d; x.s1 = s1; x.s2 = s2; return x
  37. end
  38. def Instruction.logic(d, s1, s2)
  39. x = new; x.opcode = 2; x.d = d; x.s1 = s1; x.s2 = s2; return x
  40. end
  41. def Instruction.science(imm)
  42. x = new; x.opcode = 0; x.imm = imm; return x
  43. end
  44. def Instruction.physics(imm)
  45. x = new; x.opcode = 3; x.imm = imm; return x
  46. end
  47. def Instruction.die
  48. x = new; x.opcode = 4; x.d = d; x.s1 = s1; x.s2 = s2; return x
  49. end
  50. def name() @@NAMES[opcode] end
  51. def imm?() [:science, :physics].include? name end
  52. def d1() (d + 1) % 2 end
  53. def s11() (s1 + 1) % 4 end
  54. def s21() (s2 + 1) % 4 end
  55. def raw
  56. p name
  57. return opcode << 5 | imm if imm?
  58. return opcode << 5 | d << 4 | s1 << 2 | s2
  59. end
  60. def raw=(x)
  61. opcode = x >> 5
  62. imm = x & 31
  63. d = (x >> 4) & 1
  64. s1 = (x >> 2) & 3
  65. s2 = (x >> 0) & 3
  66. end
  67. def to_i() raw end
  68. end
  69.  
  70. class Fixnum
  71. def as_int5
  72. return self if self < 0x10 or self < 0
  73. return -(32 - self)
  74. end
  75. end
  76.  
  77. class Array
  78. def to_hex_s
  79. flatten.map { |x| '%02x' % x.to_i }.join('')
  80. end
  81. def to_umodem(filename)
  82. ("rm %s\n" % filename) +
  83. ("/bin/umodem %s STOP\n" % filename) +
  84. to_hex_s + "\nSTOP"
  85. end
  86. def mask_select(mask)
  87. select { |x| x = ((mask & 1) == 1); mask >>= 1; x }
  88. end
  89. def physics_prerotate(i)
  90. x = self[1..-1].mask_select(i)
  91. y = [self[0]]
  92. y + x
  93. end
  94. def physics_rotate(i)
  95. x = self[1..-1].mask_select(i)
  96. y = [self[0]]
  97. x + y
  98. end
  99. end
  100.  
  101. class Register
  102. attr_accessor :d0, :d1, :s0, :s1, :s2, :s3
  103. include Comparable
  104. def to_a
  105. [@s0, @d1, @d0, @s3, @s2, @s1]
  106. end
  107. def a=(x)
  108. @s0, @d1, @d0, @s3, @s2, @s1 = x
  109. end
  110. def dR=(x)
  111. @d0, @d1 = x
  112. end
  113. def dR
  114. [@d0, @d1]
  115. end
  116. def sR=(x)
  117. @s0, @s1, @s2, @s3 = x
  118. end
  119. def sR
  120. [@s0, @s1, @s2, @s3]
  121. end
  122. def <=>(other)
  123. to_a <=> other.to_a
  124. end
  125. def physics(i)
  126. x = [0, 1, 2, 3, 4, 5]
  127. a = x.physics_rotate i
  128. b = x.physics_prerotate i
  129. t1 = self.to_a
  130. t2 = self.to_a
  131. t1[0] += i.as_int5
  132. a.each_index do |j|
  133. t2[a[j]] = t1[b[j]]
  134. end
  135. y = Register.new
  136. y.a = t2
  137. y
  138. end
  139. def to_s
  140. "{ %s, %s, %s, %s } { %s, %s }" % [@s0, @s1, @s2, @s3, @d0, @d1]
  141. end
  142. def swap?(other)
  143. x = self.to_a
  144. y = other.to_a
  145. (0..4).each do |a| ((a+1)..5).each do |b|
  146. return true if x[a] == y[b] and x[b] == y[a]
  147. end
  148. end
  149. return false
  150. end
  151. end
  152.  
  153. x = Register.new
  154. x.sR, x.dR = [0, 1, 2, 3], [4, 5]
  155. y = x.dup
  156. y.s0 = 44
  157. p y == x
  158. puts x.physics(31).physics(31).physics(31).physics(2)
  159.  
  160. def bruteforce_swapreg(foo = [0,1,2,3,4,5])
  161. x = Register.new
  162. x.sR, x.dR = foo[0..3], foo[4..5]
  163. x.dR = [4, 5]
  164. result = []
  165. (1..31).each do |a|
  166. #puts "%d..." % [a]
  167. (1..31).each do |b|
  168. #(1..31).each do |c|
  169. #(1..31).each do |d|
  170. y = x.physics(a).physics(b) #.physics(c).physics(d)
  171. #puts 'yay %d %d %s %s' % [a, b, x, y] if x.swap?(y)
  172. result << [a, b] if x.swap?(y)
  173. #end
  174. #end
  175. end
  176. end
  177. result
  178. end
  179.  
  180. def bruteforce_swapreg3(foo = [0,1,2,3,4,5], combos=nil)
  181. x = Register.new
  182. x.sR, x.dR = foo[0..3], foo[4..5]
  183. result = []
  184. if combos == nil then
  185. puts "Constructing combos"
  186. combos = []
  187. (1..31).each do |a|
  188. #puts "%d..." % [a]
  189. (1..31).each do |b|
  190. (1..31).each do |c|
  191. (1..31).each do |d|
  192. combos << [a,b,c,d]
  193. end
  194. end
  195. end
  196. end
  197. puts "Done constructing combos"
  198. end
  199. combos.each do |(a,b,c,d)|
  200. y = x.physics(a).physics(b).physics(c).physics(d)
  201. #puts 'yay %d %d %s %s' % [a, b, x, y] if x.swap?(y)
  202. result << [a, b, c, d] if x.swap?(y)
  203. end
  204. result
  205. end
  206.  
  207. def bruteforce_addmem2(foo = [0,1,2,3,4,5], combos=nil)
  208. x = Register.new
  209. x.sR, x.dR = foo[0..3], foo[4..5]
  210. result = []
  211. if combos == nil then
  212. puts "Constructing combos"
  213. combos = []
  214. (1..31).each do |a|
  215. #puts "%d..." % [a]
  216. (1..31).each do |b|
  217. (1..31).each do |c|
  218. (1..31).each do |d|
  219. combos << [a,b,c,d]
  220. end
  221. end
  222. end
  223. end
  224. puts "Done constructing combos"
  225. end
  226. combos.each do |(a,b,c,d)|
  227. y = x.physics(a).physics(b).physics(c).physics(d)
  228. #puts 'yay %d %d %s %s' % [a, b, x, y] if x.swap?(y)
  229. result << [a, b, c, d, y] if (y.sR.include? 0 and
  230. y.sR.include? 1 and
  231. y.dR.include? 2 and
  232. y.dR[0] == 2 and
  233. y.dR[1] == 2)
  234. end
  235. result
  236. end
  237.  
  238. def bruteforce_swapmem(foo = [0,1,2,3,4,5], combos=nil)
  239. x = Register.new
  240. x.sR, x.dR = foo[0..3], foo[4..5]
  241. result = []
  242. if combos == nil then
  243. puts "Constructing combos"
  244. combos = []
  245. (1..31).each do |a|
  246. #puts "%d..." % [a]
  247. (1..31).each do |b|
  248. (0..0).each do |c|
  249. (0..0).each do |d|
  250. combos << [a,b,c,d]
  251. end
  252. end
  253. end
  254. end
  255. puts "Done constructing combos"
  256. end
  257. combos.each do |(a,b,c,d)|
  258. y = x.physics(a).physics(b).physics(c).physics(d)
  259. #puts 'yay %d %d %s %s' % [a, b, x, y] if x.swap?(y)
  260. result << [a, b, c, d, y] if (y.sR.include? 1 and
  261. y.sR.include? 3 and
  262. y.dR[0] != y.dR[1])
  263. end
  264. result
  265. end
  266.  
  267. def swapreg2_hackt
  268. result = bruteforce_swapreg3 [0,1,2,3,4,5], $weasel
  269. p result.size
  270. (1..5).each do |foo|
  271. p foo
  272. v = (0..5).map { |x| rand 100 }
  273. result &= bruteforce_swapreg3 v, result
  274. p result.size
  275. end
  276. p result[0]
  277. end
  278.  
  279. #p bruteforce_swapreg()[0]
  280. #swapreg2_hackt
  281. #x = bruteforce_addmem2()[0]
  282. #p x
  283. #puts x[4]
  284. # >>>
  285. # [2, 28, 0, 0, #<Register:0xb7f629b0 @s3=0, @d0=2, @s1=2, @d1=5, @s2=3, # @s0=1>]
  286. # { 1, 2, 3, 0 } { 2, 5 }
  287.  
  288. #x = bruteforce_addmem2([0,1,2,3,4,5], $rabbites)[0]
  289. #p x
  290. #puts x[4]
  291. # >>>
  292. #[2, 28, 1, 28, #<Register:0xb7f6ce4c @d0=2, @s1=3, @d1=2, @s2=0, @s0=2, @s3=1>]
  293. #{ 2, 3, 0, 1 } { 2, 2 }
  294.  
  295. #x = bruteforce_swapmem()
  296. #p x
  297. #puts x[0][4]
  298. # >>>
  299. # [1, 30, 0, 0, #<Register:0xb7f663bc @d0=3, @s1=2, @d1=1, @s2=3, @s0=1, @s3=4>]
  300. # { 1, 2, 3, 4 } { 3, 1 }
  301.  
  302.  
  303. #getc
  304.  
  305. rotate_madness = ['sR[0]', 'dR[1]', 'dR[0]', 'sR[3]', 'sR[2]', 'sR[1]']
  306. (0..31).each do |x|
  307. puts "%2d: %s" % [x, rotate_madness.physics_prerotate(x)]
  308. puts " %s" % [rotate_madness.physics_rotate(x)]
  309. end
  310.  
  311. I = Instruction
  312. tight_loop = I.science 0 # ...only if M[ sR[0] ] == 0
  313.  
  314. p_stop = [
  315. (I.physics 16),
  316. tight_loop,
  317. ]
  318. puts p_stop.to_umodem "p_stop"
  319. "
  320. rm p_stop
  321. /bin/umodem p_stop STOP
  322. 7000
  323. STOP
  324. step_balance stop p_stop
  325. certify stop p_stop
  326. "
  327.  
  328. p_stop127 = [
  329. (I.physics 1),
  330. tight_loop,
  331. ]
  332. puts p_stop127.to_umodem "p_stop127"
  333. "
  334. rm p_stop127
  335. /bin/umodem p_stop127 STOP
  336. 6100
  337. STOP
  338. certify stop127 p_stop127
  339. "
  340.  
  341. #p_copymem = [
  342. #]
  343. #puts p_stopmem.to_umodem "p_copymem"
  344. #"
  345. #"
  346.  
  347. p_copyreg = [
  348. (I.physics 1),
  349. (I.physics 2),
  350. tight_loop,
  351. ]
  352. puts p_copyreg.to_umodem "p_copyreg"
  353. "
  354. "
  355.  
  356. p_swapmem = [
  357. (I.physics 1),
  358. (I.physics 30),
  359. #(I.logic 1),
  360. tight_loop,
  361. ]
  362. puts p_swapmem.to_umodem "p_swapmem"
  363. "
  364. "
  365.  
  366. p_swapreg = [
  367. (I.physics 1),
  368. (I.physics 19),
  369. tight_loop,
  370. ]
  371. puts p_swapreg.to_umodem "p_swapreg"
  372. "
  373. rm p_swapreg
  374. /bin/umodem p_swapreg STOP
  375. 617300
  376. STOP
  377. "
  378.  
  379. p_swapreg2 = [
  380. (I.physics 1),
  381. (I.physics 1),
  382. (I.physics 31),
  383. (I.physics 7),
  384. tight_loop,
  385. ]
  386. puts p_swapreg2.to_umodem "p_swapreg2"
  387. "
  388. rm p_swapreg2
  389. /bin/umodem p_swapreg2 STOP
  390. 61617f6700
  391. STOP
  392. "
  393.  
  394. p_addmem2 = [
  395. (I.physics 2),
  396. (I.physics 28),
  397. (I.physics 1),
  398. (I.physics 28),
  399. (I.math 0, 2, 3),
  400. tight_loop,
  401. ]
  402. puts p_addmem2.to_umodem "p_addmem2"
  403. "
  404. rm p_addmem2
  405. /bin/umodem p_addmem2 STOP
  406. 627c617c2b00
  407. STOP
  408. "
  409.  
  410.  
  411.  

Hell is other programming languages. -- Sartran
Hell is that programming language! -- Dan
Ordinarily, one would enrich this language with more powerful means of computation. Instead I take a different tack... -- Harmonious Monk