refactor(game): delete old game

This commit is contained in:
Kristofers Solo 2024-01-03 17:02:16 +02:00
parent fdcda990d0
commit 8d4ef1be78
20 changed files with 0 additions and 1040 deletions

View File

@ -1,4 +0,0 @@
from .config import Config
from .screens import Menu
__all__ = ["Config", "Menu"]

View File

@ -1,12 +0,0 @@
from .utils import Board, ColorScheme, Font, Header, Position, Screen, Size, Tile
class Config:
FONT = Font()
COLORSCHEME = ColorScheme.ORIGINAL.value
TILE = Tile()
BOARD = Board()
HEADER = Header()
SCREEN = Screen()

View File

@ -1,7 +0,0 @@
from .board import Board
from .button import Button
from .label import Label
from .score_label import ScoreLabel
from .tile import Tile
__all__ = ["Board", "Button", "Label", "Tile", "ScoreLabel"]

View File

@ -1,5 +0,0 @@
from .clickable_ui_element import ClickableUIElement
from .movable_ui_element import MovableUIElement
from .ui_element import UIElement
__all__ = ["ClickableUIElement", "MovableUIElement", "UIElement"]

View File

@ -1,34 +0,0 @@
from abc import abstractmethod
from typing import Callable, Optional
import pygame
from py2048.utils import Position
from .ui_element import UIElement
class ClickableUIElement(UIElement):
def __init__(
self,
hover_color: str,
action: Optional[Callable[[], None]] = None,
*args,
**kwargs,
) -> None:
super().__init__(*args, **kwargs)
self.action = action
self.hover_color = hover_color
self.is_hovered = False
@abstractmethod
def on_click(self, mouse_pos: Position) -> None:
"""Handle the click event."""
@abstractmethod
def on_hover(self, mouse_pos: Position) -> None:
"""Handle the hover event."""
@abstractmethod
def _draw_hover_background(self, surface: pygame.Surface) -> None:
"""Draw the hover rectangle."""

View File

@ -1,22 +0,0 @@
from abc import abstractmethod
from typing import Any
import pygame
from py2048.utils import Direction, Position
from .ui_element import UIElement
class MovableUIElement(UIElement):
def __init__(self, *args, **kwargs) -> None:
UIElement.__init__(self, *args, **kwargs)
@abstractmethod
def move(self, direction: Direction) -> Any:
"""Move the element in the given direction."""
@property
@abstractmethod
def pos(self) -> Position:
"""Return the position of the element."""

View File

@ -1,55 +0,0 @@
from abc import ABC, ABCMeta, abstractmethod
from typing import Optional
import pygame
from loguru import logger
from py2048 import Config
from py2048.utils import Position, Size
class UIElement(ABC, metaclass=ABCMeta):
def __init__(
self,
/,
*,
position: Position,
bg_color: str,
font_color: str,
font_size: int = Config.FONT.size,
font_family: str = Config.FONT.family,
size: Optional[Size] = Size(50, 50),
text: str = "",
border_radius: int = 0,
border_width: int = 0,
):
super().__init__()
self.text = text
self.size = size
self.bg_color = bg_color
self.font_color = font_color
self.border_radius = border_radius
self.border_width = border_width
self.position = position
self.x, self.y = self.position
self.font = pygame.font.SysFont(font_family, font_size)
@abstractmethod
def draw(self, surface: pygame.Surface) -> None:
"""Draw the element."""
@abstractmethod
def update(self) -> None:
"""Update the element."""
@abstractmethod
def _draw_background(self, surface: pygame.Surface) -> None:
"""Draw a background for the given surface."""
@abstractmethod
def _draw_text(self) -> None:
"""Draw the text of the element."""
@abstractmethod
def _create_surface(self) -> pygame.Surface:
"""Create a surface for the element."""

View File

@ -1,151 +0,0 @@
import random
from typing import Optional
import pygame
from loguru import logger
from py2048 import Config
from py2048.utils import Direction, Position
from .tile import Tile
class Board(pygame.sprite.Group):
def __init__(self):
super().__init__()
self.rect = pygame.Rect(0, 0, *Config.BOARD.size)
self.score: int = 0
self.rect.x, self.rect.y = Config.BOARD.pos
self._initiate_game()
def _initiate_game(self) -> None:
"""Initiate the game."""
self.generate_initial_tiles()
def draw(self, surface: pygame.Surface) -> None:
"""Draw the board."""
self._draw_background(surface)
super().draw(surface)
def _draw_background(self, surface: pygame.Surface) -> None:
"""Draw the board background."""
pygame.draw.rect(
surface,
Config.COLORSCHEME.BOARD_BG,
self.rect,
border_radius=Config.TILE.border.radius,
) # background
pygame.draw.rect(
surface,
Config.COLORSCHEME.BOARD_BG,
self.rect,
width=Config.TILE.border.width,
border_radius=Config.TILE.border.radius,
) # border
def move(self, direction: Direction) -> None:
"""Move the tiles in the specified direction."""
tiles = self.sprites()
tile: Tile
match direction:
case Direction.UP:
tiles.sort(key=lambda tile: tile.rect.y)
case Direction.DOWN:
tiles.sort(key=lambda tile: tile.rect.y, reverse=True)
case Direction.LEFT:
tiles.sort(key=lambda tile: tile.rect.x)
case Direction.RIGHT:
tiles.sort(key=lambda tile: tile.rect.x, reverse=True)
for tile in tiles:
self.score += tile.move(direction)
if not self._is_full():
self.generate_random_tile()
def generate_initial_tiles(self) -> None:
"""Generate the initial tiles."""
self.generate_tile(Config.TILE.initial_count)
def generate_tile(self, amount: int = 1, *pos: Position) -> None:
"""Generate `amount` number of tiles or at the specified positions."""
if pos:
for coords in pos:
x, y = coords.x * Config.TILE.size, coords.y * Config.TILE.size
self.add(Tile(Position(x, y), self))
return
for _ in range(amount):
self.generate_random_tile()
def generate_random_tile(self) -> None:
"""Generate a tile with random coordinates aligned with the grid."""
while True:
# Generate random coordinates aligned with the grid
x = random.randint(0, 3) * Config.TILE.size + Config.BOARD.pos.x
y = random.randint(0, 3) * Config.TILE.size + Config.BOARD.pos.y
tile = Tile(Position(x, y), self)
colliding_tiles = pygame.sprite.spritecollide(
tile, self, False
) # check for collisions
if not colliding_tiles:
self.add(tile)
return
def _is_full(self) -> bool:
"""Check if the board is full."""
return len(self.sprites()) == Config.BOARD.len**2
def _can_move(self) -> bool:
"""Check if any movement is possible on the board."""
tile: Tile
for tile in self.sprites():
if tile.can_move():
return True
return False
def is_game_over(self) -> bool:
"""Check if the game is over."""
return self._is_full() and not self._can_move()
def reset(self) -> None:
"""Reset the board."""
self.empty()
self._initiate_game()
def max_val(self) -> int:
"""Return the maximum value of the tiles."""
tile: Tile
return int(max(tile.value for tile in self.sprites()))
def get_tile(self, position: Position) -> Optional[Tile]:
"""Return the tile at the specified position."""
tile: Tile
for tile in self.sprites():
if tile.pos == position:
return tile
return None
def get_tile_value(self, position: Position) -> int:
"""Return the value of the tile at the specified position."""
tile = self.get_tile(position)
if tile:
return tile.value
return 0
def matrix(self) -> list[int]:
"""Return a 1d matrix of values of the tiles."""
matrix: list[int] = []
for i in range(1, Config.BOARD.len + 1):
for j in range(1, Config.BOARD.len + 1):
tile = self.get_tile(Position(j, i))
if tile:
matrix.append(tile.value)
else:
matrix.append(0)
return matrix

View File

