Skip to content

Instantly share code, notes, and snippets.

@rmorshea
Last active March 27, 2019 15:01
Show Gist options
  • Save rmorshea/df3957cd47af88dcd9bde502cc0d4750 to your computer and use it in GitHub Desktop.
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)
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