Compare commits

..

2 Commits

Author SHA1 Message Date
6e6df73007 module 7 finished 2026-03-05 15:21:29 +01:00
516ef290a7 module 7 ex 3 2026-03-03 16:00:55 +01:00
16 changed files with 373 additions and 23 deletions

View File

View File

@@ -16,6 +16,4 @@ class Card(ABC):
return res return res
def is_playable(self, available_mana: int) -> bool: def is_playable(self, available_mana: int) -> bool:
if available_mana > 5: return available_mana > 5
return True
return False

View File

@@ -1,5 +1,5 @@
def main(): def main() -> None:
from CreatureCard import CreatureCard from .CreatureCard import CreatureCard
game_state = {"player": "michel", "mana": 6} game_state = {"player": "michel", "mana": 6}
print("=== DataDeck Card Foundation ===\n") print("=== DataDeck Card Foundation ===\n")
@@ -7,8 +7,10 @@ def main():
creature_card = CreatureCard("Fire Dragon", 5, "Legendary", 7, 5) creature_card = CreatureCard("Fire Dragon", 5, "Legendary", 7, 5)
print(f"CreatureCard info:\n{creature_card.get_card_info()}") print(f"CreatureCard info:\n{creature_card.get_card_info()}")
print("\nPlaying Fire Dragon with 6 mana available:") print("\nPlaying Fire Dragon with 6 mana available:")
print(f"Playable: {creature_card.is_playable(game_state['mana'])}") playable = creature_card.is_playable(game_state["mana"])
print(f"Play result: {creature_card.play(game_state)}") print(f"Playable: {playable}")
if playable:
print(f"Play result: {creature_card.play(game_state)}")
print("\nFire Dragon attacks Goblin Warrior:") print("\nFire Dragon attacks Goblin Warrior:")
print(f"Attack result: {creature_card.attack_target('Goblin Warrior')}") print(f"Attack result: {creature_card.attack_target('Goblin Warrior')}")
print("\nTesting insufficient mana (3 available):") print("\nTesting insufficient mana (3 available):")

View File

@@ -4,10 +4,11 @@ from typing import Union
class SpellCard(Card): class SpellCard(Card):
def __init__( def __init__(
self, name: str, cost: int, rarity: str, effect_type: str self, name: str, cost: int, rarity: str, effect_type: str, mana: int
) -> None: ) -> None:
super().__init__(name, cost, rarity) super().__init__(name, cost, rarity)
self.effect_type = effect_type self.effect_type = effect_type
self.mana = mana
def play(self, game_state: dict) -> dict: def play(self, game_state: dict) -> dict:
try: try:

View File