@ -1,71 +0,0 @@
import sys
from typing import Callable, Optional
import pygame
from attrs import define, field
from py2048 import Config
from py2048.utils import Direction, Position
from .abc import ClickableUIElement
class Button(ClickableUIElement, pygame.sprite.Sprite):
def __init__(self, *args, **kwargs):
pygame.sprite.Sprite.__init__(self)
super().__init__(*args, **kwargs)
self.image = self._create_surface()
self.rect = self.image.get_rect()
self.rect.topleft = self.position
self.update()
def draw(self, surface: pygame.Surface) -> None:
"""Draw the button on the given surface."""
self._draw_background(surface)
self._draw_text()
self.image.blit(self.image, (0, 0))
def update(self) -> None:
"""Update the button."""
self._draw_background(self.image)
self._draw_text()
def on_click(self, mouse_pos: Position) -> None:
"""Handle the click event."""
if self.rect.collidepoint(mouse_pos) and self.action:
self.action()
def on_hover(self, mouse_pos: Position) -> None:
pass
def _draw_background(self, surface: pygame.Surface) -> None:
"""Draw a rectangle on the given surface."""
if self.size:
pygame.draw.rect(
surface,
self.bg_color,
(0, 0, *self.size),
border_radius=Config.TILE.border.radius,
)
def _draw_hover_background(self, surface: pygame.Surface) -> None:
"""Draw the hover rectangle."""
pygame.draw.rect(
surface,
self.hover_color,
self.rect,
border_radius=self.border_radius,
)
def _draw_text(self) -> None:
"""Draw the text of the element."""
text = self.font.render(self.text, True, self.font_color)
rect = text.get_rect(center=self.image.get_rect().center)
self.image.blit(text, rect)
def _create_surface(self) -> pygame.Surface:
"""Create a surface for the element."""
surface = pygame.Surface(self.size, pygame.SRCALPHA)
self._draw_background(surface)
return surface

View File

@ -1,52 +0,0 @@
import pygame
from loguru import logger
from py2048 import Config
from py2048.utils import Position, Size
from .abc import UIElement
class Label(UIElement, pygame.sprite.Sprite):
def __init__(self, *args, **kwargs) -> None:
pygame.sprite.Sprite.__init__(self)
super().__init__(*args, **kwargs)
self.image = self._create_surface()
self.rect = self.image.get_rect()
self.rect.topleft = self.position
self.update()
def draw(self, surface: pygame.Surface) -> None:
"""Draw the element on the given surface."""
self._draw_background(surface)
self._draw_text()
self.image.blit(self.image, (0, 0))
def update(self) -> None:
"""Update the sprite."""
self._draw_background(self.image)
self._draw_text()
self.image.blit(self.image, (0, 0))
def _draw_background(self, surface: pygame.Surface) -> None:
"""Draw a background for the given surface."""
if self.size:
pygame.draw.rect(
surface,
self.bg_color,
(0, 0, *self.size),
border_radius=Config.TILE.border.radius,
)
def _draw_text(self) -> None:
"""Draw the text of the element."""
text = self.font.render(self.text, True, self.font_color)
rect = text.get_rect(center=self.image.get_rect().center)
self.image.blit(text, rect)
def _create_surface(self) -> pygame.Surface:
"""Create a surface for the element."""
surface = pygame.Surface(self.size, pygame.SRCALPHA)
self._draw_background(surface)
return surface

View File

@ -1,65 +0,0 @@
from typing import Optional
import pygame
from loguru import logger
from py2048 import Config
from py2048.utils import Position, Size
from .abc import UIElement
class ScoreLabel(UIElement, pygame.sprite.Sprite):
def __init__(self, value: int, *args, **kwargs) -> None:
pygame.sprite.Sprite.__init__(self)
super().__init__(*args, **kwargs)
self.value = value
self.image = self._create_surface()
self.rect = self.image.get_rect()
self.rect.topleft = self.position
self.update()
def draw(self, surface: pygame.Surface) -> None:
"""Draw the element on the given surface."""
self._draw_background(surface)
self._draw_text()
def update(self) -> None:
"""Update the sprite."""
self._draw_background(self.image)
self._draw_text()
def update_score(self, score: int) -> None:
"""Update the score value."""
self.value = score
self.update()
def _draw_background(self, surface: pygame.Surface) -> None:
"""Draw a background for the given surface."""
if self.size:
pygame.draw.rect(
surface,
self.bg_color,
(0, 0, *self.size),
border_radius=self.border_radius,
)
def _draw_text(self) -> None:
"""Draw the text of the element."""
centerx, centery = self.image.get_rect().center
# Render text
label_text = self.font.render(self.text, True, self.font_color)
label_rect = label_text.get_rect(center=(centerx, centery - 10))
self.image.blit(label_text, label_rect)
# Render value
score_text = self.font.render(f"{self.value}", True, self.font_color)
score_rect = score_text.get_rect(center=(centerx, centery + 10))
self.image.blit(score_text, score_rect)
def _create_surface(self) -> pygame.Surface:
"""Create a surface for the element."""
surface = pygame.Surface(self.size, pygame.SRCALPHA)
self._draw_background(surface)
return surface

