Skip to content

Instantly share code, notes, and snippets.

@kennytm

kennytm/adjust.py

Created Nov 19, 2014
Embed
What would you like to do?
ADJUST working environment
#!/usr/bin/env python3
def factorize(num):
while num % 2 == 0:
yield 2
num //= 2
prime = 3
while prime * prime <= num:
while num % prime == 0:
yield prime
num //= prime
prime += 2
if num != 1:
yield num
class ExitProgram(Exception):
pass
class Field(object):
def __init__(self):
self._field = {}
self._cursor = (0, 0)
self._direction = 3
self._acc = 0
self._stack1 = []
self._stack2 = []
def _move_forward(self, steps):
(x, y) = self._cursor
if 1 <= self._direction <= 3:
y -= steps
if 3 <= self._direction <= 5:
x += steps
if 5 <= self._direction <= 7:
y += steps
if self._direction in {0, 1, 7}:
x -= steps
self._cursor = (x, y)
def _turn_left(self, steps):
self._turn_right(-steps)
def _turn_right(self, steps):
new_direction = self._direction + steps
if new_direction < 0:
raise ValueError("Encountered Bug in official ADJUST interpreter (-ve dir)")
self._direction = new_direction % 8
def _lighter_stack(self):
if not self._stack1:
if self._stack2:
return self._stack1
else:
return None
elif not self._stack2:
return self._stack2
top1 = self._stack1[-1]
top2 = self._stack2[-1]
if top1 < top2:
return self._stack1
elif top1 > top2:
return self._stack2
else:
return None
def _heavier_stack(self):
lighter_stack = self._lighter_stack()
if lighter_stack is self._stack1:
return self._stack2
elif lighter_stack is self._stack2:
return self._stack1
else:
return None
def _perform_2(self):
self._acc = (self._acc >> 3 | self._acc << 5) & 0xff
def _perform_3(self):
stack = self._lighter_stack()
if stack is None:
stack = self._stack1
self._turn_right(1)
elif stack is self._stack1:
if self._acc:
self._turn_left(2)
else:
self._turn_right(3)
elif stack is self._stack2:
self._turn_left(1)
stack.append(self._acc)
self._move_forward(1)
def _perform_5(self):
self._acc ^= 1
def _perform_7(self):
self._move_forward(bin(self._acc).count('1'))
def _perform_11(self):
stack = self._heavier_stack() or self._stack2
try:
self._acc = stack.pop()
except IndexError:
self._acc = 0
def _perform_13(self):
try:
print(chr(self._stack2.pop()), end='')
except IndexError:
print('***stack2 is empty!***')
pass
def _perform_17(self):
raise NotImplementedError("Prime factor 17 is not supported.")
def _perform_19(self):
try:
ch = self._stack2.pop()
self._stack1.append(ch)
except IndexError:
if self._acc & 4:
self._turn_right(2)
self._move_forward(bin(self._acc & 0b10011000).count('1'))
def _perform_23(self):
self._acc = (self._acc << 5) & 0xff
def _perform_29(self):
if self._acc == 0:
self._turn_left(1)
self._move_forward(2)
if self._lighter_stack() is self._stack2:
self._move_forward(1)
self._turn_right(1)
def _perform_31(self):
self._move_forward(1)
def _perform_37(self):
lighter_stack = self._lighter_stack()
if lighter_stack:
heavier_stack = self._heavier_stack()
heavier_stack.append(lighter_stack[-1])
def _perform_41(self):
heavier_stack = self._heavier_stack()
if heavier_stack:
heavier_stack.pop()
def _perform_43(self):
self._acc >>= 1
if self._acc == 0:
self._move_forward(1)
self._turn_left(2)
def _perform_47(self):
lighter_stack = self._lighter_stack()
if lighter_stack:
self._acc = lighter_stack.pop()
def _perform_53(self):
def reverse_bits(n):
return int('{:04b}'.format(n)[::-1], 2)
if self._lighter_stack() is self._stack1:
self._acc = (self._acc & 0xf0) | reverse_bits(self._acc & 0xf)
else:
self._acc = (self._acc & 0xf) | reverse_bits(self._acc >> 4) << 4
def _perform_59(self):
self._turn_right(bin(self._acc).count('1'))
def _perform_61(self):
(self._stack1, self._stack2) = (self._stack2, self._stack1)
def _perform_67(self):
raise ExitProgram()
def plot(self, char):
if self._cursor in self._field:
raise ValueError('{} is already occupied!', self._cursor)
self._field[self._cursor] = char
for factor in reversed(list(factorize(ord(char)))):
try:
method = getattr(self, '_perform_' + str(factor))
except AttributeError:
self._acc = factor
continue
method()
self._move_forward(1)
def plot_string(self, string):
for char in string:
self.plot(char)
def print_field(self, target):
def compute_difference_internal(acc, target):
xor = acc ^ target
unshift_amount = 0
while xor:
if xor & 1:
yield 5
xor ^= 1
if xor == 0:
yield from [2] * ((-unshift_amount) % 8)
else:
yield 2
xor = (xor >> 3 | xor << 5) & 0xff
unshift_amount += 1
def recommend_difference(acc, target):
def characters(m):
match = m.group()
fives = match.count('5')
twos = match.count('2')
return {
(1, 1): 'F',
(2, 1): '2',
(1, 4): 'P',
(0, 1): 'R',
(0, 2): 't',
(0, 3): '8',
}[(fives, twos)]
import re
string = ''.join(str(x) for x in compute_difference_internal(acc, target))
return string + ' (' + re.sub('52|552|52222|2{1,3}', characters, string) + ')'
print()
min_x = min(c[0] for c in self._field.keys())
min_y = min(c[1] for c in self._field.keys())
max_x = max(c[0] for c in self._field.keys())
max_y = max(c[1] for c in self._field.keys())
for y in range(min_y, max_y+1):
for x in range(min_x, max_x+1):
ch = self._field.get((x, y), '`')
print(ch, end='')
print()
print('\ncurrent state:')
print(' acc = {0:3} ({0:08b})'.format(self._acc))
print(' target = {0:3} ({0:08b})'.format(ord(target)))
print(' diff =', recommend_difference(self._acc, ord(target)))
print(' stack1 =', self._stack1)
print(' stack2 =', self._stack2)
print(' direct =', self._direction * 45)
# acc affecting commands:
# 2, 5, [11], -23-, 43, [47], [53], >67
# direction affecting commands:
# 3, 19, 29, 43, -59-
# can use:
# 3, 7, 13, 19, 29, 31, 37, 41, -59-, 61
field = Field()
try:
#0 "
field.plot_string('K8F8FKAnK')
#1 H
field.plot_string('RFF8RFKKA')
#2 o
field.plot_string('8FtFFKAnK')
#3 u
field.plot_string('RFFRFRFRKKA')
#4 s
field.plot_string('FtFtFRKKA')
#5 t
field.plot_string('8FtFRKKAKnnK')
#6 o
field.plot_string('FRFtFtKKA')
#7 n
field.plot_string('KKAnnKnK')
#8 ,
field.plot_string('F8FFRFKKA')
#9 _
field.plot_string('FF8RFRKKA')
#10 w
field.plot_string('tFFFRFRKKA')
#11 e
field.plot_string('FtFF8KAnK')
#12 _
field.plot_string('RFFFRFFFKKA')
#13 h
field.plot_string('FFF8tKAnK')
#14 a
field.plot_string('FRF8FRKKA')
#15 v
field.plot_string('8FFRFRKKA')
#16 e
field.plot_string('8FF8KAnK')
#17 _
field.plot_string('RFFFRFFRKKA')
#18 a
field.plot_string('tF8tKAnK')
#19 _
field.plot_string('88FRKKA')
#20 p
field.plot_string('FRFRF8KKA')
#21 r
field.plot_string('FtF8RKKA')
#22 o
field.plot_string('RFtFRFRKKA')
#23 b
field.plot_string('RF8RFRKKA')
#24 l
field.plot_string('FFRFtFRKKA')
#25 e
field.plot_string('RF88KKA')
#26 m
field.plot_string('FF88KAnK')
#27 .
field.plot_string('8FRFRFKKA')
#28 "
field.plot_string('FF8RFRKKAKnnK')
#29 _
field.plot_string('tF8FRKKA')
#30 -
field.plot_string('RF8RFRKKAKnnK')
#31 _
field.plot_string('F8RFFRKKA')
#32 J
field.plot_string('FFFF8FKAnK')
#33 i
field.plot_string('FFF8FRKKA')
#34 m
field.plot_string('F8tFRKKA')
#35 _
field.plot_string('RFF8FRKKA')
#36 L
field.plot_string('FFF8FFKAnK')
#37 o
field.plot_string('FFFF8RKKA')
#38 v
field.plot_string('RFtF8KKA')
#39 e
field.plot_string('8FF8KAnK')
#40 l
field.plot_string('8FRFtKKA')
#41 l
field.plot_string('iA')
#end.
field.plot_string('C')
except ExitProgram:
field.print_field('"Houston, we have a problem." - Jim Lovell'[40])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment