Spikes, better gameHandler, map width and height computed automatically & big peanut hard map
This commit is contained in:
@@ -2,10 +2,12 @@ from .stoneBlock import StoneBlock
|
|||||||
from .spawnPointBlock import SpawnPointBlock
|
from .spawnPointBlock import SpawnPointBlock
|
||||||
from .finishBlock import FinishBlock
|
from .finishBlock import FinishBlock
|
||||||
from .coinBlock import CoinBlock
|
from .coinBlock import CoinBlock
|
||||||
|
from .spikesBlock import SpikesBlock
|
||||||
|
|
||||||
BLOCKS = [
|
BLOCKS = [
|
||||||
StoneBlock,
|
StoneBlock,
|
||||||
SpawnPointBlock,
|
SpawnPointBlock,
|
||||||
FinishBlock,
|
FinishBlock,
|
||||||
CoinBlock
|
CoinBlock,
|
||||||
|
SpikesBlock,
|
||||||
]
|
]
|
||||||
@@ -16,8 +16,8 @@ class FinishBlock(Block):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def on_collision(self, gameState: GameState):
|
def on_collision(self, gameState: GameState):
|
||||||
gameState.set_stop_game(True)
|
|
||||||
gameState.set_game_won(True)
|
gameState.set_game_won(True)
|
||||||
|
gameState.set_stop_game(True)
|
||||||
|
|
||||||
def to_string(self):
|
def to_string(self):
|
||||||
return "🏁"
|
return "🏁"
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
from game.blocks.block import Block
|
||||||
|
from game.gameState import GameState
|
||||||
|
|
||||||
|
class SpikesBlock(Block):
|
||||||
|
@property
|
||||||
|
def character(self):
|
||||||
|
return '^'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def type(self):
|
||||||
|
return 'spikes'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def solid(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def on_collision(self, gameState: GameState):
|
||||||
|
gameState.set_game_won(False)
|
||||||
|
gameState.set_stop_game(True)
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
return "🔥"
|
||||||
+3
-2
@@ -44,10 +44,9 @@ class Game:
|
|||||||
if spawn_point_position is None:
|
if spawn_point_position is None:
|
||||||
raise ValueError("No spawn point found in the map.")
|
raise ValueError("No spawn point found in the map.")
|
||||||
self.gameState.set_player_position(spawn_point_position)
|
self.gameState.set_player_position(spawn_point_position)
|
||||||
|
self._position_update()
|
||||||
|
|
||||||
while not self.gameState.stopGame:
|
while not self.gameState.stopGame:
|
||||||
self._position_update() # Update the screen for example
|
|
||||||
|
|
||||||
if self.gameState.playerVelocity == -1 and self.waitingForInputCallback:
|
if self.gameState.playerVelocity == -1 and self.waitingForInputCallback:
|
||||||
self.gameState.set_player_velocity(self.waitingForInputCallback())
|
self.gameState.set_player_velocity(self.waitingForInputCallback())
|
||||||
self.gameState.add_move_count()
|
self.gameState.add_move_count()
|
||||||
@@ -70,6 +69,8 @@ class Game:
|
|||||||
|
|
||||||
self._update_player_velocity()
|
self._update_player_velocity()
|
||||||
|
|
||||||
|
self._position_update() # Update the screen for example
|
||||||
|
|
||||||
if self.gameStopCallback and self.gameStopCallback(self.gameState):
|
if self.gameStopCallback and self.gameStopCallback(self.gameState):
|
||||||
self.gameState.set_stop_game(True)
|
self.gameState.set_stop_game(True)
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
|
|
||||||
from game.game import Game
|
|
||||||
|
|
||||||
class GameHandler:
|
class GameHandler:
|
||||||
def __init__(self, game: Game):
|
def __init__(self):
|
||||||
self.game = game
|
pass
|
||||||
self.game.set_waiting_for_input_callback(self.on_input_request)
|
|
||||||
self.game.set_position_update_callback(self.on_position_update)
|
@abstractmethod
|
||||||
|
def run(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_position_update(self) -> None:
|
def on_position_update(self) -> None:
|
||||||
@@ -14,4 +16,6 @@ class GameHandler:
|
|||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_input_request(self) -> str:
|
def on_input_request(self) -> str:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@@ -1,14 +1,48 @@
|
|||||||
|
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from game.game import Game
|
|
||||||
from game.handlers.gameHandler import GameHandler
|
|
||||||
|
|
||||||
|
from game.handlers.gameHandler import GameHandler
|
||||||
|
from game.game import Game
|
||||||
|
from game.gameState import GameState
|
||||||
|
from game.mapReader import MapReader
|
||||||
|
from game.mapSet import MapSet
|
||||||
|
|
||||||
class UserPlayerGameHandler(GameHandler):
|
class UserPlayerGameHandler(GameHandler):
|
||||||
KEYBOARD_INPUTS = ["w", "q", "a", "z", "e", "d", "c"]
|
KEYBOARD_INPUTS = ["w", "q", "a", "z", "e", "d", "c"]
|
||||||
|
|
||||||
def __init__(self, game: Game):
|
def __init__(self):
|
||||||
super().__init__(game)
|
super().__init__()
|
||||||
|
self.mapReader = MapReader()
|
||||||
|
self.mapSet = MapSet(self.mapReader, self.mapReader.get_map_names())
|
||||||
|
self.map = self._choose_map()
|
||||||
|
self.gameState = GameState()
|
||||||
|
self.game = Game(self.map, self.gameState)
|
||||||
|
self.game.set_waiting_for_input_callback(self.on_input_request)
|
||||||
|
self.game.set_position_update_callback(self.on_position_update)
|
||||||
|
|
||||||
|
def _choose_map(self):
|
||||||
|
"""
|
||||||
|
Prompt the user to choose a map from the available maps
|
||||||
|
"""
|
||||||
|
print("\nAvailable maps:")
|
||||||
|
for i, map_name in enumerate(self.mapReader.get_map_names()):
|
||||||
|
print(f"{i + 1}. {map_name.replace("_", " ").title()}")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
choice = int(input("Choose a map by number: ")) - 1
|
||||||
|
if 0 <= choice < len(self.mapReader.get_map_names()):
|
||||||
|
return self.mapSet.get_map(choice)
|
||||||
|
else:
|
||||||
|
print("Invalid choice. Please try again.")
|
||||||
|
except ValueError:
|
||||||
|
print("Invalid input. Please enter a number.")
|
||||||
|
|
||||||
|
def run(self) -> None:
|
||||||
|
"""
|
||||||
|
Run the game loop
|
||||||
|
"""
|
||||||
|
self.game.start_game()
|
||||||
|
print("Game over : You " + ("Won!" if self.game.gameState.gameWon else "Lost!"))
|
||||||
|
|
||||||
def on_position_update(self) -> None:
|
def on_position_update(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
|||||||
+2
-2
@@ -13,11 +13,11 @@ from game.blocks.block import Block
|
|||||||
class Map:
|
class Map:
|
||||||
def __init__(self, map_data: dict):
|
def __init__(self, map_data: dict):
|
||||||
self.name = map_data.get('name', 'Unknown')
|
self.name = map_data.get('name', 'Unknown')
|
||||||
self.width = int(map_data.get('width', 0))
|
|
||||||
self.height = int(map_data.get('height', 0))
|
|
||||||
self.difficulty = float(map_data.get('difficulty', 0.0))
|
self.difficulty = float(map_data.get('difficulty', 0.0))
|
||||||
self.min_moves = map_data.get('min_moves', None)
|
self.min_moves = map_data.get('min_moves', None)
|
||||||
self.layout = map_data.get('layout', [])
|
self.layout = map_data.get('layout', [])
|
||||||
|
self.width = max(len(row) for row in self.layout) if self.layout else 0
|
||||||
|
self.height = len(self.layout) if self.layout else 0
|
||||||
|
|
||||||
def get_block_at(self, x, y) -> Block | None:
|
def get_block_at(self, x, y) -> Block | None:
|
||||||
if 0 <= x < self.width and 0 <= y < self.height:
|
if 0 <= x < self.width and 0 <= y < self.height:
|
||||||
|
|||||||
+13
-9
@@ -27,13 +27,13 @@ class MapReader:
|
|||||||
|
|
||||||
with open(map_path, 'rb') as f:
|
with open(map_path, 'rb') as f:
|
||||||
config = tomllib.load(f)
|
config = tomllib.load(f)
|
||||||
|
|
||||||
|
layout = config.get('layout', '')
|
||||||
|
|
||||||
map_data = {
|
map_data = {
|
||||||
'name': map_name,
|
'name': map_name,
|
||||||
'width': config.get('width', 0),
|
|
||||||
'height': config.get('height', 0),
|
|
||||||
'difficulty': config.get('difficulty', 0.0),
|
'difficulty': config.get('difficulty', 0.0),
|
||||||
'layout': self._parse_layout(config.get('layout', ''))
|
'layout': self._parse_layout(layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.get('min_moves') is not None:
|
if config.get('min_moves') is not None:
|
||||||
@@ -48,16 +48,20 @@ class MapReader:
|
|||||||
|
|
||||||
def _parse_layout(self, mapString):
|
def _parse_layout(self, mapString):
|
||||||
# Takes the blocks and translates their characters into the corresponding block objects.
|
# Takes the blocks and translates their characters into the corresponding block objects.
|
||||||
block_characters_mapping = self._get_block_characters_mapping()
|
# Makes sure tthe width is consistent across all rows by padding with None if necessary.
|
||||||
|
block_mapping = self._get_block_characters_mapping()
|
||||||
layout = []
|
layout = []
|
||||||
for line in mapString.strip().splitlines():
|
for line in mapString.splitlines():
|
||||||
row = []
|
row = []
|
||||||
for char in line:
|
for char in line:
|
||||||
block_class = block_characters_mapping.get(char)
|
block_class = block_mapping.get(char)
|
||||||
if block_class:
|
if block_class:
|
||||||
row.append(block_class())
|
row.append(block_class())
|
||||||
else:
|
else:
|
||||||
row.append(None)
|
row.append(None) # Unknown character, treat as empty space
|
||||||
layout.append(row)
|
layout.append(row)
|
||||||
return layout
|
max_width = max(len(row) for row in layout)
|
||||||
|
for row in layout:
|
||||||
|
while len(row) < max_width:
|
||||||
|
row.append(None) # Pad with None to ensure consistent width
|
||||||
|
return layout
|
||||||
@@ -10,6 +10,12 @@ class MapSet:
|
|||||||
self.mapReader = mapReader
|
self.mapReader = mapReader
|
||||||
self.maps = [self.mapReader.read_map(name) for name in mapNames]
|
self.maps = [self.mapReader.read_map(name) for name in mapNames]
|
||||||
|
|
||||||
|
def get_map_by_name(self, name: str):
|
||||||
|
for map in self.maps:
|
||||||
|
if map.name == name:
|
||||||
|
return map
|
||||||
|
raise ValueError(f"Map with name '{name}' not found in the MapSet.")
|
||||||
|
|
||||||
def get_map(self, index: int):
|
def get_map(self, index: int):
|
||||||
if index < 0 or index >= len(self.maps):
|
if index < 0 or index >= len(self.maps):
|
||||||
raise IndexError("Map index out of range.")
|
raise IndexError("Map index out of range.")
|
||||||
|
|||||||
@@ -11,12 +11,11 @@ from game.mapSet import MapSet
|
|||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
mapReader = MapReader()
|
# Make the user choose the game handler
|
||||||
mapSet = MapSet(mapReader, mapReader.get_map_names())
|
print("Choose a game handler:")
|
||||||
map = mapSet.get_maps_by_difficulty(0, 1)[0]
|
for i, handler_name in enumerate(GAME_HANDLERS.keys()):
|
||||||
gameState = GameState()
|
print(f"[{i + 1}] {handler_name}")
|
||||||
game = Game(map, gameState)
|
choice = int(input("Enter the number of the game handler: ")) - 1
|
||||||
gameHandler = GAME_HANDLERS["user player"](game)
|
handler_name = list(GAME_HANDLERS.keys())[choice]
|
||||||
game.start_game()
|
game_handler_class = GAME_HANDLERS[handler_name]()
|
||||||
|
game_handler_class.run()
|
||||||
# run_game()
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
difficulty = 90
|
||||||
|
min_moves = 42
|
||||||
|
layout = """
|
||||||
|
#####
|
||||||
|
###### ########
|
||||||
|
## ####
|
||||||
|
### E##
|
||||||
|
### °#####
|
||||||
|
## ° ## ######
|
||||||
|
#°####### ## # # ### ######
|
||||||
|
# # ##
|
||||||
|
## ##° ##° ^###
|
||||||
|
# ### #### ##
|
||||||
|
# #####^##### ##
|
||||||
|
# ##### ####° #
|
||||||
|
# # #
|
||||||
|
# °# #####^^##
|
||||||
|
## ° ###^########
|
||||||
|
## # ##########
|
||||||
|
#S ##^#####
|
||||||
|
#########
|
||||||
|
"""
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
width = 12
|
|
||||||
height = 6
|
|
||||||
difficulty = 10
|
difficulty = 10
|
||||||
min_moves = 6
|
min_moves = 6
|
||||||
layout = """\
|
layout = """\
|
||||||
|
|||||||
Reference in New Issue
Block a user