View File

@ -1,201 +0,0 @@
import random
from typing import Union
import pygame
from loguru import logger
from py2048 import Config
from py2048.utils import ColorScheme, Direction, Position, Size
from .abc import MovableUIElement, UIElement
def _grid_pos(position: Position) -> Position:
"""Return the position in the grid."""
x = (position.x - Config.BOARD.pos.x) // Config.TILE.size + 1
y = (position.y - Config.BOARD.pos.y) // Config.TILE.size + 1
return Position(x, y)
class Tile(MovableUIElement, pygame.sprite.Sprite):
def __init__(
self,
position: Position,
group: pygame.sprite.Group,
):
pygame.sprite.Sprite.__init__(self)
self.value = 2 if random.random() <= Config.TILE.value_probability else 4
super().__init__(
position=position,
text=f"{self.value}",
bg_color=Config.COLORSCHEME.TILE_0,
font_color=Config.COLORSCHEME.DARK_TEXT,
size=Size(Config.TILE.size, Config.TILE.size),
border_radius=Config.TILE.border.radius,
border_width=Config.TILE.border.width,
)
self.group = group
self.image = self._create_surface()
self.rect = self.image.get_rect()
self.rect.topleft = self.position
self.update()
def draw(self, surface: pygame.Surface) -> None:
"""Draw the value of the tile."""
self._draw_background(surface)
self._draw_text()
self.image.blit(self.image, (0, 0))
def update(self) -> None:
"""Update the sprite."""
self._draw_background(self.image)
self.text = f"{self.value}"
self._draw_text()
self.image.blit(self.image, (0, 0))
def _draw_background(self, surface: pygame.Surface) -> None:
"""Draw a rounded rectangle on the given surface."""
if self.size:
pygame.draw.rect(
surface,
self._get_color(),
(0, 0, *self.size),
border_radius=Config.TILE.border.radius,
)
self._draw_border(surface)
def _draw_border(self, surface: pygame.Surface) -> None:
"""Draw a rounded border on the given surface."""
if self.size:
pygame.draw.rect(
surface,
(0, 0, 0, 0),
(0, 0, *self.size),
border_radius=Config.TILE.border.radius,
width=Config.TILE.border.width,
)
def _draw_text(self) -> None:
"""Draw the text of the sprite."""
text = self.font.render(self.text, True, self.font_color)
rect = (text.get_rect(center=self.image.get_rect().center),)
self.image.blit(text, rect)
def _create_surface(self) -> pygame.Surface:
"""Create a surface for the sprite."""
surface = pygame.Surface(self.size, pygame.SRCALPHA)
self._draw_background(surface)
return surface
def move(self, direction: Direction) -> int:
"""
Move the tile by `dx` and `dy`.
If the tile collides with another tile, it will merge with it if possible.
"""
score = 0
while True:
new_x, new_y = self._calc_new_pos(direction)
if self._is_out_if_bounds(new_x, new_y):
return score
if self._has_collision(new_x, new_y):
collided_tile = self._get_collided_tile(new_x, new_y)
if collided_tile and self._can_merge(collided_tile):
score += self._merge(collided_tile)
else:
return score
self.group.remove(self)
self.rect.topleft = new_x, new_y
self.group.add(self)
def _calc_new_pos(self, direction: Direction) -> tuple[int, int]:
"""Calculate the new position of the tile."""
dx, dy = direction * Config.TILE.size
return self.rect.x + dx, self.rect.y + dy
def _is_out_if_bounds(self, x: int, y: int) -> bool:
"""Return whether the tile is out of bounds."""
board_left = Config.BOARD.pos.x
board_right = Config.BOARD.pos.x + Config.BOARD.size.width - Config.TILE.size
board_top = Config.BOARD.pos.y
board_bottom = Config.BOARD.pos.y + Config.BOARD.size.height - Config.TILE.size
return not (board_left <= x <= board_right and board_top <= y <= board_bottom)
def _has_collision(self, x: int, y: int) -> bool:
"""Checks whether the tile has a collision with any other tile."""
return any(tile.rect.collidepoint(x, y) for tile in self.group if tile != self)
def _get_collided_tile(self, x: int, y: int) -> Union["Tile", None]:
"""Get the tile that collides with the given tile."""
return next(
(
tile
for tile in self.group
if tile != self and tile.rect.collidepoint(x, y)
),
None,
)
def _can_merge(self, other: "Tile") -> bool:
"""Check if the tile can merge with another tile."""
return self.value == other.value
def _merge(self, other: "Tile") -> int:
"""Merge the tile with another tile."""
self.group.remove(other)
self.group.remove(self)
self.value += other.value
self.update()
self.group.add(self)
return self.value
def can_move(self) -> bool:
"""Check if the tile can move"""
for direction in Direction:
new_x, new_y = self._calc_new_pos(direction)
if not self._is_out_if_bounds(new_x, new_y) and self._has_collision(
new_x, new_y
):
collided_tile = self._get_collided_tile(new_x, new_y)
if collided_tile and self._can_merge(collided_tile):
return True
return False
def _get_color(self) -> str:
"""Change the color of the tile based on its value."""
color_map = {
2: Config.COLORSCHEME.TILE_2,
4: Config.COLORSCHEME.TILE_4,
8: Config.COLORSCHEME.TILE_8,
16: Config.COLORSCHEME.TILE_16,
32: Config.COLORSCHEME.TILE_32,
64: Config.COLORSCHEME.TILE_64,
128: Config.COLORSCHEME.TILE_128,
256: Config.COLORSCHEME.TILE_256,
512: Config.COLORSCHEME.TILE_512,
1024: Config.COLORSCHEME.TILE_1024,
2048: Config.COLORSCHEME.TILE_2048,
}
return color_map.get(self.value, Config.COLORSCHEME.TILE_ELSE)
def __repr__(self) -> str:
"""Return a string representation of the tile."""
return f"Tile({id(self)}): {self.pos} num={self.value}"
def __str__(self) -> str:
"""Return a string representation of the tile."""
return self.__repr__()
def __hash__(self) -> int:
"""Return a hash of the tile."""
return hash((self.rect.x, self.rect.y))
@property
def pos(self) -> Position:
"""Return the position of the tile."""
return _grid_pos(Position(*self.rect.topleft))

View File

@ -1,4 +0,0 @@
from .game import Game
from .menu import Menu
__all__ = ["Menu", "Game"]

View File

@ -1,114 +0,0 @@
import neat
import pygame
from loguru import logger
from py2048 import Config
from py2048.objects import Board, Button, ScoreLabel
from py2048.utils import Direction, Position, Size
class Game:
def __init__(self) -> None:
self.rect = pygame.Rect(0, 0, *Config.HEADER.size)
self.labels = self._create_labels()
self.buttons = self._create_buttons()
self.board = Board()
def update_score(self, new_score: int) -> None:
"""Updates the score to `new_score`."""
self.score.update_score(new_score)
def draw(self, surface: pygame.Surface) -> None:
surface.fill(Config.COLORSCHEME.BG)
self.board.draw(surface)
self.labels.draw(surface)
self.buttons.draw(surface)
pygame.display.flip()
def handle_events(self, event: pygame.Event) -> None:
if event.type == pygame.MOUSEBUTTONDOWN:
for button in self.buttons:
button.on_click(Position(*event.pos))
elif event.type == pygame.MOUSEMOTION:
for button in self.buttons:
button.on_hover(Position(*event.pos))
elif event.type == pygame.KEYDOWN:
if event.key in (pygame.K_LEFT, pygame.K_a, pygame.K_h):
self.move_left()
elif event.key in (pygame.K_RIGHT, pygame.K_d, pygame.K_l):
self.move_right()
elif event.key in (pygame.K_UP, pygame.K_w, pygame.K_k):
self.move_up()
elif event.key in (pygame.K_DOWN, pygame.K_s, pygame.K_j):
self.move_down()
def move(self, direction: Direction) -> None:
"""Moved the board in the given direction and updates the score."""
self.board.move(direction)
self.update_score(self.board.score)
# if self.board.is_game_over():
# logger.info(f"Game over! Score was {self.board.score}.")
# self.restart()
def move_up(self) -> None:
self.move(Direction.UP)
def move_down(self) -> None:
self.move(Direction.DOWN)
def move_left(self) -> None:
self.move(Direction.LEFT)
def move_right(self) -> None:
self.move(Direction.RIGHT)
def restart(self) -> None:
self.board.reset()
self.board.score = 0
self.update_score(0)
def _create_labels(self) -> pygame.sprite.Group:
size = Size(60, 40)
self.score = ScoreLabel(
value=0,
text="Score",
size=size,
position=Position(
Config.SCREEN.size.width - Config.TILE.size // 2 - size.width * 2 - 10,
10,
),
bg_color=Config.COLORSCHEME.BOARD_BG,
font_color=Config.COLORSCHEME.LIGHT_TEXT,
font_size=16,
border_radius=2,
)
highscore = ScoreLabel(
value=2048,
text="Best",
size=size,
position=Position(
Config.SCREEN.size.width - Config.TILE.size // 2 - size.width, 10
),
bg_color=Config.COLORSCHEME.BOARD_BG,
font_color=Config.COLORSCHEME.LIGHT_TEXT,
font_size=16,
border_radius=2,
)
return pygame.sprite.Group(self.score, highscore)
def _create_buttons(self) -> pygame.sprite.Group:
reset = Button(
position=(10, 10),
bg_color=Config.COLORSCHEME.BOARD_BG,
font_color=Config.COLORSCHEME.LIGHT_TEXT,
hover_color=Config.COLORSCHEME.TILE_0,
size=(100, 30),
text="New Game",
border_radius=Config.TILE.border.radius,
action=self.restart,
font_size=16,
border_width=2,
)
return pygame.sprite.Group(reset)

