Skip to content

Commit

Permalink
refactor: remove magic numbers for curses color pairs
Browse files Browse the repository at this point in the history
  • Loading branch information
mecaneer23 committed May 11, 2024
1 parent 4c67768 commit fac0980
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 27 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,3 @@ python3 snake.py --color-snake blue --color-food red
- [ ] Make horizontal and vertical speeds equal (see commit history for details)
- [ ] Fix pausing (save state and unpause at same state)
- [ ] Add support for best score saving/loading (tentative)
- [ ] Remove magic numbers for curses color pairs
63 changes: 37 additions & 26 deletions snake.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from enum import Enum
from os.path import expanduser
from random import randint
from typing import Iterator
from typing import Iterable, Iterator

from working_initscr import wrapper

Expand Down Expand Up @@ -93,6 +93,7 @@ def __init__(
head_char: str,
max_speed: int,
cheat: int,
color: int,
) -> None:
self._body_char = body_char
self._head_char = head_char
Expand All @@ -101,16 +102,22 @@ def __init__(
self._body: deque[Location] = deque((Location(4, 5),))
for _ in range(cheat + 1):
self._body.append(Location(3, 5))
self._color = color

def display(self, stdscr: curses.window) -> None:
stdscr.addch(
self._head.get_y(),
self._head.get_x(),
self._head_char,
curses.color_pair(2),
self._color,
)
for x, y in self:
stdscr.addch(y, x, self._body_char, curses.color_pair(2))
stdscr.addch(
y,
x,
self._body_char,
self._color,
)

def get_head(self) -> Location:
"""Returns the head of the snake"""
Expand Down Expand Up @@ -149,11 +156,18 @@ class Direction(Enum):
class Food(DisplayableInterface):
"""Represent the food the snake is currently trying to eat"""

def __init__(self, char: str, rows: int, cols: int) -> None:
def __init__(
self,
char: str,
rows: int,
cols: int,
color: int,
) -> None:
self._char = char
self._rows = rows
self._cols = cols
self._location = Location(rows // 2, cols // 2)
self._color = color

def get_location(self) -> Location:
"""Return the food's current location"""
Expand All @@ -176,7 +190,7 @@ def display(self, stdscr: curses.window) -> None:
self._location.get_y(),
self._location.get_x(),
self._char,
curses.color_pair(3),
self._color,
)


Expand All @@ -190,7 +204,7 @@ def _init_board(self) -> None:
for y in range(self._board.get_rows()):
for x in range(self._board.get_cols()):
self._stdscr.addch(
y, x, self._board.get_background_char(), curses.color_pair(1)
y, x, self._board.get_background_char(), self._bg_color
)

self._stdscr.addstr(
Expand All @@ -199,7 +213,7 @@ def _init_board(self) -> None:
self._LONG_TEXT
if self._board.is_large_enough(len(self._LONG_TEXT))
else self._SHORT_TEXT,
curses.color_pair(1),
self._bg_color,
)

def __init__(
Expand All @@ -208,6 +222,8 @@ def __init__(
snake: Snake,
board: Board,
food_char: str,
bg_color: int,
food_color: int,
) -> None:
self._stdscr = stdscr
self._snake = snake
Expand All @@ -216,11 +232,13 @@ def __init__(
food_char,
self._board.get_rows(),
self._board.get_cols(),
food_color,
)
self._paused = False
self._direction = Direction.RIGHT
self._running = True
self._score = len(snake)
self._bg_color = bg_color
# best_score = update_best_score(score)
self._init_board()
for obj in (self._food, self._snake):
Expand Down Expand Up @@ -286,7 +304,7 @@ def display_score(self) -> None:
)
- 1,
str(self._score),
curses.color_pair(1),
self._bg_color,
)

def run(self) -> str:
Expand All @@ -313,7 +331,7 @@ def run(self) -> str:
new_bg.get_y(),
new_bg.get_x(),
self._board.get_background_char(),
curses.color_pair(1),
self._bg_color,
)
self._snake.add_head(new_head)
for obj in (self._food, self._snake):
Expand All @@ -326,18 +344,8 @@ def get_score(self) -> int:
return self._score


def get_args() -> Namespace:
def get_args(color_choices: Iterable[str]) -> Namespace:
"""Parse the command line arguments using argparse"""
color_choices = [
"black",
"white",
"red",
"green",
"yellow",
"blue",
"magenta",
"cyan",
]
parser = ArgumentParser(
description="snake game",
add_help=False,
Expand Down Expand Up @@ -461,12 +469,6 @@ def get_args() -> Namespace:

def main(stdscr: curses.window) -> str:
"""Entry point for snake game"""
args = get_args()
curses.curs_set(0)
curses.use_default_colors()
stdscr.nodelay(True)
stdscr.timeout(1000 // args.speed)

colors = {
"black": curses.COLOR_BLACK,
"white": curses.COLOR_WHITE,
Expand All @@ -478,6 +480,12 @@ def main(stdscr: curses.window) -> str:
"cyan": curses.COLOR_CYAN,
}

args = get_args(colors.keys())
curses.curs_set(0)
curses.use_default_colors()
stdscr.nodelay(True)
stdscr.timeout(1000 // args.speed)

curses.init_pair(1, -1 if args.black_white else colors[args.color_bg], -1)
curses.init_pair(2, -1 if args.black_white else colors[args.color_snake], -1)
curses.init_pair(3, -1 if args.black_white else colors[args.color_food], -1)
Expand All @@ -489,13 +497,16 @@ def main(stdscr: curses.window) -> str:
args.char_head,
args.speed,
args.cheat,
curses.color_pair(2),
),
Board(
args.rows or stdscr.getmaxyx()[0] - 1,
args.columns or stdscr.getmaxyx()[1] - 1,
args.char_bg,
),
args.char_food,
curses.color_pair(1),
curses.color_pair(3),
)

return f"Game over: {game.run()}\nScore: {game.get_score()}"
Expand Down

0 comments on commit fac0980

Please sign in to comment.