@@ -1,4 +1,4 @@
def main(): def main() -> None:
from .Deck import Deck from .Deck import Deck
from .SpellCard import SpellCard from .SpellCard import SpellCard
from .ArtifactCard import ArtifactCard from .ArtifactCard import ArtifactCard
@@ -8,7 +8,7 @@ def main():
deck = Deck() deck = Deck()
print("Building deck with different card types...") print("Building deck with different card types...")
deck.add_card( deck.add_card(
SpellCard("Lightning Bolt", 5, "Common", "Deal 3 dammage to target") SpellCard("Lightning Bolt", 5, "Common", "Deal 3 dammage to target", 5)
) )
deck.add_card( deck.add_card(
ArtifactCard( ArtifactCard(

View File

@@ -1,4 +1,4 @@
def main(): def main() -> None:
from .EliteCard import EliteCard from .EliteCard import EliteCard
print("=== DataDeck Ability System ===\n") print("=== DataDeck Ability System ===\n")

View File

@@ -1,9 +1,22 @@
from .GameStrategy import GameStrategy from .GameStrategy import GameStrategy
from operator import attrgetter
class AgressiveStrategy(GameStrategy): class AgressiveStrategy(GameStrategy):
def execute_turn(self, hand: list, battlefield: list) -> dict: ... def execute_turn(self, hand: list, battlefield: list) -> dict:
return {
"cards_played": [card.name for card in hand],
"mana_used": 5,
"targets_attacked": battlefield,
"damage_dealt": 8,
}
def get_strategy_name(self) -> str: ... def get_strategy_name(self) -> str:
return "Aggressive"
def prioritize_targets(self, available_targets: list) -> list: ... def prioritize_targets(self, available_targets: list) -> list:
try:
return sorted(available_targets, key=attrgetter("health"))
except Exception as err:
print(err)
return available_targets

View File

@@ -2,6 +2,7 @@ from .CardFactory import CardFactory
from random import choice from random import choice
from ex0 import Card, CreatureCard from ex0 import Card, CreatureCard
from ex1 import SpellCard, ArtifactCard from ex1 import SpellCard, ArtifactCard
from copy import deepcopy
creature_cards = [ creature_cards = [
CreatureCard("Fire Dragon", 20, "Rare", 7, 20), CreatureCard("Fire Dragon", 20, "Rare", 7, 20),
@@ -9,10 +10,10 @@ creature_cards = [
] ]
spell_cards = [ spell_cards = [
SpellCard("Fire Ball", 5, "Rare", "Decrase health by 1 for 3 round"), SpellCard("Fire Ball", 5, "Rare", "Decrase health by 1 for 3 round", 5),
SpellCard("Ice Spike", 3, "Common", "Reduce damage by 2 for 1 round"), SpellCard("Ice Spike", 3, "Common", "Reduce damage by 2 for 1 round", 3),
SpellCard( SpellCard(
"Lightning bolt", 10, "Legendary", "Card can't play for 3 round" "Lightning bolt", 10, "Legendary", "Card can't play for 3 round", 10
), ),
] ]
@@ -20,13 +21,15 @@ artifact_cards = [
ArtifactCard( ArtifactCard(
"Mana Ring", 2, "Common", 3, "Increase mana by 1 for each round" "Mana Ring", 2, "Common", 3, "Increase mana by 1 for each round"
), ),
ArtifactCard("Witch Staff", 6, "Legendary", 5, ""), ArtifactCard(
"Witch Staff", 6, "Legendary", 5, "Decrease 5 mana of a card"
),
] ]
class FantasyCardFactory(CardFactory): class FantasyCardFactory(CardFactory):
def create_creature(self, name_or_power: str | int | None = None) -> Card: def create_creature(self, name_or_power: str | int | None = None) -> Card:
card = choice(creature_cards) card = deepcopy(choice(creature_cards))
if isinstance(name_or_power, str): if isinstance(name_or_power, str):
card.name = name_or_power card.name = name_or_power
elif isinstance(name_or_power, int): elif isinstance(name_or_power, int):
@@ -34,13 +37,40 @@ class FantasyCardFactory(CardFactory):
return card return card
def create_spell(self, name_or_power: str | int | None = None) -> Card: def create_spell(self, name_or_power: str | int | None = None) -> Card:
return super().create_spell(name_or_power) card = deepcopy(choice(spell_cards))
if isinstance(name_or_power, str):
card.name = name_or_power
elif isinstance(name_or_power, int):
card.mana = name_or_power
return card
def create_artifact(self, name_or_power: str | int | None = None) -> Card: def create_artifact(self, name_or_power: str | int | None = None) -> Card:
return super().create_artifact(name_or_power) card = deepcopy(choice(artifact_cards))
if isinstance(name_or_power, str):
card.name = name_or_power
elif isinstance(name_or_power, int):
card.durability = name_or_power
return card
def create_themed_deck(self, size: int) -> dict: def create_themed_deck(self, size: int) -> dict:
return super().create_themed_deck(size) deck: dict[str, list[Card]] = {}
for _ in range(size):
card = choice(
[
self.create_creature(),
self.create_artifact(),
self.create_spell(),
]
)
if card.name in deck:
deck[card.name] += [card]
else:
deck[card.name] = [card]
return deck
def get_supported_types(self) -> dict: def get_supported_types(self) -> dict:
return super().get_supported_types() return {
"creatures": [card.name for card in creature_cards],
"spells": [card.name for card in spell_cards],
"artifacts": [card.name for card in artifact_cards],
}

View File

@@ -0,0 +1,41 @@
from .CardFactory import CardFactory
from .GameStrategy import GameStrategy
class GameEngine:
def __init__(self) -> None:
self.turns_simulated = 0
self.total_damage = 0
self.created_cards = 0
def configure_engine(
self, factory: CardFactory, strategy: GameStrategy
) -> None:
self.factory = factory
self.strategy = strategy
def simulate_turn(self) -> dict:
try:
cards = []
deck = self.factory.create_themed_deck(3).values()
for card_list in deck:
for card in card_list:
cards += [card]
hand = [f"{card.name} ({card.cost})" for card in cards]
print(f"Hand: {hand}")
turn = self.strategy.execute_turn(cards, ["Enemy player"])
self.total_damage += turn["damage_dealt"]
self.created_cards += 3
self.turns_simulated += 1
return turn
except Exception as err:
print(err)
return {}
def get_engine_status(self) -> dict:
return {
"turns_simulated": self.turns_simulated,
"strategy_used": self.strategy.get_strategy_name(),
"total_damage": self.total_damage,
"cards_created": self.created_cards,
}

View File

@@ -0,0 +1,15 @@
from .AggresiveStrategy import AgressiveStrategy
from .CardFactory import CardFactory
from .FantasyCardFactory import FantasyCardFactory
from .GameEngine import GameEngine
from .GameStrategy import GameStrategy
__version__ = "1.0.0"
__author__ = "dgaillet"
__all__ = [
"AgressiveStrategy",
"CardFactory",
"FantasyCardFactory",
"GameEngine",
"GameStrategy",
]

View File

@@ -0,0 +1,27 @@
from .GameEngine import GameEngine
from .FantasyCardFactory import FantasyCardFactory
from .AggresiveStrategy import AgressiveStrategy
def main() -> None:
print("=== DataDeck Game Engine ===\n")
print("Configuring Fantasy Card Game...")
engine = GameEngine()
engine.configure_engine(FantasyCardFactory(), AgressiveStrategy())
print(f"Factory: {engine.factory.__class__.__name__}")
print(f"Strategy: {engine.strategy.__class__.__name__}")
print(f"Available types: {engine.factory.get_supported_types()}")
print("\nSimulating aggressive turn...")
actions = engine.simulate_turn()
print("\nTurn execution:")
print(f"Strategy: {engine.strategy.get_strategy_name()}")
print(f"Actions: {actions}")
print("\nGame Report:")
print(f"{engine.get_engine_status()}")
print(
"\nAbstract Factory + Strategy Pattern: Maximum flexibility achieved!"
)
if __name__ == "__main__":
main()

15
07/ex4/Rankable.py Normal file
View File

@@ -0,0 +1,15 @@
from abc import ABC, abstractmethod
class Rankable(ABC):
@abstractmethod
def calculate_rating(self) -> int: ...
@abstractmethod
def update_wins(self, wins: int) -> None: ...
@abstractmethod
def update_losses(self, losses: int) -> None: ...
@abstractmethod
def get_rank_info(self) -> dict: ...

97
07/ex4/TournamentCard.py Normal file
View File

@@ -0,0 +1,97 @@
from ex0 import Card
from ex2 import Combatable
from .Rankable import Rankable
from typing import Union
class TournamentCard(Card, Combatable, Rankable):
def __init__(
self,
id: str,
name: str,
cost: int,
rarity: str,
damage: int,
health: int,
shield: int,
rank: int,
) -> None:
super().__init__(name, cost, rarity)
self.id = id
self.looses = 0
self.wins = 0
self.damage = damage
self.health = health
self.shield = shield
self.rank = rank
def play(self, game_state: dict) -> dict:
try:
res: dict[str, int | str] = {}
if game_state["mana"] < 2:
raise Exception("Not enough mana")
res["card_played"] = self.name
res["mana_used"] = 2
return res
except Exception as err:
print(err)
return {}
def attack(self, target: str) -> dict:
return {
"attacker": self.name,
"target": target,
"damage_dealt": self.damage,
"combat_type": "melee",
}
def defend(self, incoming_damage: int) -> dict:
res: dict[str, Union[str, int, bool]] = {}
res["defender"] = self.name
if incoming_damage <= self.shield:
res["damage_blocked"] = incoming_damage
res["damage_taken"] = 0
else:
res["damage_taken"] = incoming_damage - self.shield
res["damage_blocked"] = self.shield
self.health -= incoming_damage - self.shield
res["still_alive"] = self.health > 0
return res
def get_combate_stats(self) -> dict:
return {
"damage": self.damage,
"health": self.health,
"shield": self.shield,
}
def calculate_rating(self) -> int:
try:
if self.wins == 0:
return self.rank - self.looses * 10
return self.rank + (int(self.wins / self.looses) * 10)
except ZeroDivisionError:
return self.rank + self.wins * 10
except Exception as err:
print(err)
return self.rank
def get_tournament_stats(self) -> dict:
return {
"Interfaces": "[Card, Combatable, Rankable]",
"Rating": self.calculate_rating(),
"Record": f"{self.wins}-{self.looses}",
}
def update_wins(self, wins: int) -> None:
self.wins = wins
def update_losses(self, losses: int) -> None:
self.looses = losses
def get_rank_info(self) -> dict:
return {
"wins": self.wins,
"looses": self.looses,
"rank": self.rank,
}

View File

@@ -0,0 +1,65 @@
from .TournamentCard import TournamentCard
class TournamentPlatform:
def __init__(self) -> None:
self.cards: list[TournamentCard] = []
self.math_played = 0
def register_card(self, card: TournamentCard) -> str:
try:
stats = card.get_tournament_stats()
res = f"{card.name} (ID: {card.id}):\n\
- Interfaces: {stats['Interfaces']}\n\
- Rating: {stats['Rating']}\n\
- Record: {stats['Record']}\n"
self.cards += [card]
return res
except Exception:
print("Invalid card")
return "error"
def create_match(self, card1_id: str, card2_id: str) -> dict:
from random import shuffle
try:
cards = [
card
for card in self.cards
if card.id == card1_id or card.id == card2_id
]
if len(cards) != 2:
raise Exception(
"At least once of cards id provide isn't in platform"
)
shuffle(cards)
winner = cards.pop()
loser = cards.pop()
winner.update_wins(winner.wins + 1)
loser.update_losses(loser.looses + 1)
self.math_played += 1
return {
"winner": winner.id,
"loser": loser.id,
"winner_rating": winner.calculate_rating(),
"loser_rating": loser.calculate_rating(),
}
except Exception as err:
print(err)
return {}
def get_leaderboard(self) -> list:
return sorted(
self.cards, key=lambda x: x.calculate_rating(), reverse=True
)
def generate_tournament_report(self) -> dict:
return {
"total_cards": len(self.cards),
"mathes_played": self.math_played,
"avg_rating": int(
sum([card.calculate_rating() for card in self.cards])
/ len(self.cards)
),
"platform_status": "active",
}

7
07/ex4/__init__.py Normal file
View File

@@ -0,0 +1,7 @@
from .Rankable import Rankable
from .TournamentCard import TournamentCard
from .TournamentPlatform import TournamentPlatform
__version__ = "1.0.0"
__author__ = "dgaillet"
__all__ = ["Rankable", "TournamentCard", "TournamentPlatform"]

39
07/ex4/main.py Normal file
View File

@@ -0,0 +1,39 @@
from .TournamentCard import TournamentCard
from .TournamentPlatform import TournamentPlatform
def main() -> None:
print("=== DataDeck Tournament Platform ===\n")
print("Registering Tournament Cards...\n")
platform = TournamentPlatform()
print(
platform.register_card(
TournamentCard(
"dragon_001", "Fire Dragon", 20, "Rare", 15, 25, 5, 1200
)
)
)
print(
platform.register_card(
TournamentCard(
"wizard_001", "Ice Wizard", 15, "common", 10, 30, 4, 1150
)
)
)
print("Creating tournament match...")
match_res = platform.create_match("dragon_001", "wizard_001")
print(f"Math result: {match_res}\n")
print("Tournament Leaderboard:")
leaderboard = platform.get_leaderboard()
for i in range(len(leaderboard)):
print(f"{i + 1}. {leaderboard[i].name} - Rating:\
{leaderboard[i].calculate_rating()}\
({leaderboard[i].get_tournament_stats()['Record']})")
print("\nPlatform Report:")
print(platform.generate_tournament_report())
print("\n=== Tournament Platform Successfully Deployed! ===")
print("All abstract patterns working together harmoniously!")
if __name__ == "__main__":
main()