View File

@ -1,129 +0,0 @@
import sys
from pathlib import Path
import neat
import pygame
from ai import get_config, read_genome
from loguru import logger
from py2048 import Config
from py2048.objects import Button
from py2048.utils import Position
from .game import Game
class Menu:
def __init__(self):
pygame.init()
pygame.display.set_caption("2048")
self._surface: pygame.Surface = pygame.display.set_mode(Config.SCREEN.size)
logger.info("Initializing game")
self._buttons_data = {
"Play": self.play,
"AI": self.ai,
"Settings": self.settings,
"Exit": self.exit,
}
self._game_active = False
self._ai_active = False
self._setting_active = False
self._buttons = self._create_buttons()
def _create_buttons(self) -> pygame.sprite.Group:
"""Create the buttons."""
width, height = 120, 50
buttons = pygame.sprite.Group()
for index, (text, action) in enumerate(self._buttons_data.items(), start=1):
buttons.add(
Button(
position=(
Config.SCREEN.size.width / 2 - width / 2,
Config.SCREEN.size.height / len(self._buttons_data) * index
- height,
),
bg_color=Config.COLORSCHEME.BOARD_BG,
font_color=Config.COLORSCHEME.LIGHT_TEXT,
hover_color=Config.COLORSCHEME.TILE_0,
size=(width, height),
text=text,
border_radius=Config.TILE.border.radius,
action=action,
)
)
return buttons
def draw(self) -> None:
self._surface.fill(Config.COLORSCHEME.BG)
self._buttons.draw(self._surface)
pygame.display.flip()
def run(self) -> None:
"""Run the game loop."""
while True:
self._hande_events()
if self._game_active:
self.game.draw(self._surface)
elif self._ai_active:
self._ai_move()
self.game.draw(self._surface)
elif self._setting_active:
pass
else:
self.draw()
def _hande_events(self) -> None:
"""Handle pygame events."""
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
for button in self._buttons:
button.on_click(Position(*event.pos))
elif event.type == pygame.MOUSEMOTION:
for button in self._buttons:
button.on_hover(Position(*event.pos))
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
self.exit()
if self._game_active or self._ai_active:
self.game.handle_events(event)
def play(self) -> None:
logger.debug("Launching game")
self._game_active = True
self.game = Game()
def ai(self) -> None:
logger.debug("AI")
self._ai_active = True
self.game = Game()
self.network = neat.nn.FeedForwardNetwork.create(read_genome(), get_config())
def _ai_move(self) -> None:
decisions = {
0: self.game.move_up,
1: self.game.move_down,
2: self.game.move_left,
3: self.game.move_right,
}
output = self.network.activate((*self.game.board.matrix(),))
decision = output.index(max(output))
decisions[decision]()
def settings(self) -> None:
logger.debug("Settings")
def exit(self) -> None:
"""Exit the game."""
logger.debug("Exiting")
pygame.quit()
sys.exit()

