Last active
March 27, 2019 15:01
-
-
Save rmorshea/df3957cd47af88dcd9bde502cc0d4750 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(state="grid_size, block_size") | |
async def Game(self, grid_size, block_size): | |
game = idom.StaticBunch( | |
snake=[], | |
grid=Grid(grid_size, block_size), | |
new_direction=idom.Var(WASD.d), | |
old_direction=idom.Var(WASD.d), | |
food=idom.Var(None), | |
won=idom.Var(False), | |
lost=idom.Var(False), | |
) | |
@game.grid.eventHandlers.on("KeyDown") | |
async def direction_change(key): | |
if hasattr(WASD, key): | |
game.new_direction.set(WASD[key]) | |
game.snake.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(game.snake) | |
new_food = random.choice(list(points_not_in_snake)) | |
get_grid_block(game.grid, new_food).update("blue") | |
game.food.set(new_food) | |
@self.animate | |
async def loop(): | |
if game.won.get() or game.lost.get(): | |
self.update() | |
await asyncio.sleep(1) | |
else: | |
await draw(game, grid_size, set_new_food) | |
self.animate(loop) | |
set_new_food() | |
return game.grid | |
async def draw(game, grid_size, set_new_food): | |
start = time.time() | |
if game.snake[-1] in game.snake[:-1]: | |
# point out where you touched | |
get_grid_block(game.grid, game.snake[-1]).update("red") | |
game.lost.set(True) | |
return | |
vector_sum = tuple(map(sum, zip( | |
game.old_direction.get().value, | |
game.new_direction.get().value | |
))) | |
if vector_sum != (0, 0): | |
game.old_direction.set(game.new_direction.get()) | |
new_head = ( | |
# grid wraps due to mod op here | |
(game.snake[-1][0] + game.old_direction.get().value[0]) % grid_size, | |
(game.snake[-1][1] + game.old_direction.get().value[1]) % grid_size, | |
) | |
game.snake.append(new_head) | |
if new_head == game.food.get(): | |
if len(game.snake) == grid_size * grid_size: | |
game.won.set(True) | |
return | |
set_new_food() | |
else: | |
get_grid_block(game.grid, game.snake.pop(0)).update("white") | |
# update head after tail - new head may be the same as the old tail | |
get_grid_block(game.grid, new_head).update("black") | |
stop = time.time() | |
await asyncio.sleep(0.5 - (start - stop)) | |
def Grid(grid_size, block_size): | |
return idom.nodes.div( | |
[ | |
idom.nodes.div( | |
[Block("white", block_size) for i in range(grid_size)], | |
style={"height": block_size}, | |
) | |
for i in range(grid_size) | |
], | |
style={ | |
"height": f"{block_size * grid_size}px", | |
"width": f"{block_size * grid_size}px", | |
}, | |
eventHandlers=idom.Events(), | |
tabIndex=-1, | |
) | |
@idom.element(state="block_size") | |
async def Block(self, color, block_size): | |
return idom.nodes.div( | |
style={ | |
"height": f"{block_size}px", | |
"width": f"{block_size}px", | |
"backgroundColor": color, | |
"display": "inline-block", | |
"border": "1px solid white", | |
} | |
) | |
def get_grid_block(grid, point): | |
x, y = point | |
return grid["children"][x]["children"][y] | |
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