最后活跃于 1748487320

bitsy.nv 原始文件 Playground
1|| :\: OH, btw, the text stuff assumes you have this font installed
2 :\: managore.itch.io/m3x6
3
4|:: get color for .|
5 :color: 51 68 85
6|:: get color for #|
7 :color: 255 187 51
8
9|:: get sprite 1 for .|
10 :sprite data: (
11 . . . . . . . .
12 . . . . . . . .
13 . . . . . . . .
14 . . . . . . . .
15 . . . . . . . .
16 . . . . . . . .
17 . . . . . . . .
18 . . . . . . . .
19 )
20
21|:: get sprite 1 for p|
22 :sprite data: (
23 . # . # # # # .
24 . # # # # # . .
25 . . . . . . . .
26 . . # # # # . .
27 . # . # # . # .
28 . . # . . # . .
29 . . # . . # . .
30 . . # . . # . .
31 )
32
33|:: is p actor| :actor: p yes
34|:: get sprite 2 for p|
35 :sprite data: (
36 # . # # # # . .
37 # # # # # . . .
38 . . . . . . . .
39 . . # # # # . .
40 . # . # # . # .
41 . . # . . # . .
42 . . # . . # . .
43 . . # . . # . .
44 )
45
46|:: is c actor| :actor: c yes
47
48|:: touched c :angy:?|
49|:: touched c :already pet:| :angy:
50|:: touched c :touched once:| :already pet:
51|:: touched c| :touched once:
52
53|:: get dialogue for c :angy:? :current room: test2?|
54 :@text to draw: "still agny!!"
55|:: get dialogue for c :angy:?|
56 :@text to draw: "no talk, me angy."
57|:: get dialogue for c :already pet:?|
58 :@text to draw: "okay, enough."
59|:: get dialogue for c| :@text to draw: "meow! meow!"
60
61|:: get sprite 1 for c :angy:? :current room: test2?|
62 :sprite data: (
63 . . . . . . . .
64 . . . . . . . .
65 . . . . . # . #
66 . . . . . # # #
67 . . . . . # # #
68 . . . . # # # .
69 # . . # # # # .
70 . # # # # . # .
71 )
72|:: get sprite 2 for c :angy:? :current room: test2?|
73 :sprite data: (
74 . . . . . . . .
75 . . . . . . . .
76 . . . . . # . #
77 . . . . . # # #
78 . . . . . # # #
79 . . . . # # # .
80 . # . # # # # .
81 . # # # # . # .
82 )
83
84|:: get sprite 1 for c :angy:?|
85 :sprite data: (
86 . . . . . . . .
87 . . . . . . . .
88 # . # . . . . .
89 # # # . . . . .
90 # # # . . . . .
91 . # # # . . . .
92 . # # # # . . #
93 . # . # # # # .
94 )
95|:: get sprite 2 for c :angy:?|
96 :sprite data: (
97 . . . . . . . .
98 . . . . . . . .
99 # . # . . . . .
100 # # # . . . . .
101 # # # . . . . .
102 . # # # . . . .
103 . # # # # . # .
104 . # . # # # # .
105 )
106
107|:: get sprite 1 for c|
108 :sprite data: (
109 . . . . . . . .
110 . . . . . . . .
111 . . . . . # . #
112 . . . . . # # #
113 . # . . . # # #
114 . # . # # # # .
115 . . # # # # # .
116 . . . # # . # .
117 )
118|:: get sprite 2 for c|
119 :sprite data: (
120 . . . . . . . .
121 . . . . . . . .
122 . . . . . # . #
123 . . . . . # # #
124 . . . . . # # #
125 # . . # # # # .
126 . # # # # # # .
127 . . . # # . # .
128 )
129
130|:: is w solid| :solid: w yes
131|:: get sprite 1 for w|
132 :sprite data: (
133 # # # # # # # #
134 # # . . . . # #
135 # . # # # # . #
136 # . # . . # . #
137 # . # . . # . #
138 # . # # # # . #
139 # # . . . . # #
140 # # # # # # # #
141 )
142
143|:: is [ solid| :solid: [ yes
144|:: get sprite 1 for [|
145 :sprite data: (
146 # # # # # # # #
147 # # . . . . . .
148 # . # # # # # #
149 # . # . . . . .
150 # . # . . . . .
151 # . # # # # # #
152 # # . . . . . .
153 # # # # # # # #
154 )
155
156|:: is = solid| :solid: = yes
157|:: get sprite 1 for =|
158 :sprite data: (
159 # # # # # # # #
160 . . . . . . . .
161 # # # # # # # #
162 . . . . . . . .
163 . . . . . . . .
164 # # # # # # # #
165 . . . . . . . .
166 # # # # # # # #
167 )
168
169|:: is ] solid| :solid: ] yes
170|:: get sprite 1 for ]|
171 :sprite data: (
172 # # # # # # # #
173 . . . . . . # #
174 # # # # # # . #
175 . . . . . # . #
176 . . . . . # . #
177 # # # # # # . #
178 . . . . . . # #
179 # # # # # # # #
180 )
181
182
183|:: get sprite 1 for g|
184 :sprite data: (
185 . . . . . . . .
186 . . . . . . . .
187 . . . . . . . .
188 . . . . . . . .
189 . . . . . . . .
190 . . # . . . . .
191 . . # . . # . .
192 . . # . . # . .
193 )
194
195|:: get sprite 2 for g|
196 :sprite data: (
197 . . . . . . . .
198 . . . . . . . .
199 . . . . . . . .
200 . . . . . . . .
201 . . . . . . . .
202 . # . . . . . .
203 . # . . # . . .
204 . . # . . # . .
205 )
206
207|:: is e exit| :exit: e yes
208|:: is x exit| :exit: x yes
209|:: is i exit| :exit: i yes
210|:: is t exit| :exit: t yes
211|:: e goes to :current room: test2?| :go to: test
212|:: e goes to| :go to: test2
213|:: x goes to| :: e goes to
214|:: i goes to| :: e goes to
215|:: t goes to| :: e goes to
216|:: get sprite 1 for e :current room: test2?|
217 :sprite data: (
218 . . . . . . . .
219 . . . # . . . .
220 . . # # . . . .
221 . # # # # # # .
222 . # # # # # # .
223 . . # # . . . .
224 . . . # . . . .
225 . . . . . . . .
226 )
227|:: get sprite 1 for e |
228 :sprite data: (
229 . . . . . . . .
230 . . . . # . . .
231 . . . . # # . .
232 . # # # # # # .
233 . # # # # # # .
234 . . . . # # . .
235 . . . . # . . .
236 . . . . . . . .
237 )
238|:: get sprite 1 for x| :: get sprite 1 for e
239|:: get sprite 1 for i| :: get sprite 1 for e
240|:: get sprite 1 for t| :: get sprite 1 for e
241
242|| :starting room: test
243|:: player for test room| :player: p
244|:: get tiles for test|
245 :room data: (
246 w w . . . . w w
247 w . . . . g . w
248 . . [ = = ] . e
249 . c . g . . p x
250 . . . . . . . i
251 . g [ = = ] . t
252 w . . . . g . w
253 w w . . . . w w
254 )
255
256|:: player for test2 room| :player: p
257|:: get tiles for test2|
258 :room data: (
259 w w w w w w w w
260 w . . . g . . w
261 e . w . . w . w
262 x p . . . c . w
263 i . . g . . g w
264 t . w . . w . w
265 w . . . g . . w
266 w w w w w w w w
267 )
268
269
270
271|| :screen resolution: 64 64
272 :frame for sprites: 1
273
274|:: start? :starting room: $room|
275 :: change rooms :go to: $room
276
277|:: change rooms? :actors: $1 $2 $3|
278|:: change rooms? :solids: $1 $2 $3|
279|:: change rooms? :exits: $1 $2 $3|
280|:: change rooms? :player actor: $1 $2 $3|
281|:: change rooms? :current room: $_|
282|:: change rooms :go to: $room|
283 :current room: $room
284 :: player for $room room
285 :: get actor locations
286 :: set player actor
287
288|:: get actor locations :current room: $room?|
289 :: get tiles for $room :: find each actor :tile location: 0 0
290 :: get tiles for $room :: find each solid :tile location: 0 0
291 :: get tiles for $room :: find each exit :tile location: 0 0
292
293|:: find each $type :room data: ($1 $2 $3 $4 $5 $6 $7 $8)|
294 :: is $1 $type :: add to $type list :: next tile column
295 :: is $2 $type :: add to $type list :: next tile column
296 :: is $3 $type :: add to $type list :: next tile column
297 :: is $4 $type :: add to $type list :: next tile column
298 :: is $5 $type :: add to $type list :: next tile column
299 :: is $6 $type :: add to $type list :: next tile column
300 :: is $7 $type :: add to $type list :: next tile column
301 :: is $8 $type :: add to $type list :: next tile row
302 :: find each $type
303|:: find each $type :tile location: $x $y|
304
305|:: add to actor list :actor: $who yes :tile location: $x $y?|
306 :actors: $who $x $y
307|:: add to actor list :actor: $who no|
308
309|:: add to solid list :solid: $what yes :tile location: $x $y?|
310 :solids: $what $x $y
311|:: add to solid list :solid: $what no|
312
313|:: add to exit list :exit: $what yes :tile location: $x $y?|
314 :exits: $what $x $y
315|:: add to exit list :exit: $what no|
316
317
318|:: set player actor :player: $actor :actors: $actor $x $y|
319 :: rollback actors :player actor: $actor $x $y
320|:: set player actor :player: $actor :no more actors:|
321|:: set player actor?|
322 :: next actor
323
324|::start :screen resolution: $x $y?|
325 :@graphics: set-resolution fullscreen $x $y
326 ::main loop
327
328
329|:: draw? :go to: $room?|
330 :: change rooms
331
332|:: draw|
333 :: move player actor
334 :: clear the screen
335 :: draw current room
336 :: draw npcs
337 :: draw player
338 :: get dialogue :: draw dialogue
339 :: tick frame
340
341
342|:: get dialogue :player touching: $something?|
343 :: get dialogue for $something
344|:: get dialogue|
345
346|:: draw dialogue :@text to draw: $something?|
347 :@graphics: draw-text 0 48
348|:: draw dialogue :no dialogue:|
349|:: draw dialogue|
350
351
352|:: is $x actor| :actor: $x no
353|:: is $x solid| :solid: $x no
354|:: is $x exit| :exit: $x no
355|:: get dialogue for $what| :no dialogue:
356|:: get sprite $frame for $id|
357 :: get sprite 1 for $id
358
359
360|:: next actor :actors: $actor $x $y :actors: $more $_x $_y?|
361 :discarded actors: $actor $x $y
362|:: next actor :actors: $actor $x $y|
363 :discarded actors: $actor $x $y
364 :no more actors:
365|:: next actor|
366 :no more actors:
367|:: rollback actors :discarded actors: $actor $x $y|
368 :actors: $actor $x $y
369|:: rollback actors|
370
371|:: next solid :solids: $actor $x $y :solids: $more $_x $_y?|
372 :discarded solids: $actor $x $y
373|:: next solid :solids: $actor $x $y|
374 :discarded solids: $actor $x $y
375 :no more solids:
376|:: next solid|
377 :no more solids:
378|:: rollback solids? :discarded solids: $solid $x $y|
379 :solids: $solid $x $y
380|:: rollback solids|
381
382
383|:: next exit :exits: $exit $x $y :exits: $more $_x $_y?|
384 :discarded exits: $exit $x $y
385|:: next exit :exits: $exit $x $y|
386 :discarded exits: $exit $x $y
387 :no more exits:
388|:: next exit|
389 :no more exits:
390|:: rollback exits? :discarded exits: $exit $x $y|
391 :exits: $exit $x $y
392|:: rollback exits|
393
394
395|:: draw current room :current room: $room?|
396 :tile location: 0 0
397 :: get tiles for $room
398 :: draw room
399|:: draw room :room data: ($1 $2 $3 $4 $5 $6 $7 $8)|
400 :: render tile $1 to screen
401 :: render tile $2 to screen
402 :: render tile $3 to screen
403 :: render tile $4 to screen
404 :: render tile $5 to screen
405 :: render tile $6 to screen
406 :: render tile $7 to screen
407 :: render tile $8 to screen :: last column
408 :: draw room
409|:: draw room :tile location: $x $y|
410
411|:: render tile $id to screen :: last column|
412 :: is $id actor :: draw sprite $id :: next tile row
413|:: render tile $id to screen|
414 :: is $id actor :: draw sprite $id :: next tile column
415
416
417
418|:: draw npcs? :tile location: $x $y|
419|:: draw npcs :no more actors:|
420 :: rollback actors
421|:: draw npcs? :actors: $actor $x $y?|
422 :: draw sprite $actor :tile location: $x $y
423 :: next actor
424
425
426
427|:: draw player :player actor: $actor $x $y?|
428 :: draw sprite $actor :tile location: $x $y
429
430
431
432|:: draw sprite $actor :actor: $actor yes|
433 :: draw sprite .
434|:: draw sprite $actor? :actor: $actor no|
435|:: draw sprite $sprite :frame for sprites: $frame? :tile location: $x $y?|
436 :pixel location: $x $y
437 :: get sprite $frame for $sprite
438 :: draw sprite
439
440|:: draw sprite :sprite data: ($1 $2 $3 $4 $5 $6 $7 $8)|
441 :: plot $1 :: next pixel column
442 :: plot $2 :: next pixel column
443 :: plot $3 :: next pixel column
444 :: plot $4 :: next pixel column
445 :: plot $5 :: next pixel column
446 :: plot $6 :: next pixel column
447 :: plot $7 :: next pixel column
448 :: plot $8 :: next pixel row
449 :: draw sprite
450|:: draw sprite :pixel location: $x $y|
451
452
453|:: plot . :pixel location: $x $y? :color: $r $g $b|
454 :@graphics: set-pixel $x $y $r $g $b
455|:: plot # :pixel location: $x $y? :color: $r $g $b|
456 :@graphics: set-pixel $x $y $r $g $b
457|:: plot $char?|
458 :: get color for $char
459
460|:: next pixel column :@math: $x :pixel location: $_ $y|
461 :pixel location: $x $y
462|:: next pixel column? :pixel location: $x $y?|
463 :@math: add $x 1
464|:: next pixel row :@math: $y :pixel location: $_x $_y :tile location: $x $_?|
465 :pixel location: $x $y
466|:: next pixel row? :pixel location: $x $y?|
467 :@math: add $y 1
468
469|:: next tile column :@math: $x :tile location: $_ $y|
470 :tile location: $x $y
471|:: next tile column? :tile location: $x $y?|
472 :@math: add $x 8
473|:: next tile row :@math: $y :tile location: $x $_|
474 :tile location: 0 $y
475|:: next tile row? :tile location: $x $y?|
476 :@math: add $y 8
477
478|:: tick frame :frame for sprites: 1|
479 :frame for sprites: 2
480|:: tick frame :frame for sprites: 2|
481 :frame for sprites: 1
482
483
484
485|:: move player actor|
486 :: check if up is pressed :: move player
487 :: check if right is pressed :: move player
488 :: check if down is pressed :: move player
489 :: check if left is pressed :: move player
490
491|:: move player :key pressed: up :player actor: $actor $x 0?|
492|:: move player? :key pressed: up :player actor: $actor $x $y?|
493 :: move y :@math: subtract $y 8
494|:: move player :key pressed: right :player actor: $actor 56 $y?|
495|:: move player? :key pressed: right :player actor: $actor $x $y?|
496 :: move x :@math: add $x 8
497|:: move player :key pressed: down :player actor: $actor $x 56?|
498|:: move player? :key pressed: down :player actor: $actor $x $y?|
499 :: move y :@math: add $y 8
500|:: move player :key pressed: left :player actor: $actor 0 $y?|
501|:: move player? :key pressed: left :player actor: $actor $x $y?|
502 :: move x :@math: subtract $x 8
503|:: move player|
504
505
506|:: move x? :@math: $x :player actor: $actor $_ $y?|
507 :make move: $x $y
508 :: clear touching
509 :: check for solid $x $y
510 :: check for exit $x $y
511 :: check for actor $x $y
512
513|:: move y? :@math: $y :player actor: $actor $x $_?|
514 :make move: $x $y
515 :: clear touching
516 :: check for solid $x $y
517 :: check for exit $x $y
518 :: check for actor $x $y
519
520|:: move $axis :make move: $x $y :player actor: $actor $_x $_y|
521 :player actor: $actor $x $y
522|:: move $axis|
523
524|:: clear touching :player touching: $not-this|
525|:: clear touching|
526
527
528|:: check for solid $x $y :solids: $what $x $y? :make move: $x $y|
529 :: rollback solids
530|:: check for solid $x $y :no more solids:|
531 :: rollback solids
532|:: check for solid $x $y?|
533 :: next solid
534
535|:: check for exit $x $y :exits: $what $x $y? :make move: $_x $_y|
536 :: rollback exits :: $what goes to
537|:: check for exit $x $y :no more exits:|
538 :: rollback exits
539|:: check for exit $x $y?|
540 :: next exit
541
542|:: check for actor $x $y :actors: $what $x $y?|
543 :: rollback actors
544 :: touched $what
545 :player touching: $what
546|:: check for actor $x $y :no more actors:|
547 :: rollback actors
548|:: check for actor $x $y?|
549 :: next actor
nova.py 原始文件 Playground
1#!/usr/bin/env python3
2
3import sys, time, random, copy
4
5try:
6 import warnings
7 warnings.filterwarnings("ignore")
8 from os import environ
9 environ['PYGAME_HIDE_SUPPORT_PROMPT'] = '1'
10 import pygame
11 import pygame.midi
12 pygame_supported = True
13except:
14 pygame_supported = False
15 pass
16
17try:
18 import nfc, ndef, zlib, base64
19 from nfc.clf import RemoteTarget
20 nfc_supported = True
21except:
22 nfc_supported = False
23 pass
24
25def parse_container(string):
26 left = []
27 right = []
28 target = left
29 characters = (character for character in list(string) + [None])
30 delimiter = None
31 for character in characters:
32 if character in {' ', '\n', '\r', '\t'}:
33 continue
34 delimiter = character
35 break
36 if delimiter is None:
37 return None
38 for character in characters:
39 if character in {delimiter, None}:
40 if target is left:
41 target = right
42 else:
43 target = left
44 yield (left.copy(), right.copy())
45 left.clear()
46 right.clear()
47 else:
48 target.append(character)
49
50def parse_labels(rules):
51 left = []
52 right = []
53 pair = ([], [])
54 target = left
55 delimiter = None
56 for condition, result in rules:
57 for side in (condition, result):
58 characters = (character for character in side + [None])
59 state = "find delimiter"
60 for character in characters:
61 if character == None:
62 label = "".join(pair[0]).strip()
63 pattern = "".join(pair[1]).strip()
64 if not(len(label) == 0 and len(pattern) == 0):
65 target.append((label, pattern))
66 pair[0].clear()
67 pair[1].clear()
68 break
69 elif state == "find delimiter":
70 if character in {' ', '\n', '\r', '\t'}:
71 continue
72 delimiter = character
73 state = "parse label"
74 elif state == "parse label":
75 if character == delimiter:
76 state = "parse pattern"
77 continue
78 pair[0].append(character)
79 elif state == "parse pattern":
80 if character in {delimiter, None}:
81 state = "parse label"
82 label = "".join(pair[0]).strip()
83 pattern = "".join(pair[1]).strip()
84 if not(len(label) == 0 and len(pattern) == 0):
85 target.append((label, pattern))
86 pair[0].clear()
87 pair[1].clear()
88 continue
89 pair[1].append(character)
90 if target is left:
91 target = right
92 else:
93 target = left
94 yield (left.copy(), right.copy())
95 left.clear()
96 right.clear()
97
98def parse_patterns(rules):
99 for condition, result in rules:
100 left = []
101 right = []
102 preserves = []
103 for label, pattern in condition:
104 preserve = False
105 if pattern.endswith('?'):
106 pattern = pattern[:-1]
107 preserve = True
108 if (pattern.startswith('"') or pattern.startswith("'")) and (pattern.endswith('"') or pattern.endswith("'")):
109 for character in pattern[1:-1]:
110 left.append((label, [str(ord(character))]))
111 if preserve:
112 right.append((label, [str(ord(character))]))
113 elif pattern.startswith('(') and pattern.endswith(')'):
114 for token in pattern[1:-1].split():
115 left.append((label, [token]))
116 if preserve:
117 right.append((label, [token]))
118 elif pattern.startswith('.'):
119 for tuple in pattern.split('.'):
120 tuple = tuple.strip()
121 if len(tuple) != 0:
122 left.append((label, tuple.split()))
123 if preserve:
124 right.append((label, tuple.split()))
125 else:
126 left.append((label, pattern.split()))
127 if preserve:
128 preserves.append((label, pattern.split()))
129 for label, pattern in result:
130 if (pattern.startswith('"') or pattern.startswith("'")) and (pattern.endswith('"') or pattern.endswith("'")):
131 for character in pattern[1:-1]:
132 right.append((label, [str(ord(character))]))
133 elif pattern.startswith('(') and pattern.endswith(')'):
134 for token in pattern[1:-1].split():
135 right.append((label, [token]))
136 elif pattern.startswith('.'):
137 for tuple in pattern.split('.'):
138 tuple = tuple.strip()
139 if len(tuple) != 0:
140 right.append((label, tuple.split()))
141 else:
142 right.append((label, pattern.split()))
143 yield (left.copy(), right.copy() + preserves.copy())
144 left.clear()
145 right.clear()
146 preserves.clear()
147
148def parse(string):
149 return parse_patterns(parse_labels(parse_container(string)))
150
151def facts(ruleset):
152 for left, right in ruleset:
153 if not left:
154 for element in right:
155 yield element
156
157def rules(ruleset):
158 for left, right in ruleset:
159 if left:
160 yield (left, right)
161
162def match(pattern, knowledge, variables=None):
163 if variables is None:
164 variables = {}
165 label, elements = pattern
166 if label not in knowledge or not knowledge[label][0]:
167 return None
168 if knowledge[label][1] >= len(knowledge[label][0]):
169 knowledge[label][1] = 0
170 return None
171 top = knowledge[label][0][(-1 - knowledge[label][1])]
172 len_top = len(top)
173 if len_top != len(elements):
174 knowledge[label][1] = 0
175 return None
176 for index in range(len_top):
177 left = elements[index]
178 right = top[index]
179 if left[0] == '$':
180 variable = left[1:]
181 if variable not in variables:
182 variables[variable] = right
183 elif variables[variable] != right:
184 knowledge[label][1] = 0
185 return None
186 elif left != right:
187 knowledge[label][1] = 0
188 return None
189 knowledge[label][1] += 1
190 return variables
191
192def consume(pattern, knowledge):
193 if type(pattern) == str:
194 knowledge[pattern][0].pop()
195 knowledge[pattern][1] = 0
196 else:
197 label, _ = pattern
198 knowledge[label][0].pop()
199 knowledge[label][1] = 0
200
201def produce(pattern, knowledge, variables=None):
202 if variables is None:
203 variables = {}
204 label, elements = pattern
205 len_elements = len(elements)
206 fact = [None] * len_elements
207 for index in range(len_elements):
208 element = elements[index]
209 if element[0] == '$':
210 variable = element[1:]
211 if variable in variables:
212 element = variables[variable]
213 fact[index] = element
214 if label not in knowledge:
215 knowledge[label] = [[], 0]
216 knowledge[label][0].append(fact)
217 knowledge[label][1] = 0
218
219def reset(pattern, knowledge):
220 label, _ = pattern
221 if label in knowledge:
222 knowledge[label][1] = 0
223
224def prepare(ruleset, knowledge=None):
225 if knowledge == None:
226 knowledge = {}
227 for fact in reversed(list(facts(ruleset))):
228 label, elements = fact
229 if label not in knowledge:
230 knowledge[label] = [[], 0]
231 knowledge[label][0].append(elements)
232 return knowledge
233
234def print_knowledge(knowledge, debug=0, maximum=10):
235 for label, facts in knowledge.items():
236 facts = facts[0]
237 if not facts:
238 continue
239 if not label:
240 label = ":"
241 print(label + ': ', end="")
242 if len(facts) >= maximum and debug % 2:
243 print("...", len(facts), "...")
244 continue
245 if facts:
246 if len(facts[-1]) == 0:
247 print("<blank>")
248 else:
249 print(" ".join(facts[-1]))
250 for fact in reversed(facts[:-1]):
251 if len(fact) == 0:
252 fact = ["<blank>"]
253 print(' ' * (len(label) + 1), " ".join(fact))
254
255def step(ruleset, primitives=[], knowledge=None, snapshots=[], debug=0, trace=False):
256 variables = {}
257 steps = 0
258 if debug >= 3:
259 print_knowledge(knowledge, debug)
260 print("")
261 matched = False
262 for primitive in primitives:
263 steps += 1
264 if primitive(ruleset, knowledge, snapshots):
265 matched = True
266 break
267 if matched:
268 return (True, steps, knowledge)
269 for left, right in ruleset:
270 steps += 1
271 matched = True
272 variables.clear()
273 for pattern in left:
274 if match(pattern, knowledge, variables) is None:
275 matched = False
276 for pattern in left:
277 reset(pattern, knowledge)
278 break
279 if matched:
280 for pattern in left:
281 consume(pattern, knowledge)
282 for pattern in reversed(right):
283 produce(pattern, knowledge, variables)
284 break
285 return (matched, steps, knowledge)
286
287def run(ruleset, primitives=[], knowledge=None, debug=0, trace=False):
288 knowledge = prepare(ruleset, knowledge)
289 ruleset = list(rules(ruleset))
290 matched = True
291 steps = 0
292 snapshots = []
293 while matched:
294 matched, completed, knowledge = step(ruleset, primitives, knowledge, snapshots, debug, trace)
295 steps += completed
296 if trace:
297 snapshots.append(copy.deepcopy(knowledge))
298 if debug:
299 print("Took", steps, "steps.")
300 return (knowledge, snapshots)
301
302def usage(name):
303 print(name, ":: a nova interpreter")
304 print("usage:")
305 print('\t' + name, "<file> [-d] [-r]")
306
307def math(ruleset, knowledge, snapshots=[], trace=False):
308 if (variables := match(("@math", ["$operation", "$x", "$y"]), knowledge)) is not None:
309 try:
310 operation = variables["operation"]
311 x = int(variables["x"])
312 y = int(variables["y"])
313 if operation == "add":
314 variables["z"] = str(x + y)
315 elif operation == "subtract":
316 variables["z"] = str(x - y)
317 elif operation == "multiply":
318 variables["z"] = str(x * y)
319 elif operation == "divide":
320 variables["z"] = str(x // y)
321 elif operation == "modulo":
322 variables["z"] = str(x % y)
323 elif operation == "compare":
324 if x < y:
325 variables["z"] = "less"
326 elif x == y:
327 variables["z"] = "equal"
328 else:
329 variables["z"] = "greater"
330 elif operation == "random":
331 if y < x:
332 x, y = y, x
333 variables["z"] = str(random.randrange(x, y))
334 consume("@math", knowledge)
335 produce(("@math", ["$z"]), knowledge, variables)
336 return True
337 except Exception as e:
338 print(e)
339 pass
340 return False
341
342def arrays():
343 arrays = {}
344 def create(ruleset, knowledge, snapshots=[], trace=False):
345 nonlocal arrays
346 if (variables := match(("@array", ["create", "$array", "$size"]), knowledge)) is not None:
347 try:
348 array = variables["array"]
349 size = int(variables["size"])
350 consume("@array", knowledge)
351 if array in arrays:
352 produce(("@array", ["$array", "exists"]), knowledge, variables)
353 else:
354 arrays[array] = [None] * size
355 return True
356 except:
357 pass
358 return False
359 def set(ruleset, knowledge, snapshots=[], trace=False):
360 nonlocal arrays
361 if (variables := match(("@array", ["set", "$array", "$index", "$value"]), knowledge)) is not None:
362 try:
363 array = variables["array"]
364 index = int(variables["index"])
365 value = variables["value"]
366 consume("@array", knowledge)
367 if array not in arrays:
368 produce(("@array", ["$array", "not", "found"]), knowledge, variables)
369 elif index >= len(arrays[array]):
370 produce(("@array", ["$index", "out", "of", "bounds", "for", "$array"]), knowledge, variables)
371 else:
372 arrays[array][index] = value
373 return True
374 except:
375 pass
376 return False
377 def get(ruleset, knowledge, snapshots=[], trace=False):
378 nonlocal arrays
379 if (variables := match(("@array", ["get", "$array", "$index"]), knowledge)) is not None:
380 try:
381 array = variables["array"]
382 index = int(variables["index"])
383 consume("@array", knowledge)
384 if array not in arrays:
385 produce(("@array", ["$array", "not", "found"]), knowledge, variables)
386 elif index >= len(arrays[array]):
387 produce(("@array", ["$index", "out", "of", "bounds", "for", "$array"]), knowledge, variables)
388 else:
389 if arrays[array][index] == None:
390 produce(("@array", ["$array", "$index"]), knowledge, variables)
391 else:
392 variables["value"] = str(arrays[array][index])
393 produce(("@array", ["$array", "$index", "$value"]), knowledge, variables)
394 return True
395 except:
396 pass
397 return False
398 return [
399 create,
400 set,
401 get
402 ]
403
404def graphics():
405 keys = {}
406 mouse_buttons = {}
407 screen = None
408 pixels = None
409 clock = None
410 font = None
411 resolution = (0, 0)
412 def poll_input(ruleset, knowledge, snapshots=[]):
413 nonlocal keys
414 nonlocal mouse_buttons
415 if match(("@input", ["poll-input"]), knowledge) is not None:
416 consume("@input", knowledge)
417 for event in pygame.event.get():
418 if event.type == pygame.QUIT:
419 produce(("@signal", ["quit"]), knowledge)
420 keys = pygame.key.get_pressed()
421 mouse_buttons = pygame.mouse.get_pressed()
422 return True
423 return False
424 def check_key(ruleset, knowledge, snapshots=[]):
425 nonlocal keys
426 if (variables := match(("@input", ["check-key", "$key"]), knowledge)) is not None:
427 consume("@input", knowledge)
428 keycode = pygame.key.key_code(variables["key"])
429 if keys[keycode]:
430 produce(("@input", ["key-pressed", "$key"]), knowledge, variables)
431 else:
432 produce(("@input", ["key-released", "$key"]), knowledge, variables)
433 return True
434 return False
435 def check_mouse_button(ruleset, knowledge, snapshots=[]):
436 nonlocal mouse_buttons
437 if (variables := match(("@input", ["check-mouse-button", "$button"]), knowledge)) is not None:
438 consume("@input", knowledge)
439 button = int(variables["button"])
440 if mouse_buttons[button]:
441 produce(("@input", ["mouse-button-pressed", "$button"]), knowledge, variables)
442 else:
443 produce(("@input", ["mouse-button-released", "$button"]), knowledge, variables)
444 return True
445 return False
446 def get_mouse_position(ruleset, knowledge, snapshots=[]):
447 if (variables := match(("@input", ["get-mouse-position"]), knowledge)) is not None:
448 consume("@input", knowledge)
449 position = pygame.mouse.get_pos()
450 variables["x"], variables["y"] = (str(position[0]), str(position[1]))
451 produce(("@input", ["mouse-position", "$x", "$y"]), knowledge, variables)
452 return True
453 return False
454 def set_pixel(ruleset, knowledge, snapshots=[]):
455 nonlocal pixels
456 if (variables := match(("@graphics", ["set-pixel", "$x", "$y", "$r", "$g", "$b"]), knowledge)) is not None:
457 try:
458 x = int(variables["x"])
459 y = int(variables["y"])
460 r = int(variables["r"])
461 g = int(variables["g"])
462 b = int(variables["b"])
463 pixels[x % resolution[0], y % resolution[1]] = (r % 256, g % 256, b % 256)
464 consume("@graphics", knowledge)
465 return True
466 except:
467 pass
468 return False
469 def draw_line(ruleset, knowledge, snapshots=[]):
470 nonlocal screen
471 if (variables := match(("@graphics", ["draw-line", "$x1", "$y1", "$x2", "$y2", "$r", "$g", "$b", "$w"]), knowledge)) is not None:
472 try:
473 x1 = int(variables["x1"])
474 y1 = int(variables["y1"])
475 x2 = int(variables["x2"])
476 y2 = int(variables["y2"])
477 r = int(variables["r"])
478 g = int(variables["g"])
479 b = int(variables["b"])
480 w = int(variables["w"])
481 pygame.draw.line(screen, (r % 256, g % 256, b % 256), (x1, y1), (x2, y2), w)
482 consume("@graphics", knowledge)
483 return True
484 except:
485 pass
486 return False
487 def draw_rect(ruleset, knowledge, snapshots=[]):
488 nonlocal screen
489 if (variables := match(("@graphics", ["draw-rect", "$x1", "$y1", "$x2", "$y2", "$r", "$g", "$b", "$w"]), knowledge)) is not None:
490 try:
491 x1 = int(variables["x1"])
492 y1 = int(variables["y1"])
493 x2 = int(variables["x2"])
494 y2 = int(variables["y2"])
495 r = int(variables["r"])
496 g = int(variables["g"])
497 b = int(variables["b"])
498 w = int(variables["w"])
499 pygame.draw.rect(screen, (r % 256, g % 256, b % 256), (x1, y1, x2, y2), w)
500 consume("@graphics", knowledge)
501 return True
502 except:
503 pass
504 return False
505 def draw_circle(ruleset, knowledge, snapshots=[]):
506 nonlocal screen
507 if (variables := match(("@graphics", ["draw-circle", "$x", "$y", "$d", "$r", "$g", "$b", "$w"]), knowledge)) is not None:
508 try:
509 x = int(variables["x"])
510 y = int(variables["y"])
511 d = int(variables["d"])
512 r = int(variables["r"])
513 g = int(variables["g"])
514 b = int(variables["b"])
515 w = int(variables["w"])
516 pygame.draw.circle(screen, (r % 256, g % 256, b % 256), (x, y), d, w)
517 consume("@graphics", knowledge)
518 return True
519 except:
520 pass
521 return False
522 def clear_screen(ruleset, knowledge, snapshots=[]):
523 nonlocal screen
524 if (variables := match(("@graphics", ["clear-screen", "$r", "$g", "$b"]), knowledge)) is not None:
525 try:
526 r = int(variables["r"])
527 g = int(variables["g"])
528 b = int(variables["b"])
529 screen.fill((r % 256, g % 256, b % 256))
530 consume("@graphics", knowledge)
531 return True
532 except:
533 pass
534 return False
535 def draw_fps(ruleset, knowledge, snapshots=[]):
536 nonlocal pixels
537 nonlocal screen
538 nonlocal clock
539 nonlocal font
540 if match(("@graphics", ["draw-fps"]), knowledge) is not None:
541 if clock is None:
542 clock = pygame.time.Clock()
543 clock.tick()
544 if font is None:
545 font = pygame.font.SysFont("m3x6", 16)
546 framerate = clock.get_fps()
547 if framerate <= 1_000_000:
548 fps = font.render(str(int(clock.get_fps())) , 1, pygame.Color("RED"))
549 pixels.close()
550 screen.blit(fps, (0, 0))
551 pixels = pygame.PixelArray(screen)
552 consume("@graphics", knowledge)
553 return True
554 return False
555 def display(ruleset, knowledge, snapshots=[]):
556 nonlocal pixels
557 if match(("@graphics", ["display"]), knowledge) is not None:
558 pixels.close()
559 pygame.display.flip()
560 pixels = pygame.PixelArray(screen)
561 consume("@graphics", knowledge)
562 return True
563 return False
564 def draw_text(ruleset, knowledge, snapshots=[]):
565 nonlocal font
566 nonlocal screen
567 nonlocal pixels
568 if (variables := match(("@graphics", ["draw-text", "$x", "$y"]), knowledge)) is not None:
569 x = int(variables["x"])
570 y = int(variables["y"])
571 if font is None:
572 font = pygame.font.SysFont("m3x6", 16)
573 text = ''.join(chr(int(n[0])) for n in reversed(knowledge["@text to draw"][0]))
574 knowledge["@text to draw"] = [[], 0]
575 drawn_text = font.render(text, False, pygame.Color("WHITE"))
576 pixels.close()
577 pygame.draw.rect(screen, (0, 0, 0), (0, 48, 64, 64))
578 screen.blit(drawn_text, (x, y))
579 pixels = pygame.PixelArray(screen)
580 consume("@graphics", knowledge)
581 return True
582 return False
583
584
585 def set_resolution(ruleset, knowledge, snapshots=[]):
586 nonlocal screen
587 nonlocal pixels
588 nonlocal resolution
589 if (variables := match(("@graphics", ["set-resolution", "$x", "$y"]), knowledge)) is not None:
590 try:
591 if screen is None:
592 pygame.init()
593 x = int(variables["x"])
594 y = int(variables["y"])
595 screen = pygame.display.set_mode((x, y))
596 pygame.display.set_caption("Nova")
597 icon = pygame.Surface((32, 32))
598 icon.fill("black")
599 icon.set_colorkey((0, 0, 0))
600 pygame.display.set_icon(icon)
601 pixels = pygame.PixelArray(screen)
602 resolution = (x, y)
603 consume("@graphics", knowledge)
604 return True
605 except:
606 pass
607 elif (variables := match(("@graphics", ["set-resolution", "fullscreen", "$x", "$y"]), knowledge)) is not None:
608 try:
609 if screen is None:
610 pygame.init()
611 x = int(variables["x"])
612 y = int(variables["y"])
613 screen = pygame.display.set_mode((x, y), flags=pygame.FULLSCREEN | pygame.SCALED)
614 pygame.display.set_caption("Nova")
615 icon = pygame.Surface((32, 32))
616 icon.fill("black")
617 icon.set_colorkey((0, 0, 0))
618 pygame.display.set_icon(icon)
619 pixels = pygame.PixelArray(screen)
620 resolution = (x, y)
621 consume("@graphics", knowledge)
622 return True
623 except:
624 pass
625 elif (variables := match(("@graphics", ["set-resolution", "fullscreen"]), knowledge)) is not None:
626 try:
627 if screen is None:
628 pygame.init()
629 screen = pygame.display.set_mode((0, 0), flags=pygame.FULLSCREEN)
630 pygame.display.set_caption("Nova")
631 icon = pygame.Surface((32, 32))
632 icon.fill("black")
633 icon.set_colorkey((0, 0, 0))
634 pygame.display.set_icon(icon)
635 pixels = pygame.PixelArray(screen)
636 resolution = pygame.display.get_surface().get_size()
637 consume("@graphics", knowledge)
638 return True
639 except:
640 pass
641 return False
642 return [
643 set_pixel,
644 draw_line,
645 draw_rect,
646 draw_circle,
647 draw_text,
648 display,
649 poll_input,
650 draw_fps,
651 clear_screen,
652 check_key,
653 check_mouse_button,
654 get_mouse_position,
655 set_resolution
656 ]
657
658def midi():
659 output = None
660 def set_output(ruleset, knowledge, snapshots=[]):
661 nonlocal output
662 if (variables := match(("@midi", ["set-output", "$x"]), knowledge)) is not None:
663 try:
664 if output is None:
665 pygame.midi.init()
666 else:
667 del output
668 output = pygame.midi.Output(int(variables["x"]))
669 consume("@midi", knowledge)
670 return True
671 except:
672 pass
673 return False
674 def abort(ruleset, knowledge, snapshots=[]):
675 nonlocal output
676 if (variables := match(("@midi", ["abort"]), knowledge)) is not None:
677 try:
678 output.abort()
679 consume("@midi", knowledge)
680 return True
681 except:
682 pass
683 return False
684 def set_instrument(ruleset, knowledge, snapshots=[]):
685 nonlocal output
686 if (variables := match(("@midi", ["set-instrument", "$x"]), knowledge)) is not None:
687 try:
688 output.set_instrument(int(variables["x"]))
689 consume("@midi", knowledge)
690 return True
691 except:
692 pass
693 return False
694 def note(ruleset, knowledge, snapshots=[]):
695 nonlocal output
696 if (variables := match(("@midi", ["note", "$x", "$y", "$z", "$w"]), knowledge)) is not None:
697 try:
698 state = variables["x"]
699 note = int(variables["y"])
700 velocity = int(variables["z"])
701 channel = int(variables["w"])
702 if state == "on":
703 output.note_on(note, velocity, channel)
704 elif state == "off":
705 output.note_off(note, velocity, channel)
706 else:
707 return False
708 consume("@midi", knowledge)
709 return True
710 except:
711 pass
712 elif (variables := match(("@midi", ["note", "$x", "$y", "$z"]), knowledge)) is not None:
713 try:
714 state = variables["x"]
715 note = int(variables["y"])
716 velocity = int(variables["z"])
717 if state == "on":
718 output.note_on(note, velocity)
719 elif state == "off":
720 output.note_off(note, velocity)
721 else:
722 return False
723 consume("@midi", knowledge)
724 return True
725 except:
726 pass
727 return False
728 return [
729 set_output,
730 abort,
731 set_instrument,
732 note
733 ]
734
735def _time():
736 def sleep(ruleset, knowledge, snapshots=[]):
737 if (variables := match(("@time", ["sleep", "$x", "$y"]), knowledge)) is not None:
738 try:
739 duration = int(variables["x"])
740 unit = variables["y"]
741 if unit == "seconds":
742 time.sleep(duration)
743 elif unit == "milliseconds":
744 time.sleep(0.001 * duration)
745 else:
746 return False
747 consume("@time", knowledge)
748 return True
749 except:
750 pass
751 return False
752 return [
753 sleep
754 ]
755
756def stdio():
757 def read(ruleset, knowledge, snapshots=[]):
758 if (variables := match(("@stdio", ["read", "$x"]), knowledge)) is not None:
759 try:
760 amount = int(variables["x"])
761 bytes = sys.stdin.read(amount)
762 consume("@stdio", knowledge)
763 for byte in reversed(bytes.encode()):
764 variables["x"] = str(byte)
765 produce(("@stdio", ["$x"]), knowledge, variables)
766 return True
767 except KeyboardInterrupt:
768 consume("@stdio", knowledge)
769 return True
770 except:
771 pass
772 elif (variables := match(("@stdio", ["read"]), knowledge)) is not None:
773 try:
774 variables["x"] = str(ord(sys.stdin.read(1)))
775 consume("@stdio", knowledge)
776 produce(("@stdio", ["$x"]), knowledge, variables)
777 return True
778 except KeyboardInterrupt:
779 consume("@stdio", knowledge)
780 return True
781 except:
782 pass
783 return False
784 def write(ruleset, knowledge, snapshots=[]):
785 if (variables := match(("@stdio", ["write", "$x", "$y"]), knowledge)) is not None:
786 try:
787 byte = int(variables["x"])
788 length = int(variables["y"])
789 if byte < 0:
790 sys.stdout.buffer.write(byte.to_bytes(length, signed=True))
791 else:
792 sys.stdout.buffer.write(byte.to_bytes(length))
793 sys.stdout.buffer.flush()
794 consume("@stdio", knowledge)
795 variables["x"] = str(length)
796 produce(("@stdio", ["wrote", "$x"]), knowledge, variables)
797 return True
798 except OverflowError:
799 length = (byte.bit_length() + 7) // 8
800 if length == 0:
801 length = 1
802 if byte < 0:
803 sys.stdout.buffer.write(byte.to_bytes(length, signed=True))
804 else:
805 sys.stdout.buffer.write(byte.to_bytes(length))
806 sys.stdout.buffer.flush()
807 consume("@stdio", knowledge)
808 variables["x"] = str(length)
809 produce(("@stdio", ["wrote", "$x"]), knowledge, variables)
810 return True
811 except:
812 pass
813 elif (variables := match(("@stdio", ["write", "$x"]), knowledge)) is not None:
814 try:
815 byte = int(variables["x"])
816 length = (byte.bit_length() + 7) // 8
817 if length == 0:
818 length = 1
819 if byte < 0:
820 sys.stdout.buffer.write(byte.to_bytes(length, signed=True))
821 else:
822 sys.stdout.buffer.write(byte.to_bytes(length))
823 sys.stdout.buffer.flush()
824 consume("@stdio", knowledge)
825 variables["x"] = str(length)
826 produce(("@stdio", ["wrote", "$x"]), knowledge, variables)
827 return True
828 except:
829 pass
830 return False
831 return [
832 read, write
833 ]
834
835def _nfc():
836 clf = None
837 last_card = None
838 def nfc_read_card():
839 nonlocal clf
840 payload = []
841 identifier = None
842 card_types = [RemoteTarget('106A'), RemoteTarget('106B'), RemoteTarget('212F')]
843 target = clf.sense(*card_types)
844 if target is not None:
845 tag = nfc.tag.activate(clf, target)
846 if tag is not None and tag.ndef is not None:
847 for record in tag.ndef.records:
848 text = zlib.decompress(base64.b64decode(record.text)).decode()
849 payload += list(parse(text))
850 identifier = tag.identifier
851 return (payload, identifier)
852 def open(ruleset, knowledge, snapshots=[]):
853 nonlocal clf
854 if (variables := match(("@nfc", ["open"]), knowledge)) is not None:
855 try:
856 consume("@nfc", knowledge)
857 clf = nfc.ContactlessFrontend('usb')
858 return True
859 except:
860 produce(("@nfc", ["no-device"]), knowledge)
861 return True
862 return False
863 def close(ruleset, knowledge, snapshots=[]):
864 nonlocal clf
865 if (variables := match(("@nfc", ["close"]), knowledge)) is not None:
866 try:
867 consume("@nfc", knowledge)
868 clf.close()
869 return True
870 except:
871 produce(("@nfc", ["no-device"]), knowledge)
872 return True
873 return False
874 def read_card(ruleset, knowledge, snapshots=[]):
875 nonlocal last_card
876 if (variables := match(("@nfc", ["read-card"]), knowledge)) is not None:
877 try:
878 consume("@nfc", knowledge)
879 (payload, identifier) = nfc_read_card()
880 variables["x"] = "".join([hex(byte)[2:] for byte in identifier])
881 last_card = payload
882 produce(("@nfc", ["card", "$x"]), knowledge, variables)
883 return True
884 except:
885 produce(("@nfc", ["read-failed"]), knowledge)
886 return True
887 return False
888 def load_card_rules(ruleset, knowledge, snapshots=[]):
889 nonlocal last_card
890 if (variables := match(("@nfc", ["load-rules"]), knowledge)) is not None:
891 try:
892 for rule in rules(reversed(last_card)):
893 ruleset.insert(0, rule)
894 consume("@nfc", knowledge)
895 return True
896 except:
897 pass
898 return False
899 def load_card_facts(ruleset, knowledge, snapshots=[]):
900 if (variables := match(("@nfc", ["load-facts"]), knowledge)) is not None:
901 try:
902 prepare(last_card, knowledge)
903 consume("@nfc", knowledge)
904 return True
905 except:
906 pass
907 return False
908 return [
909 open,
910 close,
911 read_card,
912 load_card_rules,
913 load_card_facts
914 ]
915
916def repl(rulesets, primitives, debug):
917 try:
918 knowledge, _ = run(rulesets)
919 print_knowledge(knowledge, debug)
920 current_stack = ""
921 command = input("::> ")
922 while command != "@quit":
923 if command in {"@run", '!'}:
924 knowledge, _ = run(rulesets, primitives, knowledge)
925 if debug:
926 print_knowledge(knowledge, debug)
927 if match(("@signal", ["quit"]), knowledge) != None:
928 break
929 elif command.startswith('@'):
930 current_stack = command[1:]
931 elif command.startswith('.'):
932 command = command[1:]
933 knowledge, _ = run(list(parse(command)) + list(rules(rulesets)), primitives, knowledge, debug)
934 if debug:
935 print_knowledge(knowledge, debug)
936 if match(("@signal", ["quit"]), knowledge) != None:
937 break
938 elif command.startswith(':'):
939 command = command[1:]
940 rulesets = list(parse(command)) + rulesets
941 knowledge, _ = run(rulesets, primitives, knowledge, debug)
942 if debug:
943 print_knowledge(knowledge, debug)
944 if match(("@signal", ["quit"]), knowledge) != None:
945 break
946 elif len(command) != 0:
947 command = "||:" + current_stack + ':' + command
948 knowledge, _ = run(list(parse(command)) + list(rules(rulesets)), primitives, knowledge, debug)
949 if debug:
950 print_knowledge(knowledge, debug)
951 if match(("@signal", ["quit"]), knowledge) != None:
952 break
953 else:
954 if debug:
955 print_knowledge(knowledge, debug)
956 command = input(":" + current_stack + ":> ")
957 except EOFError:
958 pass
959 except KeyboardInterrupt:
960 pass
961
962def main(name, arguments):
963 primitives = _time() + [math] + arrays() + stdio()
964 if pygame_supported:
965 primitives += graphics() + midi()
966 if nfc_supported:
967 primitives += _nfc()
968 rulesets = []
969 debug = 0
970 prompt = False
971 trace = False
972 if not arguments:
973 usage(name)
974 return
975 for argument in arguments:
976 if argument == '-d':
977 debug += 1
978 elif argument == '-r':
979 prompt = True
980 elif argument == '-t':
981 trace = True
982 else:
983 with open(argument) as file:
984 rulesets += list(parse(file.read()))
985 if prompt:
986 repl(rulesets, primitives, debug)
987 else:
988 if len(rulesets) == 0:
989 usage(name)
990 return
991 if debug:
992 knowledge, snapshots = run(rulesets, primitives, None, debug, trace)
993 if trace:
994 for index in range(len(snapshots)):
995 print("Snapshot", str(index) + ':')
996 print("----------------")
997 print_knowledge(snapshots[index], debug)
998 print("")
999 else:
1000 print_knowledge(knowledge, debug)
1001 else:
1002 run(rulesets, primitives, None, debug, trace)
1003
1004if __name__ == "__main__":
1005 main(sys.argv[0], sys.argv[1:])
1006