Toggle Navigation
Hatchery
Eggs
pixelSnake
pixelSnake.py
Users
Badges
Login
Register
MCH2022 badge?
go to mch2022.badge.team
pixelSnake.py
raw
Content
import badge import ugfx import utime import urandom import math import wifi import usocket from umqtt.simple import MQTTClient import sys class PixelSnake: UP = 0 RIGHT = 1 DOWN = 2 LEFT = 3 SELECT = 4 # TODO: indexes in list/tuple should be replaced with named tuple. X = 0 Y = 1 COLOR = 2 name_to_color = { "blue": 0x3030ff, "green": 0x30ff30, "red": 0xff3030, "yellow": 0xffbc1c } # TODO: grow snake using food FOOD_COLOR = 0xff0102 colors = list(name_to_color.keys()) color_to_name = {color: name for name, color in name_to_color.items()} def __init__(self): self.name = badge.nvs_get_str("owner","name", "lazyDude") self.color = self.name_to_color[self.colors[0]] self.tail_length = 3 self.speed = 1 self._position = [0,0] # init random self.direction = 0 self.grid = [[80+240+80, 0],[80+240+80+80, 80]] self.tail = [] # stores displaced pixels and restores them afterwards TODO: replace with named tuples self.aborted = False self.time_started = None self.dead = False self.readable_pixels = False # was too buggy apparently self.action_scheduled = None wifi.init() badge.init() ugfx.init() ugfx.input_init() ugfx.clear(ugfx.WHITE) ugfx.string(10, 10, "Waiting for wifi...", "Roboto_Regular12", 0) ugfx.flush() # Wait for WiFi connection while not wifi.sta_if.isconnected(): utime.sleep(0.1) pass self.address = usocket.getaddrinfo('barflood.sha2017.org', 2342)[0][-1] ugfx.clear(ugfx.BLACK) ugfx.flush() ugfx.clear(ugfx.WHITE) ugfx.flush() ugfx.input_attach(ugfx.BTN_START, self.action_home) ugfx.input_attach(ugfx.JOY_UP, self.action_up) ugfx.input_attach(ugfx.JOY_DOWN, self.action_down) ugfx.input_attach(ugfx.JOY_LEFT, self.action_left) ugfx.input_attach(ugfx.JOY_RIGHT, self.action_right) ugfx.input_attach(ugfx.BTN_A, self.action_select) self.socket = None def action_home(self, pressed): if pressed: self.aborted = True def action_up(self, pressed): if pressed: self.action_scheduled = self.UP def action_down(self, pressed): if pressed: self.action_scheduled = self.DOWN def action_left(self, pressed): if pressed: self.action_scheduled = self.LEFT def action_right(self, pressed): if pressed: self.action_scheduled = self.RIGHT def action_select(self, pressed): if pressed: self.action_scheduled = self.SELECT def pick_color(self): color_index = 0 while not self.aborted: ugfx.clear(ugfx.WHITE) ugfx.string(0, 0, "{} choose a color ".format(self.name), "Roboto_Black22", ugfx.BLACK) ugfx.string(0, 30, "color: {}".format(self.colors[color_index]), "Roboto_Black22", ugfx.BLACK) ugfx.string(0, 50, "A: select color | start = home", "Roboto_Black22", ugfx.BLACK) ugfx.string(0, 90, "up/down = rotate color", "Roboto_Black22", ugfx.BLACK) ugfx.flush() utime.sleep(0.02) if self.action_scheduled == self.UP: color_index += 1 self.action_scheduled = None if color_index >= len(self.colors): color_index = 0 if self.action_scheduled == self.DOWN: color_index -= 1 if color_index < 0: color_index = len(self.colors)-1 self.action_scheduled = None if self.action_scheduled == self.SELECT: return self.colors[color_index] def run(self): self.color = self.name_to_color.get(self.pick_color(), 0xffffff) ugfx.clear(ugfx.WHITE) ugfx.string(0, 0, "Physically be in the bar!", " Roboto_Regular12", ugfx.BLACK) ugfx.string(0, 30, "Get ready and press A to start Snake Combat!", " Roboto_Regular12", ugfx.BLACK) ugfx.string(0, 50, "Or slither away home by pressing start", " Roboto_Regular12", ugfx.BLACK) ugfx.string(0, 90, "Have Fun!", " Roboto_Regular12", ugfx.BLACK) ugfx.flush() while not self.aborted and self.action_scheduled != self.SELECT: utime.sleep(0.1) if self.aborted: return self.log_start() self.connect() ugfx.clear(ugfx.WHITE) ugfx.string(0, 0, "creating initial snake", " Roboto_Regular12", ugfx.BLACK) ugfx.flush() self.create_initial_snake() ugfx.clear(ugfx.WHITE) ugfx.string(0, 0, "Go!", "Roboto_Black22", ugfx.BLACK) ugfx.string(0, 20, "use the arrows to steer your snake", " Roboto_Regular12", ugfx.BLACK) ugfx.string(0, 50, "Or slither away home by pressing start", " Roboto_Regular12", ugfx.BLACK) ugfx.string(0, 90, "Have Fun!", " Roboto_Regular12", ugfx.BLACK) ugfx.flush() while not self.aborted: if self.action_scheduled in [self.UP, self.DOWN, self.LEFT, self.RIGHT]: self.direction = self.action_scheduled self.action_scheduled = None print("changed direction to: {}\n".format(self.direction)) print("tick\n") self.tick() print("clean tail") self.clean_up_tail() #utime.sleep(1 / self.speed) print("writeing/sleep") self.keep_writing_snake_in_pause(1/self.speed) time_elapsed = utime.time() - self.time_started self.speed = 1 + 0.3 * (time_elapsed /60) if not self.dead: self.log_score("QUIT") def tick(self): # main game progression x, y = self.tail[-1][self.X:self.Y + 1] if self.direction == self.UP: x -= 1 elif self.direction == self.DOWN: x -= 1 elif self.direction == self.RIGHT: y += 1 elif self.direction == self.LEFT: y -= 1 if x < self.grid[0][self.X] or y < self.grid[0][self.Y] or x > self.grid[1][self.X] or y > self.grid[1][self.Y]: self.die("WALL") pixel = self.get_pixel(x,y) if pixel[self.COLOR] in self.colors: self.die(self.color_to_name[pixel[self.COLOR]]) return self.writePixel(pixel, self.color) self.tail.append(pixel) def keep_writing_snake_in_pause(self, time_delta): start = utime.time() #while utime.time() - start < time_delta: for pixel in self.tail: self.writePixel(pixel, self.color, connect=False) utime.sleep(time_delta - (utime.time() - start)) def clean_up_tail(self): if len(self.tail) > self.tail_length: pixel = self.tail.pop(0) self.writePixel(pixel) def die(self, reason): for pixel in self.tail: self.writePixel(pixel) self.aborted = True self.dead = True self.log_score(reason) ugfx.clear(ugfx.WHITE) ugfx.string(0, 0, "you died by running into {}".format(reason), "Roboto_Black22", ugfx.BLACK) ugfx.flush() def create_initial_snake(self): found = False # find a free location facing away from the wall. direction = self.UP tail = None # type: Optional[List[Tuple[int, int, int]]] while not found: x = self.grid[0][self.X] + 30 #urandom.getrandbits(16) % self.grid[1][self.X] y = self.grid[0][self.Y] + 30 #urandom.getrandbits(16) % self.grid[1][self.Y] tail = [self.get_pixel(x, y)] if self.color_to_name.get(tail[0][self.COLOR]): continue direction = self.RIGHT x_dir = 1 if x - self.grid[0][self.X] < 10: direction = self.LEFT x_dir = -1 x += x_dir tail.append(self.get_pixel(x, y)) if self.color_to_name.get(tail[1][self.COLOR]): continue x += x_dir tail.append(self.get_pixel(x, y)) if self.color_to_name.get(tail[1][self.COLOR]): continue found = True self.direction = direction self.tail = tail for pixel in tail: self.writePixel(pixel, self.color) def get_pixel(self, x, y): if self.readable_pixels: self.connect() self.socket.write("PX {} {}\n".format(x, y)) pixel = (x, y, int(self.socket.readline(), 16)) return pixel else: # no output from file, no info on this for pixel in self.tail: if pixel[self.X] == x and pixel[self.Y]: return (x,y,self.color) return (x,y, 0x000000) # if color is None it restores the pixel def writePixel(self, pixel, color=None, connect=True): if connect: self.connect() print("writing pixel") self.socket.write("PX {} {} {}\n".format(pixel[self.X], pixel[self.Y], hex(pixel[2] if color == None else color))) def connect(self): if self.socket is not None: print("closing socket") self.socket.close() self.socket = usocket.socket() print("opening socket") self.socket.connect(self.address) #self.socket.send("size\n") #utime.sleep(0.1) #self.grid = [int(i) for i in self.socket.recv(80).split(" ")] def log_score(self, death_reason): #c = MQTTClient("pixelSnake", "mqtt.sha2017.org", clean_session=False) #c.publish("python {} playing as {} died by {} after {} seconds with tail length {} and speed {}".format( # self.name, self.color, death_reason, utime.time() - self.time_started, self.tail_length, self.speed #)) #c.disconnect() self.dead = True def log_start(self): #c = MQTTClient("pixelSnake", "mqtt.sha2017.org", clean_session=False) #c.publish("python {} playing as {} joined the arena".format( # self.name, self.color #)) #c.disconnect() self.time_started = utime.time() try: PixelSnake().run() except BaseException as exc: sys.print_exception(exc, file=sys.stdout) print("here")