Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@Pagliacii
Last active November 7, 2021 06:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Pagliacii/7969cd9edc4a93b79d7428bd93e44283 to your computer and use it in GitHub Desktop.
Save Pagliacii/7969cd9edc4a93b79d7428bd93e44283 to your computer and use it in GitHub Desktop.
An easy action adventure game based on text.
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
"""An easy action adventure game based on text."""
import random
import time
import uuid
from typing import Dict, Generator, List, Protocol
class WeaponBehavior(Protocol):
"""A behavior that a weapon could be performed."""
attack: int
article: str
name: str
def use_weapon(self, enemy: "Character") -> None:
"""Uses a weapon to attack an enemy"""
print(f"Attacking with {self.article} {self.name}: -{self.attack}")
enemy.hurt(self.attack)
class KnifeBehavior(WeaponBehavior):
"""A knife"""
attack = 5
article = "a"
name = "knife"
class BowAndArrowBehavior(WeaponBehavior):
"""A bow and arrows"""
attack = 8
article = "a"
name = "bow and arrows"
class AxeBehavior(WeaponBehavior):
"""An axe"""
attack = 15
article = "an"
name = "axe"
class SwordBehavior(WeaponBehavior):
"""A sword"""
attack = 10
article = "a"
name = "sword"
class Character(Protocol):
"""A game character"""
cid: str
weapon: WeaponBehavior
name: str
health: int = 10
speed: int
shield: int
_hit_rate: float
_dodge_rate: float
def __new__(cls):
cls.cid = uuid.uuid4().hex
cls._hit_rate = random.uniform(0.08, 1.0)
cls._dodge_rate = random.uniform(0.0, 0.2)
return super().__new__(cls)
def fight(self, enemy: "Character") -> None:
"""Fights an enemy with a weapon"""
if random.random() <= self._hit_rate:
print(f"{self.name}'s attack is missing!")
return
self.weapon.use_weapon(enemy)
def hurt(self, attack) -> None:
"""Hurts by an attack"""
if random.random() <= self._dodge_rate:
print(f"{self.name} is dodging!")
return
self.health -= attack - self.shield
print(
f"Hurt > {self.name}: Health = {self.health}, Shield = {self.shield}"
)
def death(self) -> bool:
"""This character is dead."""
return self.health <= 0
class King(Character):
"""The king of a kingdom"""
name = "King"
health = 10
speed = 8
shield = 8
weapon = BowAndArrowBehavior()
class Queen(Character):
"""The queen"""
name = "Queen"
health = 8
speed = 10
shield = 8
weapon = KnifeBehavior()
class Knight(Character):
"""The knight"""
name = "Knight"
health = 12
speed = 10
shield = 8
weapon = SwordBehavior()
class Troll(Character):
"""The troll"""
name = "Troll"
health = 32
speed = 6
shield = 2
weapon = AxeBehavior()
class Goblin(Character):
"""The goblin"""
name = "Goblin"
health = 6
speed = 12
shield = 4
weapon = KnifeBehavior()
class Game(object):
"""The game"""
_heroes: Dict[str, Character] = {
c.cid: c for c in (King(), Queen(), Knight())
}
_enemies: Dict[str, Character] = {c.cid: c for c in (Troll(), Goblin())}
_round: int = 0
_round_ticks: int = 16
_wait_time: float = 1.0
_finished: bool = False
def all_characters(self) -> Generator[Character, None, None]:
"""A generator to yield all characters"""
characters: List[Character] = []
characters.extend(self._heroes.values())
characters.extend(self._enemies.values())
characters.sort(key=lambda c: c.speed, reverse=True)
for character in characters:
yield character
def run(self) -> None:
"""Let's play the game."""
random.seed()
print("Fight!!!")
while True:
self._round += 1
print("=" * 16 + f"Round {self._round}" + "=" * 16)
self.activate_round()
if self._finished:
break
time.sleep(self._wait_time)
print("=" * 39)
print("Game over.")
def attack_enemy(self, character: Character) -> Character:
"""Controls the character to attack a random enemy
Args:
character (Character): Which one will do an attack.
Returns:
Character: which enemy has been attacked.
"""
enemy: Character = random.choice(
list(
(
self._enemies
if character.cid in self._heroes
else self._heroes
).values()
)
)
print(f"{character.name} turn")
character.fight(enemy)
return enemy
def activate_round(self):
"""Activates a round"""
tick: int = self._round_ticks
while not self._finished and tick > 0:
for character in self.all_characters():
if character.speed != tick:
continue
enemy: Character = self.attack_enemy(character)
if enemy.death():
print(f"{enemy.name} is dead.")
self._heroes.pop(enemy.cid, None)
self._enemies.pop(enemy.cid, None)
if not (self._heroes and self._enemies):
self._finished = True
if self._heroes:
print("Heroes win.")
else:
print("Enemies win.")
break
tick -= 1
if __name__ == "__main__":
game = Game()
game.run()
@Pagliacii
Copy link
Author

Pagliacii commented Nov 7, 2021

Output:

λ py game.py
Fight!!!
================Round 1================
Goblin turn
Goblin's attack is missing!
Queen turn
Queen's attack is missing!
Knight turn
Attacking with a sword: -10
Hurt > Goblin: Health = 0, Shield = 4
Goblin is dead.
King turn
King's attack is missing!
Troll turn
Attacking with an axe: -15
King is dodging!
================Round 2================
Queen turn
Queen's attack is missing!
Knight turn
Knight's attack is missing!
King turn
Attacking with a bow and arrows: -8
Hurt > Troll: Health = 26, Shield = 2
Troll turn
Attacking with an axe: -15
Hurt > King: Health = 3, Shield = 8
================Round 3================
Queen turn
Attacking with a knife: -5
Hurt > Troll: Health = 23, Shield = 2
Knight turn
Attacking with a sword: -10
Hurt > Troll: Health = 15, Shield = 2
King turn
King's attack is missing!
Troll turn
Attacking with an axe: -15
Hurt > King: Health = -4, Shield = 8
King is dead.
================Round 4================
Queen turn
Queen's attack is missing!
Knight turn
Attacking with a sword: -10
Hurt > Troll: Health = 7, Shield = 2
Troll turn
Attacking with an axe: -15
Hurt > Queen: Health = 1, Shield = 8
================Round 5================
Queen turn
Queen's attack is missing!
Knight turn
Attacking with a sword: -10
Hurt > Troll: Health = -1, Shield = 2
Troll is dead.
Heroes win.
=======================================
Game over.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment