snake_main.py
snake_main.py
class Position:
def __init__(self, x: int, y: int) -> None:
self.x = x
self.y = y
def __repr__(self):
return f"({self.x}, {self.y})"
class Direction:
def __init__(self, horizontal_component: int, vertical_component: int) -> None:
self.vertical = vertical_component
self.horizontal = horizontal_component
class KeyBinds:
def __init__(self, up: str, right: str, down: str, left: str) -> None:
self.up: str = up
self.right: str = right
self.down: str = down
self.left: str = left
class Colour:
def __init__(self, red: int, green: int, blue: int) -> None:
self.red: int = red
self.green: int = green
self.blue: int = blue
class Function:
def __init__(self, function, *arguments):
self.function = function
self.arguments = arguments
def execute(self):
try:
self.function(*self.arguments)
except:
raise Exception(self.arguments)
class Game:
def __init__(self) -> None:
self.is_running = True
self.width, self.height = os.get_terminal_size();
self.snakes: List[Snake] = []
self.lock = threading.Lock()
self.background_colour = Colour(0, 0, 0)
self.timed_functions: Dict[Function, int] = {}
if self.timed_functions[timed_function] == 0:
timed_function.execute()
timed_functions_to_delete.append(timed_function)
def create_game():
global game
game = Game()
create_game()
class Consumables:
def __init__(self) -> None:
self.consumables: Dict[Position, Consumable] = {}
self.consumable_types: List[type[Consumable]] = []
def generate_consumable(self):
position = game.generate_random_position(self.consumables)
random.choice(self.consumable_types)(position)
consumables = Consumables()
class Consumable:
def generate(self) -> None:
pass
class Apple(Consumable):
def generate(self) -> None:
pass
new_pos = consumable.position
for _ in range(2):
new_pos = calculate_new_position(new_pos, dir, 1)
if new_pos == snake.get_position():
consumable.consume(snake)
break
elif not game.is_position_in_a_snake(new_pos) and not new_pos in
consumables.consumables:
consumable.move(new_pos)
else:
break
class Magnet(Consumable):
def generate(self) -> None:
self.range = random.randint(1, game.width)
class Snake:
def __init__(self, position: Position, direction: Direction, keybinds:
KeyBinds, functions = []) -> None:
self.direction: Direction = direction
self.colour: Colour = generate_random_colour()
self.speed: int = 1
self.functions: List[Function | None] = functions
self.free_function_indexes: List[int] = []
self.functions_to_add: List[Tuple[Function, int | None]] = []
self.snake_segments: List[Position] = [position]
self.assign_keybinds(keybinds)
self.alive = True
self.counter = 0
game.register_snake(self)
def move_snake(self):
with game.lock:
if not self.alive:
self.counter -= 1
render(Position(0, 5), f"time: {self.counter}")
if self.counter == 0:
self.snake_segments = [game.generate_random_position([])]
self.alive = True
else:
return
if self.grow():
delete_pixel(self.snake_segments.pop(0))
else:
return
if self.alive and len(self.snake_segments) != 0:
for function in self.functions:
if function:
function.execute()
self.register_functions()
def grow(self):
if not game.is_position_in_a_snake(c_pos :=
calculate_new_position(self.snake_segments[-1], self.direction, 1)) and 1 <=
c_pos.x < game.width and 1 <= c_pos.y < game.height:
self.snake_segments.append(c_pos)
if self.snake_segments[-1] in consumables.consumables:
consumables.consumables[self.snake_segments[-1]].consume(self)
render_pixel(c_pos, self.colour)
return True
else:
for segment in self.snake_segments:
delete_pixel(segment)
self.snake_segments = []
render(Position(1, 0), f"Player {game.snakes.index(self) + 1} died!",
Colour(255, 0, 0))
self.alive = False
self.counter = 100
return False
def movement():
dirs = list(map(lambda x: Direction(*x), [(0, -1), (-1, 0), (0, 1), (1, 0)]))
while True:
key = get_input()
with game.lock:
for snake in game.snakes:
if snake.keybinds.is_keybind_defined(key):
new_dir = dirs[snake.keybinds.get_key_index(key)]
if not (new_dir.vertical + snake.direction.vertical == 0 and
new_dir.horizontal + snake.direction.horizontal == 0):
snake.direction = new_dir
break
def get_keybinds():
string_directions = ["up", "right", "down", "left"]
keybind_list = []
for _ in range(4):
keybind_list.append(get_key_as_a_keybind(string_directions[_],
keybind_list))
return KeyBinds(*keybind_list)
if key in current:
continue
else:
for index, snake in enumerate(game.snakes):
if snake.keybinds.is_keybind_defined(key):
print(f"Keybind is already defined for player {index + 1}")
continue
break
return key
def main():
consumables.register_consumable(Apple)
consumables.register_consumable(Magnet)
while True:
constant = 1/60
p = Position(0, 0)
frame_start = time.time()
for snake in game.snakes:
snake.move_snake()
main()