/
fnooblatz1000.py
789 lines (781 loc) · 31.6 KB
/
fnooblatz1000.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
# ________________
#
# FNOOBLATZ 1000
# ________________
#
#
# License: http://en.wikipedia.org/wiki/WTFPL
#
#
# @ # * @ # * @ # * @ # * @ # * @ # * @# * @# * @#* @#*
#
# In the Fabled and Far Away Land of Discordia,
# Discordian programmers toil day and night, producing
# programs in the infinite variety their varied and
# variable customers continually demand.
# Modern Discordian programming is much concerned
# with Functions and Objects and so forth just as you'll
# find in many modern lands. But while here we have
# scorned our old computers and environments, with their
# seemingly unnecessary old complications, in Discordia
# all programmers hold in their hearts a special place
# for the Fnooblatz 1000, as its bizarre behaviors
# continue to be the slippery fundament of all the
# chaotic Discordian languages of today.
#
# @ # * @ # * @ # * @ # * @ # * @# * @# * @#* @#*
#
#
# Run "python fnooblatz1000.py" to use a Fnooblatz
# 1000 interactively.
import collections
from doohickey import Doohickey
import alphabetrotator
class Fnooblatz1000(object):
def __init__(self):
self.reset_everything()
def printable_display(self):
printable = '\n'
for row in self.display:
for column in row:
printable += column
printable += '\n'
return printable
def print_curses(self,stdscr):
for y in range(len(self.display)):
for x in range(len(self.display[y])):
stdscr.addch(y,x,ord(self.display[y][x]))
stdscr.refresh()
def set_width(self,width):
if width < 1:
return False
while len(self.display[0]) > width:
self.press_button(3)
while len(self.display[0]) < width:
self.press_button(1)
assert(len(self.display[0]) == width)
return True
def set_height(self,height):
if height < 1:
return False
while len(self.display) > height:
self.press_button(4)
while len(self.display) < height:
self.press_button(2)
assert(len(self.display) == height)
return True
def reset_everything(self):
empty_row = collections.deque()
empty_row.append('*')
self.display = collections.deque()
self.display.append(empty_row)
self.buttons_pressed = collections.deque()
self.cursor_stack = collections.deque()
self.background_instructions = collections.deque()
self.background_current_instruction = -1 # So it starts at zero.
self.background_processing_on = False
self.alternator = True
self.cursor_row = 0
self.cursor_column = 0
self.rotation_direction = 1
self.doohickey = Doohickey()
self.remembered_character = ' '
def check_cursor_bounds(self):
if self.cursor_row < 0:
self.cursor_row = 0
if self.cursor_column < 0:
self.cursor_column = 0
while self.cursor_row >= len(self.display):
self.cursor_row -= 1
while self.cursor_column >= len(self.display[0]):
self.cursor_column -= 1
def execute_sequence(self,sequence):
for instruction in sequence:
self.press_button(instruction)
def execute_background_instruction(self):
if len(self.background_instructions) < 1:
return # If there are no instructions, there's nothing to do.
self.background_current_instruction += 1
if self.background_current_instruction >= len(self.background_instructions):
self.background_current_instruction = 0
instruction = \
self.background_instructions[self.background_current_instruction]
self.execute_single_instruction(instruction)
def press_button(self,button_number):
self.buttons_pressed.append(button_number)
if len(self.buttons_pressed) > 1024:
self.buttons_pressed.popleft()
if self.alternator:
self.alternator = False
else:
self.alternator = True
# The alternator, as you can see, alternates
# BEFORE each instruction is executed. Confusing
# but true!
self.execute_single_instruction(button_number)
if self.background_processing_on:
self.execute_background_instruction()
def execute_single_instruction(self,button_number):
if button_number == 0:
self.reset_everything()
return
# Resets everything.
#
# This functionality was desperately necessary
# of course on actual Fnooblatz 1000s, which if
# given difficult computations would overheat and
# smoke furiously. I don't think there's an FB1000
# would have made it through the first night without
# this button. Hopefully on this simulator it
# should be necessary slightly less desperately,
# but it's still useful for getting out of any of
# the confusing internal states a Fnooblatz is
# prone to!
if button_number == 1:
for row in self.display:
row.append('*')
return
if button_number == 2:
new_row = collections.deque()
for column in self.display[0]:
new_row.append('*')
self.display.append(new_row)
return
# The above commands to expand the Fnooblatz screen
# are necessary because the display starts 1 pixel by
# 1 pixel. But why does it? Well, besides the fact
# that in the old days people would run their Fnooblatz
# at as small a resolution as they actually needed, to
# conserve energy, or that a cheap one-pixel display
# would often be used to diagnose what's wrong with a
# sick Fnooblatz (so it couldn't burn out a whole
# expensive display), there's also the case of those
# folks who would insist that they just didn't need
# more than a one-pixel display to get by. And it's
# true, you can read the news quite adequately one
# character at a time, if you're patient.
if button_number == 3:
if len(self.display[0]) > 1:
for row in self.display:
row.pop()
self.check_cursor_bounds()
return
if button_number == 4:
if len(self.display) > 1:
self.display.pop()
self.check_cursor_bounds()
return
# If you can make the display bigger, it's convenient
# to be able to make it smaller too, instead of just
# having to start all over!
if button_number == 5:
for row in self.display:
row.rotate(self.rotation_direction)
return
if button_number == 6:
self.display.rotate(self.rotation_direction)
return
# Rotating the display, which gives us just barely
# enough instructions to paint pictures! :D
if button_number == 7:
return
# Button seven doesn't do anything, 'anything' that is
# except for all the stuff the Fnooblatz does every
# instruction (alternate the alternator, etc.)-- but,
# like, nothing EXTRA.
if button_number == 8:
self.check_cursor_bounds()
if self.alternator:
self.display[self.cursor_row][self.cursor_column] = '|'
else:
self.display[self.cursor_row][self.cursor_column] = '-'
return
# This allows you to see the behavior of the alternator,
# and combined with the following instructions to move the
# cursor can be useful for drawing.
if button_number == 9:
if self.alternator:
self.cursor_row += 1
else:
self.cursor_row -= 1
self.check_cursor_bounds()
return
# The previous instruction allows you to go either up OR down!
if button_number == 10:
if self.alternator:
self.cursor_column += 1
else:
self.cursor_column -= 1
self.check_cursor_bounds()
return
# The previous instruction allows you to go either left OR right!
if button_number == 11:
self.check_cursor_bounds()
self.display[self.cursor_row][self.cursor_column] = ' '
return
# Spaces. Ah. Relaxing.
if button_number == 12:
self.display[self.cursor_row][self.cursor_column] = self.doohickey.other()
return
# The Fnooblatz1000 contains a simple interface
# to access its contained Doohickey! This presses
# the 'other' button on the Doohickey and prints
# the result.
if button_number == 13:
self.display[self.cursor_row][self.cursor_column] = self.doohickey.a()
return
if button_number == 14:
self.display[self.cursor_row][self.cursor_column] = self.doohickey.b()
return
# With these you can use the Doohickey to write 'a' and
# 'b', which is useful for talking about ABBA!
if button_number == 15:
self.buttons_pressed.pop() # Otherwise it gets weird.
self.background_instructions = self.buttons_pressed
self.background_current_instruction = -1 # So we start at zero.
self.buttons_pressed = collections.deque()
return
# Moves what you've done recently to the background,
# where it will continue to happen as you go on doing
# other things. Fun!
if button_number == 16:
self.buttons_pressed.pop() # Otherwise it gets weird.
if self.background_processing_on:
self.background_processing_on = False
else:
self.background_processing_on = True
return
# Toggles background processing. If it's turned
# on it will start quite immediately, before the
# next instruction.
if button_number == 17:
self.cursor_row = 0
self.cursor_column = 0
return
# An orderly instruction for finding one's place.
if button_number == 18:
self.check_cursor_bounds()
if self.display[self.cursor_row][self.cursor_column] != '|':
self.cursor_column -= 1
self.check_cursor_bounds()
return
if button_number == 19:
self.check_cursor_bounds()
if self.display[self.cursor_row][self.cursor_column] != '|':
self.cursor_column += 1
self.check_cursor_bounds()
return
if button_number == 20:
self.check_cursor_bounds()
if self.display[self.cursor_row][self.cursor_column] != '-':
self.cursor_row -= 1
self.check_cursor_bounds()
return
if button_number == 21:
self.check_cursor_bounds()
if self.display[self.cursor_row][self.cursor_column] != '-':
self.cursor_row += 1
self.check_cursor_bounds()
return
# The above instructions allow you to travel easily in
# all four directions, while also allowing you to safely
# contain yourself in a box-- or a maze perhaps!
if button_number == 22:
if self.rotation_direction == 1:
self.rotation_direction = -1
else:
self.rotation_direction = 1
return
# Allows you to switch to rotating the display in the
# opposite direction. This might make you less dizzy.
if button_number == 23:
self.check_cursor_bounds()
self.remembered_character = self.display[self.cursor_row][self.cursor_column]
return
if button_number == 24:
self.check_cursor_bounds()
self.display[self.cursor_row][self.cursor_column] = self.remembered_character
return
# Allows you to remember a character for a little
# while. Useful for smearing things around!
if button_number == 25:
self.check_cursor_bounds()
self.display[self.cursor_row][self.cursor_column] = \
alphabetrotator.rotate(self.display[self.cursor_row][self.cursor_column])
return
# Combined with the Doohickey, which prints out
# 'a's and 'b's, this allows you to write any
# letter of the alphabet!
if button_number == 26:
self.check_cursor_bounds()
if self.display[self.cursor_row][self.cursor_column] == ' ':
return # Do nothing to blank spaces.
self.display[self.cursor_row][self.cursor_column] = 'g'
return
# This is useful for GIG.
if button_number == 27:
self.cursor_stack.append((self.cursor_row, self.cursor_column))
if len(self.cursor_stack) > 1024:
self.cursor_stack.popleft()
return
if button_number == 28:
if len(self.cursor_stack) > 0:
(self.cursor_row, self.cursor_column) = self.cursor_stack.pop()
return
# Whereever you go, there you are, but it's also nice
# to remember where else you've been recently.
self.display[0][0] = '@'
# Error signal for unpressableness,
# since if we've reached this point,
# an unpressable button has been pressed!
def help_system():
print """
________
HELLO AN
D WELCOM
E TO THE please enter the number
FNOOBLAT of the button you would
Z 1000 H like help with, please.
ELP SYST
EM!!!!!!
________
"""
help_with = raw_input("HELP: ")
print
if help_with.isdigit():
help_with = int(help_with)
if help_with == 'quit':
print "Quits the Fnooblatz 1000 simulator, in case"
print "there's ever any reason you want to leave."
return
if help_with == 'help':
print "Helps you with things, like I've just helped you!"
return
if help_with == 'print':
print "Prints a list of the buttons you've pressed, since resetting or moving the list."
return
if help_with == 0:
print "Resets everything!!!"
return
if help_with == 1:
print "Expands the Fnooblatz display by one column."
return
if help_with == 2:
print "Expands the Fnooblatz display by one row."
return
if help_with == 3:
print "Contracts the Fnooblatz display by one column."
return
if help_with == 4:
print "Contracts the Fnooblatz display by one row."
return
if help_with == 5:
print "Rotates columns according to the rotation direction."
return
if help_with == 6:
print "Rotates rows according to the rotation direction."
return
if help_with == 7:
print "Doesn't do anything (except alternate the alternator, etc)."
return
if help_with == 8:
print "Outputs a | if the alternator is true and a - if it is false."
return
if help_with == 9:
print "Goes down if the alternator is true, and up if it is false."
return
if help_with == 10:
print "Goes right if the alternator is true, and left if it is false."
return
if help_with == 11:
print "Prints a relaxing space at the cursor."
return
if help_with == 12:
print "Prints the result of pressing the Doohickey's 'other' button at cursor."
return
if help_with == 13:
print "Prints the result of pressing the Doohickey's 'a' button at cursor."
return
if help_with == 14:
print "Prints the result of pressing the Doohickey's 'b' button at cursor."
return
if help_with == 15:
print "Moves recently pressed buttons to background instruction list."
return
if help_with == 16:
print "Toggles background processing on and off."
return
if help_with == 17:
print "Moves the cursor to the upper left corner."
return
if help_with == 18:
print "Goes left unless the cursor is at a '|'."
return
if help_with == 19:
print "Goes right unless the cursor is at a '|'."
return
if help_with == 20:
print "Goes up unless the cursor is at a '-'."
return
if help_with == 21:
print "Goes down unless the cursor is at a '-'."
return
if help_with == 22:
print "Reverses the rotation direction."
return
if help_with == 23:
print "Remembers the character at cursor."
return
if help_with == 24:
print "Prints the remembered character."
return
if help_with == 25:
print "Rotates the character at the cursor through the alphabet."
return
if help_with == 26:
print "Usually puts a 'g' at the cursor, but leaves blank spaces blank."
return
if help_with == 27:
print "Push the current cursor location onto the cursor location stack."
return
if help_with == 28:
print "Pop a location off the cursor location stack and go to it."
return
print "Never heard of that, sorry. :("
class TestSuiteRunner(object):
def reset_score(self):
self.tests_score = 0
self.total_tests = 0
def grade(self,boolean,error):
if boolean:
self.tests_score += 1
else:
print "FAILED: ", error
self.total_tests += 1
def run_test_suite(self,fnoo):
self.reset_score()
print
fnoo.press_button(0) # Reset the Fnooblatz.
# Size of the Fnooblatz should now be 1 by 1.
self.grade(len(fnoo.display) == 1,
"Initial Fnooblatz display is not exactly 1 row long.")
self.grade(len(fnoo.display[0]) == 1,
"Initial Fnooblatz display is not exactly 1 column wide.")
fnoo.press_button(99999) # This button should not exist.
self.grade(fnoo.display[0][0] == '@',
"Pressed button 99999 but upperlefterrorsquare didn't turn into '@'.")
fnoo.press_button(1) # Attempt to expand Fnooblatz display one column.
self.grade(len(fnoo.display[0]) == 2,
"Pressing button 1 did not expand Fnooblatz display by a column.")
fnoo.press_button(2) # Attempt to expand Fnooblatz display one row.
self.grade(len(fnoo.display) == 2,
"Pressing button 2 did not expand Fnooblatz display by a row.")
fnoo.press_button(3) # Attempt to contract Fnooblatz display one column.
self.grade(len(fnoo.display[0]) == 1,
"Pressing button 3 did not contract Fnooblatz display by a column.")
fnoo.press_button(3)
# Attempt to contract display by a column even though it's only one column
# wide already (should leave it the same).
self.grade(len(fnoo.display[0]) == 1,
"Pressing button 3 after Fnooblatz display "
"was already 1 column changed width again.")
fnoo.press_button(4) # Attempt to contract Fnooblatz display one row.
self.grade(len(fnoo.display) == 1,
"Pressing button 4 did not contract Fnooblatz display by a row.")
fnoo.press_button(4)
# Attempt to contract display by a row even though it's only one row
# long already (should leave it the same).
self.grade(len(fnoo.display) == 1,
"Pressing button 4 after Fnooblatz display "
"was already 1 row changed length again.")
fnoo.press_button(1)
fnoo.press_button(1)
fnoo.press_button(2)
fnoo.press_button(2) # Expand the Fnooblatz a little so we can move it around.
self.grade(fnoo.display[0][0] == '@',
"The @ isn't in the upperleft corner for some reason.")
fnoo.press_button(5) # Attempt to move display one column right.
self.grade(fnoo.display[0][1] == '@',
"Couldn't move the @ one right.")
self.grade(fnoo.display[0][0] == '*',
"Upper left corner wasn't replaced with a * when the display moved right.")
fnoo.press_button(6) # Attempt to move display one row down.
self.grade(fnoo.display[1][1] == '@',
"Couldn't move the @ one row down.")
fnoo.press_button(99999) # Make a new @
self.grade(fnoo.display[0][0] == '@',
"Couldn't make a new @")
fnoo.press_button(6) # Attempt to move down one row with new @
self.grade(fnoo.display[1][0] == '@',
"Couldn't move new @ down one row.")
fnoo.execute_sequence([0]) # Should reset everything!
self.grade(len(fnoo.display) == 1,
"Tried to reset Fnooblatz by sending a sequence with just 0,"
" but then display wasn't 1 row long.")
self.grade(fnoo.display[0][0] == '*',
"Tried to reset Fnooblatz by sending a sequence with just 0,"
" but then the upper left corner wasn't a *.")
fnoo.execute_sequence([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
99999, 5, 99999, 6, 6, 99999, 6, 99999, 6,
99999, 6, 99999, 6, 99999, 6,
99999, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 99999, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 99999, 6,
99999, 6, 99999, 6, 99999, 6, 99999,
6, 6, 6, 5, 5, 5, 5, 3,
3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4]) # Should draw an !
self.grade(fnoo.printable_display() == """
********
********
***@@***
***@@***
***@@***
***@@***
***@@***
***@@***
********
***@@***
********
********
""", "Exclamation mark script printed out wrong.")
fnoo.press_button(7)
self.grade(fnoo.printable_display() == """
********
********
***@@***
***@@***
***@@***
***@@***
***@@***
***@@***
********
***@@***
********
********
""", "Pressing 7 changed the exclamation mark picture.")
fnoo.press_button(0) # Reset, to reset the alternator.
self.grade(fnoo.alternator, "Alternator didn't start True.")
fnoo.press_button(7) # Alternate the alternator.
self.grade(fnoo.alternator == False, "Alternator didn't alternate to False.")
fnoo.press_button(7) # Alternate again.
self.grade(fnoo.alternator, "Alternator didn't alternate back to True.")
fnoo.press_button(0) # Clean up to draw something new.
fnoo.execute_sequence([1,1,2,2]) # Expand to 3x3.
self.grade(len(fnoo.display) == 3,
"Sequence [1,1,2,2] didn't expand Fnooblatz to three rows long.")
self.grade(len(fnoo.display[0]) == 3,
"Sequence [1,1,2,2] didn't expand Fnooblatz to three columns wide.")
fnoo.press_button(11)
self.grade(fnoo.display[0][0] == ' ',
"Pressing 11 didn't make a space.")
fnoo.execute_sequence([9,8,9,11]) # These 9s should go down.
self.grade(fnoo.display[1][0] == '-',
"Couldn't go down with 9 and paint '-' on the left.")
fnoo.execute_sequence([10,8]) # Go right and write '|'.
self.grade(fnoo.display[2][1] == '-',
"Couldn't go right with 10 and then paint '-'.")
fnoo.press_button(8)
self.grade(fnoo.display[2][1] == '|',
"Pressing 8 again didn't paint '|' instead of '-'.")
fnoo.execute_sequence([9,8,9,8,7,10,11,9,8,9,11])
self.grade(fnoo.printable_display() == """
|
-|-
|
""", "Failed at drawing a little cross.")
fnoo.press_button(0) # OK start again.
fnoo.execute_sequence([1, 2, 7, 9, 7, 10, 12]) # Print 'b' in the lower right corner.
self.grade(fnoo.display[1][1] == 'b',
"Pressing button 12 to press 'other' on the Doohickey didn't print 'b'.")
fnoo.press_button(13)
self.grade(fnoo.display[1][1] == 'a',
"Pressing button 13 didn't write an 'a'.")
fnoo.press_button(14)
self.grade(fnoo.display[1][1] == 'b',
"Pressing button 14 didn't write a 'b'.")
fnoo.press_button(12)
self.grade(fnoo.display[1][1] == 'a',
"Pressing button 12 to press 'other' didn't print 'a' after 'b'.")
fnoo.press_button(0)
fnoo.execute_sequence([1, 1, 1, 12, 12, 12, 6, 5, 12, 5, 12, 5, 12, 5, 12, 12, 5, 5, 5, 12, 5, 13, 5, 13, 14, 5, 13, 5, 13, 5, 14, 5, 5, 2, 6, 14, 5, 13, 5, 13, 5, 14, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5])
self.grade(fnoo.printable_display() == """
abba
aabb
""", "Wasn't able to use the Doohickey to write about ABBA.")
fnoo.press_button(0)
# OK now we'll test the background processing.
fnoo.press_button(8)
fnoo.press_button(15) # Put a blinker in the background.
fnoo.press_button(16) # Start processing,
fnoo.press_button(7) # NOP, which should change it to a '|'.
self.grade(fnoo.display[0][0] == '|',
"Wasn't able to run an instruction in the background.")
fnoo.press_button(7) # NOP, which should change it again.
self.grade(fnoo.display[0][0] == '-',
"Background twinkle didn't twinkle.")
fnoo.press_button(16) # Stop processing.
fnoo.execute_sequence([7,7,7,7]) # Actual NOP.
self.grade(fnoo.display[0][0] == '-',
"Background processing wouldn't stop.")
fnoo.press_button(0)
fnoo.execute_sequence([1,1,1,1,1,10,8,10,8,10,8,10,8,10,8])
self.grade(fnoo.printable_display() == """
*-----
""", "Couldn't write a line of dashes.")
fnoo.press_button(17) # Should go to upper left corner.
fnoo.press_button(8)
self.grade(fnoo.display[0][0] == '-',
"Couldn't paint dash in upper left corner by pressing 17.")
fnoo.execute_sequence([10,7,10,7,10,7,8])
self.grade(fnoo.printable_display() == """
---|--
""", "Couldn't put a | on the line of dashes.")
fnoo.press_button(17)
fnoo.execute_sequence([19,19,19,19,19]) # Go right a bunch, but hit the wall.
fnoo.press_button(14)
self.grade(fnoo.printable_display() == """
---b--
""", "Couldn't hit a wall going right and then turn it into a b.")
fnoo.press_button(0)
fnoo.execute_sequence([1,1,1,1,1,10,8,10,8,10,8,10,8,10,8,17,8,10,7,8,7,10,7,10,7,10])
self.grade(fnoo.printable_display() == """
-|----
""", "Couldn't print second wall to hit.")
fnoo.execute_sequence([18,18,18,18,18]) # Go left a bunch, but hit the wall.
fnoo.press_button(14)
self.grade(fnoo.printable_display() == """
-b----
""", "Couldn't hit a wall going left and then turn it into a b.")
fnoo.press_button(0)
draw_up_down_wall = [2, 2, 2, 8, 7, 9, 7, 8, 7, 9, 7, 8,
7, 9, 7, 8, 17, 8, 7, 9, 8, 9, 7, 9]
fnoo.execute_sequence(draw_up_down_wall)
self.grade(fnoo.printable_display() == """
|
-
|
|
""", "Couldn't draw wall for going up-down.")
fnoo.execute_sequence([20,20,20]) # Go up and hit the wall.
fnoo.press_button(14)
self.grade(fnoo.printable_display() == """
|
b
|
|
""", "Couldn't hit wall going up and turn it into a 'b'.")
fnoo.press_button(0)
fnoo.execute_sequence(draw_up_down_wall)
fnoo.press_button(17) # Go home.
fnoo.execute_sequence([21,21,21]) # Go down and hit the wall.
fnoo.press_button(14)
self.grade(fnoo.printable_display() == """
|
b
|
|
""", "Couldn't hit wall going down and turn it into a 'b'.")
fnoo.press_button(0)
fnoo.execute_sequence([1, 2, 8, 19, 8, 8, 21, 8, 8, 18, 8, 8])
self.grade(fnoo.printable_display() == """
-|
|-
""", "Couldn't draw little swirl.")
fnoo.execute_sequence([1,2,1,2]) # Expand a little.
fnoo.press_button(22) # Reverse rotation.
fnoo.execute_sequence([5,6,5,6,5,6]) # Rotate back around to the middle.
self.grade(fnoo.printable_display() == """
****
*-|*
*|-*
****
""", "Couldn't move swirl to the middle by reversing rotation direction.")
fnoo.press_button(0)
fnoo.execute_sequence([1,14,19,13,2])
fnoo.press_button(23) # Should remember an 'a'.
fnoo.execute_sequence([21,18])
fnoo.press_button(24) # Should paint the remembered 'a'.
fnoo.press_button(20)
fnoo.press_button(23) # Should remember a 'b'.
fnoo.execute_sequence([21,19])
fnoo.press_button(24) # Should paint the remembered 'b'.
self.grade(fnoo.printable_display() == """
ba
ab
""", "Couldn't remember characters and repaint them.")
fnoo.press_button(0)
fnoo.press_button(14)
fnoo.press_button(25)
self.grade(fnoo.display[0][0] == 'c',
"Couldn't use alphabetrotator to change 'b' to 'c'.")
fnoo.execute_sequence([25,25,25,25,25,25,25,25,25,25,25,25,25,
25,25,25,25,25,25,25,25,25,25])
self.grade(fnoo.display[0][0] == 'z',
"Couldn't use alphabetrotator to advance letter to 'z'.")
fnoo.press_button(25)
self.grade(fnoo.display[0][0] == 'a',
"Using alphabetrotator on 'z' didn't give 'a'.")
fnoo.press_button(26)
self.grade(fnoo.display[0][0] == 'g',
"Pressing 26 didn't turn an 'a' into a 'g'.")
fnoo.press_button(11)
fnoo.press_button(26)
self.grade(fnoo.display[0][0] == ' ',
"Pressing 26 on a blank space didn't leave it blank.")
fnoo.press_button(0)
fnoo.execute_sequence([1,2])
fnoo.press_button(27) # Push 0,0 on the stack.
fnoo.press_button(19)
fnoo.press_button(27) # Push 0,1 on the stack.
fnoo.press_button(21)
fnoo.press_button(27) # Push 1,1 on the stack.
fnoo.press_button(18)
fnoo.execute_sequence([13,28,12,28,12,28,12])
self.grade(fnoo.printable_display() == """
ba
ab
""", "Couldn't print baab square by stack push-popping!")
fnoo.press_button(0) # Leave the Fnooblatz clean!
print
print "Passed", self.tests_score, "tests out of", self.total_tests, "!"
print
def main():
print "..bleep....bloop....blap.."
fn = Fnooblatz1000()
tester = TestSuiteRunner()
tester.run_test_suite(fn) # tests! sweet!
print "________________________"
print
print "FNOOBLATZ 1000 ACTIVATED"
print "________________________"
print "type 'quit' to quit"
print "type 'help' for help on the Fnooblatz buttons"
print "type 'print' to print a list of the buttons recently pressed"
print "otherwise, enter a number to simulate"
print "pressing that button on the Fnooblatz 1000"
print "________________________"
while True:
print
print fn.printable_display()
print
prompt = "Alt: " + str(fn.alternator) + \
" Row: " + str(fn.cursor_row) + \
" Col: " + str(fn.cursor_column) + " >-> "
input = raw_input(prompt)
if input == 'quit':
break
if input == 'help':
help_system()
print
print "..returning from help system"
print "||.........................."
continue
if input == 'print':
print fn.buttons_pressed
continue
if input.isdigit():
fn.press_button(int(input))
continue
print "I did not understand your command. :("
if __name__ == "__main__":
main()