Created
February 28, 2019 22:47
-
-
Save rmorshea/56509989480306236dc29c5f95eafb22 to your computer and use it in GitHub Desktop.
The game Snake implemented in Python with iDOM (https://github.com/rmorshea/idom)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import idom | |
import enum | |
import time | |
import random | |
import asyncio | |
class WASD(enum.Enum): | |
w = (-1, 0) | |
a = (0, -1) | |
s = (1, 0) | |
d = (0, 1) | |
@idom.element | |
async def Game( | |
self, | |
grid_size, | |
block_size, | |
snake=idom.Context(list), | |
direction=idom.Context(WASD.d), | |
food=idom.Context(), | |
won=idom.Context(False), | |
lost=idom.Context(False), | |
): | |
snake.current = [] | |
grid = Grid(grid_size, block_size) | |
grid.attributes["tabIndex"] = -1 | |
events = grid.eventHandlers = idom.Events() | |
@events.on("KeyDown") | |
def direction_change(key): | |
if hasattr(WASD, key): | |
old = direction.current.value | |
new = WASD[key].value | |
vector_sum = tuple(map(sum, zip(old, new))) | |
if vector_sum != (0, 0): | |
direction.current = WASD[key] | |
snake.current.extend([ | |
(grid_size // 2 - 1, grid_size // 2 - 3), | |
(grid_size // 2 - 1, grid_size // 2 - 2), | |
(grid_size // 2 - 1, grid_size // 2 - 1), | |
]) | |
grid_points = set((x, y) for x in range(grid_size) for y in range(grid_size)) | |
def set_new_food(): | |
points_not_in_snake = grid_points.difference(snake.current) | |
new_food = food.current = random.choice(list(points_not_in_snake)) | |
grid["children"][new_food[0]]["children"][new_food[1]].update(color="red") | |
async def loop(): | |
if self.state.lost.current: | |
self.reset(grid_size, block_size) | |
await asyncio.sleep(2) | |
return | |
elif self.state.won.current: | |
return | |
else: | |
await draw(self, grid, grid_size, set_new_food) | |
self.callback(loop) | |
self.callback(loop) | |
set_new_food() | |
return grid | |
async def draw(game, grid, grid_size, set_new_food): | |
start = time.time() | |
snake = game.state.snake.current | |
old_head = snake[-1] | |
new_head = ( | |
# grid wraps due to mod op here | |
(old_head[0] + game.state.direction.current.value[0]) % grid_size, | |
(old_head[1] + game.state.direction.current.value[1]) % grid_size, | |
) | |
new_head_element = grid["children"][new_head[0]]["children"][new_head[1]] | |
new_head_element.update("black") | |
if new_head == game.state.food.current: | |
set_new_food() | |
else: | |
old_tail = snake.pop(0) | |
old_tail_element = grid["children"][old_tail[0]]["children"][old_tail[1]] | |
old_tail_element.update("white") | |
if new_head in snake: | |
game.state.lost.current = True | |
elif len(snake) == grid_size * grid_size: | |
game.state.won.current = True | |
snake.append(new_head) | |
stop = time.time() | |
await asyncio.sleep(0.3 - (start - stop)) | |
def Grid(grid_size, block_size): | |
return idom.node( | |
"div", | |
[ | |
{ | |
"tagName": "div", | |
"attributes": {"style": {"height": block_size}}, | |
"children": [Block("white", block_size) for i in range(grid_size)] | |
} | |
for i in range(grid_size) | |
], | |
style={ | |
"height": "%spx" % (block_size * grid_size), | |
"width": "%spx" % (block_size * grid_size), | |
} | |
) | |
@idom.element | |
def Block(self, color, block_size): | |
return idom.node( | |
"div", | |
style={ | |
"height": "%spx" % block_size, | |
"width": "%spx" % block_size, | |
"backgroundColor": color, | |
"display": "inline-block" | |
} | |
) | |
idom.SimpleWebServer(Game, 15, 30).daemon("localhost", 8765) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment