2023-08-16 14:52:56 -04:00
|
|
|
from st3m.application import Application, ApplicationContext
|
|
|
|
from st3m.run import run_view
|
2023-08-17 15:29:43 -04:00
|
|
|
import leds
|
2023-08-16 14:52:56 -04:00
|
|
|
import os.path
|
2023-08-16 09:45:20 -04:00
|
|
|
|
|
|
|
UP = 0
|
|
|
|
LEFT = 1
|
|
|
|
DOWN = 2
|
|
|
|
RIGHT = 3
|
|
|
|
|
|
|
|
|
|
|
|
class Random:
|
|
|
|
def __init__(self):
|
|
|
|
self._state = 0x9ec5_9ec5 # (two gecs)
|
|
|
|
|
|
|
|
# idk its fine its just for choosing delay and direction
|
|
|
|
def next(self):
|
|
|
|
self._state *= 37
|
|
|
|
self._state &= 0xffff_ffff
|
|
|
|
return self._state >> 24
|
|
|
|
|
|
|
|
def direction(self):
|
|
|
|
return self.next() & 3
|
|
|
|
|
|
|
|
def delay(self):
|
2023-08-16 14:52:56 -04:00
|
|
|
return Quox.TURN_DELAY_BASE + self.next()
|
2023-08-16 09:45:20 -04:00
|
|
|
|
|
|
|
# screen coords range ±120 each side
|
|
|
|
|
2023-08-16 14:52:56 -04:00
|
|
|
class Quox(Application):
|
2023-08-16 14:27:13 -04:00
|
|
|
STEP_DELAY = 250
|
2023-08-16 09:45:20 -04:00
|
|
|
TURN_DELAY_BASE = 1400
|
2023-08-16 14:27:13 -04:00
|
|
|
MOVE_DELAY = 100
|
|
|
|
TOP = -90
|
|
|
|
BOTTOM = 70 # so its always a bit visible
|
|
|
|
LEFT = -90
|
|
|
|
RIGHT = 70
|
2023-08-16 09:45:20 -04:00
|
|
|
|
2023-08-17 15:04:00 -04:00
|
|
|
# start at top and go clockwise, 100px from center, 36° apart
|
|
|
|
# y = 100 cos θ; x = 100 sin θ
|
2023-08-17 15:29:43 -04:00
|
|
|
BOX_COORDS = \
|
2023-08-17 15:04:00 -04:00
|
|
|
[(0, -100), (59, -81), (95, -31), (95, 31), (59, 81),
|
|
|
|
(0, 100), (-59, 81), (-95, 31), (-95, -31), (-59, -81)]
|
|
|
|
|
2023-08-17 05:16:05 -04:00
|
|
|
@staticmethod
|
|
|
|
def image_path(direction, step):
|
|
|
|
dir = os.path.dirname(__file__)
|
|
|
|
bases = {UP: 'back', LEFT: 'left', DOWN: 'front', RIGHT: 'right'}
|
|
|
|
base = bases[direction]
|
|
|
|
return f"{dir}/sprites/{base}{step}.png"
|
|
|
|
|
2023-08-16 14:52:56 -04:00
|
|
|
def __init__(self, app_ctx):
|
|
|
|
super().__init__(app_ctx)
|
2023-08-16 09:45:20 -04:00
|
|
|
self.random = Random()
|
2023-08-17 05:16:05 -04:00
|
|
|
|
2023-08-17 15:04:00 -04:00
|
|
|
self.boxes = []
|
|
|
|
self.x = 0
|
|
|
|
self.y = 0
|
2023-08-17 05:16:05 -04:00
|
|
|
|
2023-08-16 09:45:20 -04:00
|
|
|
self.step = 0
|
2023-08-16 14:52:56 -04:00
|
|
|
self.step_delay = Quox.STEP_DELAY
|
|
|
|
self.move_delay = Quox.MOVE_DELAY
|
2023-08-17 05:16:05 -04:00
|
|
|
|
2023-08-17 15:04:00 -04:00
|
|
|
self.new_direction()
|
|
|
|
self.new_turn_delay()
|
|
|
|
|
2023-08-17 15:29:43 -04:00
|
|
|
leds.set_gamma(2, 2, 2)
|
|
|
|
leds.set_auto_update(False)
|
|
|
|
leds.set_slew_rate(255)
|
|
|
|
|
2023-08-17 15:04:00 -04:00
|
|
|
def adjusted_x(self):
|
|
|
|
if self.direction == UP or self.direction == DOWN:
|
|
|
|
return self.x - 32
|
|
|
|
else:
|
|
|
|
return self.x - 44
|
|
|
|
|
|
|
|
def adjusted_y(self):
|
|
|
|
if self.direction == UP or self.direction == DOWN:
|
|
|
|
return self.y - 30
|
|
|
|
else:
|
|
|
|
return self.y - 28
|
2023-08-16 09:45:20 -04:00
|
|
|
|
|
|
|
def draw(self, ctx):
|
|
|
|
self.clear(ctx)
|
|
|
|
# self.text(ctx)
|
2023-08-17 15:04:00 -04:00
|
|
|
self.quox_sprite(ctx)
|
2023-08-16 09:45:20 -04:00
|
|
|
|
|
|
|
def clear(self, ctx):
|
|
|
|
ctx.rgb(0, 0, 0) \
|
|
|
|
.rectangle(-120, -120, 240, 240) \
|
|
|
|
.fill()
|
|
|
|
|
2023-08-17 15:04:00 -04:00
|
|
|
def quox_sprite(self, ctx):
|
2023-08-17 05:16:05 -04:00
|
|
|
path = Quox.image_path(self.direction, self.step)
|
2023-08-17 15:04:00 -04:00
|
|
|
ctx.image(path, self.adjusted_x(), self.adjusted_y(), -1, -1)
|
2023-08-16 13:51:55 -04:00
|
|
|
|
2023-08-16 09:45:20 -04:00
|
|
|
@staticmethod
|
|
|
|
def coord(d):
|
|
|
|
if d == UP:
|
|
|
|
return (-20, -100)
|
|
|
|
elif d == LEFT:
|
|
|
|
return (-100, -20)
|
|
|
|
elif d == RIGHT:
|
|
|
|
return (100, 20)
|
|
|
|
elif d == DOWN:
|
|
|
|
return (20, 100)
|
|
|
|
|
|
|
|
def text(self, ctx):
|
2023-08-17 15:04:00 -04:00
|
|
|
msg = f"{self.target()}"
|
2023-08-16 13:51:55 -04:00
|
|
|
ctx.font_size = 16.0
|
|
|
|
ctx.text_align = ctx.CENTER
|
|
|
|
ctx.rgb(1, 1, 1).move_to(0, -100).text(msg)
|
2023-08-16 09:45:20 -04:00
|
|
|
|
|
|
|
def think(self, state, Δ):
|
2023-08-16 14:52:56 -04:00
|
|
|
super().think(state, Δ)
|
2023-08-16 09:45:20 -04:00
|
|
|
self.update_delay(Δ)
|
2023-08-17 15:04:00 -04:00
|
|
|
self.add_boxes(state)
|
2023-08-17 09:36:30 -04:00
|
|
|
self.pick_direction()
|
|
|
|
self.pick_step()
|
|
|
|
self.maybe_move()
|
2023-08-17 15:29:43 -04:00
|
|
|
self.update_leds()
|
2023-08-16 09:45:20 -04:00
|
|
|
|
2023-08-17 15:04:00 -04:00
|
|
|
def add_boxes(self, state):
|
|
|
|
for i, button in enumerate(state.captouch.petals):
|
2023-08-17 15:29:43 -04:00
|
|
|
box = Quox.BOX_COORDS[i]
|
2023-08-17 15:04:00 -04:00
|
|
|
if button.pressed:
|
|
|
|
if box not in self.boxes:
|
|
|
|
self.boxes.append(box)
|
|
|
|
else:
|
|
|
|
if box in self.boxes:
|
|
|
|
self.boxes.remove(box)
|
|
|
|
|
2023-08-16 09:45:20 -04:00
|
|
|
def update_delay(self, Δ):
|
|
|
|
self.turn_delay -= Δ
|
|
|
|
self.step_delay -= Δ
|
2023-08-16 14:27:13 -04:00
|
|
|
self.move_delay -= Δ
|
2023-08-17 09:36:30 -04:00
|
|
|
|
|
|
|
def pick_direction(self):
|
2023-08-17 15:04:00 -04:00
|
|
|
if self.turn_delay <= 0 or not self.towards_target():
|
|
|
|
old_delay = min(self.turn_delay, 0)
|
|
|
|
self.new_direction()
|
|
|
|
self.new_turn_delay(old_delay)
|
2023-08-17 09:36:30 -04:00
|
|
|
|
|
|
|
def pick_step(self):
|
2023-08-16 09:45:20 -04:00
|
|
|
if self.step_delay <= 0:
|
2023-08-16 14:52:56 -04:00
|
|
|
self.step_delay = Quox.STEP_DELAY
|
2023-08-16 13:51:55 -04:00
|
|
|
self.step = (self.step + 1) & 3
|
2023-08-17 09:36:30 -04:00
|
|
|
|
|
|
|
def maybe_move(self):
|
2023-08-16 14:27:13 -04:00
|
|
|
if self.move_delay <= 0:
|
2023-08-16 14:52:56 -04:00
|
|
|
self.move_delay += Quox.MOVE_DELAY
|
2023-08-16 14:27:13 -04:00
|
|
|
self.move()
|
2023-08-16 09:45:20 -04:00
|
|
|
|
2023-08-17 15:04:00 -04:00
|
|
|
def new_direction(self):
|
|
|
|
d = self.random.direction()
|
|
|
|
while not self.towards(d, self.target()):
|
|
|
|
d = self.random.direction()
|
|
|
|
self.direction = d
|
2023-08-16 09:45:20 -04:00
|
|
|
|
2023-08-17 15:04:00 -04:00
|
|
|
def new_turn_delay(self, subtract=0):
|
2023-08-16 14:27:13 -04:00
|
|
|
self.turn_delay = self.random.delay() + subtract
|
|
|
|
|
|
|
|
def at_edge(self):
|
2023-08-16 14:52:56 -04:00
|
|
|
return ((self.direction == UP and self.y <= Quox.TOP) or
|
|
|
|
(self.direction == DOWN and self.y >= Quox.BOTTOM) or
|
|
|
|
(self.direction == LEFT and self.x <= Quox.LEFT) or
|
|
|
|
(self.direction == RIGHT and self.x >= Quox.RIGHT))
|
2023-08-16 14:27:13 -04:00
|
|
|
|
|
|
|
def flip_direction(self):
|
|
|
|
if self.direction == UP:
|
|
|
|
self.direction = DOWN
|
|
|
|
elif self.direction == LEFT:
|
|
|
|
self.direction = RIGHT
|
|
|
|
elif self.direction == DOWN:
|
|
|
|
self.direction = UP
|
|
|
|
elif self.direction == RIGHT:
|
|
|
|
self.direction = LEFT
|
|
|
|
|
|
|
|
def move(self):
|
|
|
|
if self.at_edge():
|
|
|
|
self.flip_direction()
|
|
|
|
|
|
|
|
if self.direction == UP:
|
|
|
|
self.y -= 5
|
|
|
|
elif self.direction == LEFT:
|
|
|
|
self.x -= 5
|
|
|
|
elif self.direction == DOWN:
|
|
|
|
self.y += 5
|
|
|
|
elif self.direction == RIGHT:
|
|
|
|
self.x += 5
|
2023-08-16 09:45:20 -04:00
|
|
|
|
2023-08-17 15:04:00 -04:00
|
|
|
def target(self):
|
2023-08-17 15:29:43 -04:00
|
|
|
if self.boxes:
|
|
|
|
return self.boxes[0]
|
|
|
|
else:
|
|
|
|
return None
|
2023-08-17 15:04:00 -04:00
|
|
|
|
|
|
|
def towards(self, direction, point):
|
|
|
|
if not point:
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
x, y = point
|
|
|
|
if direction == UP:
|
|
|
|
return self.y > y
|
|
|
|
elif direction == LEFT:
|
|
|
|
return self.x > x
|
|
|
|
elif direction == RIGHT:
|
|
|
|
return self.x < x
|
|
|
|
elif direction == DOWN:
|
|
|
|
return self.y < y
|
|
|
|
|
|
|
|
def towards_target(self):
|
|
|
|
return self.towards(self.direction, self.target())
|
|
|
|
|
2023-08-17 15:29:43 -04:00
|
|
|
def update_leds(self):
|
|
|
|
leds.set_all_rgb(0, 0, 0)
|
|
|
|
for i, box in enumerate(Quox.BOX_COORDS):
|
|
|
|
if box in self.boxes:
|
|
|
|
center = i * 4
|
|
|
|
left = (center - 1) % 40
|
|
|
|
right = (center + 1) % 40
|
|
|
|
for led in [left, right, center]:
|
|
|
|
leds.set_hsv(led, ((i + 4) * 36) % 360, 1, 1)
|
|
|
|
leds.update()
|
|
|
|
|
2023-08-16 14:52:56 -04:00
|
|
|
if __name__ == '__main__':
|
|
|
|
run_view(Quox(ApplicationContext()))
|