View File

@ -1,17 +0,0 @@
from path import BASE_PATH
from .collections import Board, Font, Header, Position, Screen, Size, Tile
from .color import ColorScheme
from .enums import Direction
__all__ = [
"Board",
"ColorScheme",
"Direction",
"Font",
"Position",
"Size",
"Tile",
"Header",
"Screen",
]

View File

@ -1,52 +0,0 @@
from typing import NamedTuple
from attr import Factory, define, field
class Position(NamedTuple):
x: int | float
y: int | float
class Size(NamedTuple):
width: int
height: int
@define
class Font:
family: str = "Roboto"
size: int = 32
@define
class Border:
width: int
radius: int
@define
class Tile:
size: int = 75
border: Border = Border(size // 20, size // 10)
initial_count: int = 2
value_probability: float = 0.9
@define
class Board:
len: int = 4
size: Size = Size(len * Tile().size, len * Tile().size)
pos: Position = Position(Tile().size // 2, Tile().size + Tile().size // 2)
@define
class Header:
size: Size = Size(Board().size.width + Tile().size, Tile().size)
@define
class Screen:
size: Size = Size(
Header().size.width, Board().size.height + Tile().size + Header().size.height
)

View File

@ -1,27 +0,0 @@
from enum import Enum
class Original:
TILE_0 = "#cdc1b4"
TILE_2 = "#eee4da"
TILE_4 = "#eee1c9"
TILE_8 = "#f3b27a"
TILE_16 = "#f69664"
TILE_32 = "#f77c5f"
TILE_64 = "#f75f3b"
TILE_128 = "#edcf72"
TILE_256 = "#edcc61"
TILE_512 = "#edc850"
TILE_1024 = "#edc53f"
TILE_2048 = "#edc22e"
TILE_ELSE = "#ff0000"
LIGHT_TEXT = "#f9f6f2"
DARK_TEXT = "#776e65"
OTHER = "#000000"
BG = "#faf8ef"
BOARD_BG = "#bbada0"
class ColorScheme(Enum):
ORIGINAL = Original
DARK = ... # TODO: Implement dark color scheme

View File

@ -1,18 +0,0 @@
from enum import Enum
from .collections import Position
class Direction(Enum):
UP = Position(0, -1)
DOWN = Position(0, 1)
LEFT = Position(-1, 0)
RIGHT = Position(1, 0)
def __mul__(self, num: int) -> Position:
"""Multiply the direction by a constant."""
return Position(self.value.x * num, self.value.y * num)
def __imul__(self, num: int) -> tuple[int, int]:
"""Multiply the direction by a constant."""
return Position(self.value.x * num, self.value.y * num)