Question Details

No question body available.

Tags

python game-development text-based python-3.12

Answers (15)

April 10, 2026 Score: 4 Rep: 149,764 Quality: Low Completeness: 0%

why do you use images instead of putting text

April 10, 2026 Score: 3 Rep: 4,348 Quality: Medium Completeness: 60%

Lots of stuff you can immediately change. Look into state machines and transitions. This will give you a lot cleaner code and will allow you to easily add states or transitions without having to go back and figure out where its needs to be added. You could also easily swap some of the hardcoded values to constants at the top of a file so that you can change those in one place without having to tweak them everywhere.

Basically can tweak to something like this:

import random

Adjust these to balance the game.

STARTINGHP = 100 STARTINGSTAMINA = 100

JABDAMAGE = 10 JABSTAMINACOST = 5 JABMISSSIDES = 4 # 1-in-4 chance to miss (25%)

UPPERCUT
DAMAGE = 30 UPPERCUTSTAMINACOST = 35 UPPERCUTMISSSIDES = 2 # 1-in-2 chance to miss (50%)

BLOCKSTAMINAGAIN = 10 BLOCKDAMAGEMULTIPLIER = 0.5 # blocking halves incoming damage

To add a new state (e.g. "shop", "heal"), define it here

and add an elif branch in the main loop.

STATEPLAYERTURN = "playerturn" STATEENEMYTURN = "enemyturn" STATEPLAYERWIN = "playerwin" STATEENEMYWIN = "enemywin"

def rollmiss(misssides): """Returns True if the attack misses. misssides=4 means a 1-in-4 miss chance.""" return random.randint(1, misssides) == 1

def attemptattack(attackerstamina, defenderhp, defenderblocking, damage, staminacost, misssides): """Resolve one attack. Returns (stamina, defenderhp, result). result is one of: 'nostamina', 'miss', 'blocked', 'hit'.""" if attackerstamina < staminacost: return attackerstamina, defenderhp, "nostamina"

attacker
stamina -= staminacost

if roll
miss(misssides): return attackerstamina, defenderhp, "miss"

if defender
blocking: defenderhp -= int(damage * BLOCKDAMAGEMULTIPLIER) return attackerstamina, defenderhp, "blocked"

defender
hp -= damage return attackerstamina, defenderhp, "hit"

States

playerhp = STARTINGHP playerstamina = STARTINGSTAMINA playerblocking = False

enemy
hp = STARTINGHP enemystamina = STARTINGSTAMINA

state = STATE
PLAYERTURN

Main loop

while state not in (STATE
PLAYERWIN, STATEENEMYWIN):

if state == STATE
PLAYERTURN: print("----------") print(f"enemy health = {enemyhp}") print(f"player health = {playerhp}") print(f"player stamina = {playerstamina}")

choice = input( f" actions:\n" f" 1. jab (costs {JABSTAMINACOST} stamina, deals {JABDAMAGE} damage)\n" f" 2. uppercut (costs {UPPERCUTSTAMINACOST} stamina, deals {UPPERCUTDAMAGE} damage)\n" f" 3. block (gains {BLOCKSTAMINAGAIN} stamina)\n" f" > " )

playerblocking = False

if choice == "1": player
stamina, enemyhp, result = attemptattack( playerstamina, enemyhp, False, JABDAMAGE, JABSTAMINACOST, JABMISSSIDES) if result == "nostamina": print("not enough stamina — blocking instead") playerstamina += BLOCKSTAMINAGAIN playerblocking = True elif result == "miss": print("you miss!") else: print(f"you land a jab for {JABDAMAGE} damage")

elif choice == "2": player
stamina, enemyhp, result = attemptattack( playerstamina, enemyhp, False, UPPERCUTDAMAGE, UPPERCUTSTAMINACOST, UPPERCUTMISSSIDES) if result == "nostamina": print("not enough stamina — blocking instead") playerstamina += BLOCKSTAMINAGAIN playerblocking = True elif result == "miss": print("you miss!") else: print(f"you land an uppercut for {UPPERCUTDAMAGE} damage")

elif choice == "3": player
stamina += BLOCKSTAMINAGAIN playerblocking = True print(f"you brace and recover {BLOCKSTAMINAGAIN} stamina")

state = STATE
PLAYERWIN if enemyhp
April 10, 2026 Score: 3 Rep: 2,255 Quality: Low Completeness: 0%

please stop posting pictures of text ... it cannot be copied and tested. .. people using screen readers are excluded from participating ... giving you a downvote

April 10, 2026 Score: 2 Rep: 23,906 Quality: Medium Completeness: 80%

A long python script with no functions is hard to read, understand, and debug. First consider an object-oriented approach making classes of the player and enemy. First the array of each set of hp, stamina, and actions become variables in the respective classes. Next encapsulate the player logic in those classes in a move() function, and separate functions for each of the actions.

class Player:

def init(self): self.hp = 100 self.stamina = 100 self.action = ""

def move(self): self.action = input(""" actions: 1. jab (takes 5 stamina) deals 10 damage 2. uppercut (takes 35 stamina) deals 30 damage 3. block (gives 10 stamina) >> """) match self.action: case "1": self.jab() case "2": self.uppercut() case "3": self.block() case : # The underscore () is the wildcard/default case print("invalid action - lose a turn")

def jab(self): # add jab action logic here

def uppercutb(self): # add upper cut action logic here

def upper_block(self): # add block action logic here

The main code is then simplified to something like this.

player = Player()
enemy = Enemy()
turn = "player"
while player.hp > 0 and enemy.hp > 0:
 if turn == "player":
    player.move()
    turn = "enemy"
 else:
    enemy.move()
    turn = "player"

At the end, add your win/lose logic, e.g. if enemy.hp == 0 and player.hp > 0: print("player wins").

There are many tutorials to guide you on creating classes in Python. For example, see https://realpython.com/python-classes/.

April 10, 2026 Score: 2 Rep: 790,174 Quality: Low Completeness: 20%

Code Review is a better place to ask questions like this.

April 10, 2026 Score: 1 Rep: 13,639 Quality: Low Completeness: 20%

You would probably get a good deal out of embracing Data Classes

April 10, 2026 Score: 1 Rep: 16 Quality: Low Completeness: 80%
  1. Add spacing between each line of code

  2. You need an error checking loop in case the user's input is invalid, otherwise the player's turn is skipped with no explanation

  3. enemyhp is undefined

if turn == "player": 
   turn = "enemy"
  1. I understand this is used to alternate turns, but when read aloud it makes no sense. Instead, the turn variable should be a number that increases at the end of each iteration. If the number is odd, it's the player's turn, if the number is even, it's the enemy's turn
player = [100, 100, ""]
enemy = [100, 100, 0]
hit = [0, 0]
damage = [10, 30]
  1. what does each item in these arrays even mean??? There should be comments explaining this
----------
enemy health = 100
player health = 5.0
player stamina = 460
 actions:
    1. jab (takes 5 stamina)
    deals 10 damage
    2. uppercut (takes 35 stamina)
    deals 30 damage
    3. block (gives 10 stamina)
    3
----------
the enemy throws a jab
axolotl@fedora:~/Code/boxinggame$
  1. The game abruptly ends, there should be a message saying whether you won or lost

Hope this helps

April 10, 2026 Score: 1 Rep: 5,077 Quality: Low Completeness: 80%

Some further reorganization that you might find interesting:

  • Adding type hints
    • Allows the IDE you're working in to detect what kind of object something is supposed to be
  • Putting the main loop into a main() method
    • Python coding standard practice
    • If this became a larger project with imports, importing from this file would normally run the game which is not what we want
    • The if name == "main" block only runs if you run the file directly
  • Encapsulating the game state and attack results as Enums instead of
    • No need to rely on magic strings which might have typos
    • Allows you to use IDE autocomplete more easily
    • Makes mistakes (typos for instance) easier to catch
  • Encapsulating player/enemy state in a dataclass
    • related variables like playerhp, playerstamina, playerblocking all get passed around together, just like in the arrays you set up
    • attribute names like player.hp mean you don't need to remember which part of array corresponds to what
    • (you could accomplish a similar improvement over your arrays by using a Python dictionary; some of this is down to preference)
  • modifying attemptattack to change fighter objects in-place
  • extracting action functions like dojab and douppercut
    • makes the main loop cleaner
    • separates out the concern of printing messages

See this code:


import random
from dataclasses import dataclass
from enum import Enum, auto

Adjust these to balance the game.

STARTINGHP = 100 STARTINGSTAMINA = 100

JABDAMAGE = 10 JABSTAMINACOST = 5 JABMISSSIDES = 4 # 1-in-4 chance to miss (25%)

UPPERCUT
DAMAGE = 30 UPPERCUTSTAMINACOST = 35 UPPERCUTMISSSIDES = 2 # 1-in-2 chance to miss (50%)

BLOCKSTAMINAGAIN = 10 BLOCKDAMAGEMULTIPLIER = 0.5 # blocking halves incoming damage

Using an Enum instead of plain strings means a typo like

GameState.PLAYRTURN raises an AttributeError immediately,

rather than silently never matching.

class GameState(Enum): PLAYER
TURN = auto() ENEMYTURN = auto() PLAYERWIN = auto() ENEMYWIN = auto()

class AttackResult(Enum): NO
STAMINA = auto() MISS = auto() BLOCKED = auto() HIT = auto()

A dataclass groups related variables into a single object.

Python auto-generates init and repr for you, so

Fighter("Player") gives you hp=100, stamina=100, blocking=False

without writing a constructor by hand.

@dataclass class Fighter: name: str hp: int = STARTINGHP stamina: int = STARTINGSTAMINA blocking: bool = False

def rollmiss(misssides: int) -> bool: """Returns True if the attack misses. misssides=4 means a 1-in-4 miss chance.""" return random.randint(1, misssides) == 1

def attemptattack( attacker: Fighter, defender: Fighter, damage: int, staminacost: int, misssides: int, ) -> AttackResult: """Resolve one attack. Mutates attacker.stamina and defender.hp in place and returns an AttackResult.""" if attacker.stamina < staminacost: return AttackResult.NOSTAMINA

attacker.stamina -= stamina
cost

if rollmiss(misssides): return AttackResult.MISS

if defender.blocking: defender.hp -= int(damage * BLOCKDAMAGEMULTIPLIER) return AttackResult.BLOCKED

defender.hp -= damage return AttackResult.HIT

def dojab(attacker: Fighter, defender: Fighter) -> AttackResult: """Attempt a jab. Falls back to blocking if out of stamina.""" result = attemptattack(attacker, defender, JABDAMAGE, JABSTAMINACOST, JABMISSSIDES) if result == AttackResult.NOSTAMINA: doblock(attacker) return result

def do
uppercut(attacker: Fighter, defender: Fighter) -> AttackResult: """Attempt an uppercut. Falls back to blocking if out of stamina.""" result = attemptattack(attacker, defender, UPPERCUTDAMAGE, UPPERCUTSTAMINACOST, UPPERCUTMISSSIDES) if result == AttackResult.NOSTAMINA: doblock(attacker) return result

def doblock(fighter: Fighter) -> None: """Recover stamina and enter a blocking stance.""" fighter.stamina += BLOCKSTAMINAGAIN fighter.blocking = True

def main() -> None: player = Fighter(name="Player") enemy = Fighter(name="Enemy")

state = GameState.PLAYER
TURN

while state not in (GameState.PLAYERWIN, GameState.ENEMYWIN):

if state == GameState.PLAYERTURN: print("----------") print(f"enemy health = {enemy.hp}") print(f"player health = {player.hp}") print(f"player stamina = {player.stamina}")

print("actions:") print(f" 1. jab (costs {JAB
STAMINACOST} stamina, deals {JABDAMAGE} damage)") print(f" 2. uppercut (costs {UPPERCUTSTAMINACOST} stamina, deals {UPPERCUTDAMAGE} damage)") print(f" 3. block (gains {BLOCKSTAMINAGAIN} stamina)") choice = input(" > ")

player.blocking = False

if choice == "1": result = do
jab(player, enemy) if result == AttackResult.NOSTAMINA: print("not enough stamina — blocking instead") elif result == AttackResult.MISS: print("you miss!") else: print(f"you land a jab for {JABDAMAGE} damage")

elif choice == "2": result = douppercut(player, enemy) if result == AttackResult.NOSTAMINA: print("not enough stamina — blocking instead") elif result == AttackResult.MISS: print("you miss!") else: print(f"you land an uppercut for {UPPERCUTDAMAGE} damage")

elif choice == "3": do
block(player) print(f"you brace and recover {BLOCKSTAMINAGAIN} stamina")

state = GameState.PLAYER_WIN if enemy.hp
April 10, 2026 Score: 0 Rep: 1 Quality: Low Completeness: 0%

I didn't know about that group, I'll ask this there too

April 10, 2026 Score: 0 Rep: 149,764 Quality: Low Completeness: 60%


  • you could split code to functions

  • you could use class or at least dictionary for player/enemy information -

    e.g. player = {"x":100, "y":100, "action":""}


April 10, 2026 Score: 0 Rep: 1 Quality: Low Completeness: 0%

This is such a big help, thank you so much!

April 10, 2026 Score: 0 Rep: 1 Quality: Low Completeness: 10%

you can always use the doom engine concepts to go very minimal for rendering just up date spritand back ground now you create store sprites to a retro visaul locost retro resentation of the store

April 10, 2026 Score: 0 Rep: 5,077 Quality: Low Completeness: 60%

One further nice change is to extract functions for "playerturn" and "enemyturn", like this:


import random
from dataclasses import dataclass
from enum import Enum, auto

Adjust these to balance the game.

STARTINGHP = 100 STARTINGSTAMINA = 100

JABDAMAGE = 10 JABSTAMINACOST = 5 JABMISSSIDES = 4 # 1-in-4 chance to miss (25%)

UPPERCUT
DAMAGE = 30 UPPERCUTSTAMINACOST = 35 UPPERCUTMISSSIDES = 2 # 1-in-2 chance to miss (50%)

BLOCKSTAMINAGAIN = 10 BLOCKDAMAGEMULTIPLIER = 0.5 # blocking halves incoming damage

Using an Enum instead of plain strings means a typo like

GameState.PLAYRTURN raises an AttributeError immediately,

rather than silently never matching.

class GameState(Enum): PLAYER
TURN = auto() ENEMYTURN = auto() PLAYERWIN = auto() ENEMYWIN = auto()

class AttackResult(Enum): NO
STAMINA = auto() MISS = auto() BLOCKED = auto() HIT = auto()

A dataclass groups related variables into a single object.

Python auto-generates init and repr for you, so

Fighter("Player") gives you hp=100, stamina=100, blocking=False

without writing a constructor by hand.

@dataclass class Fighter: name: str hp: int = STARTINGHP stamina: int = STARTINGSTAMINA blocking: bool = False

def rollmiss(misssides: int) -> bool: """Returns True if the attack misses. misssides=4 means a 1-in-4 miss chance.""" return random.randint(1, misssides) == 1

def attemptattack( attacker: Fighter, defender: Fighter, damage: int, staminacost: int, misssides: int, ) -> AttackResult: """Resolve one attack. Mutates attacker.stamina and defender.hp in place and returns an AttackResult.""" if attacker.stamina < staminacost: return AttackResult.NOSTAMINA

attacker.stamina -= stamina
cost

if rollmiss(misssides): return AttackResult.MISS

if defender.blocking: defender.hp -= int(damage BLOCK_DAMAGE_MULTIPLIER) return AttackResult.BLOCKED

defender.hp -= damage return AttackResult.HIT

def do_jab(attacker: Fighter, defender: Fighter) -> AttackResult: """Attempt a jab. Falls back to blocking if out of stamina.""" result = attempt_attack(attacker, defender, JAB_DAMAGE, JAB_STAMINA_COST, JAB_MISS_SIDES) if result == AttackResult.NO_STAMINA: do_block(attacker) return result

def do_uppercut(attacker: Fighter, defender: Fighter) -> AttackResult: """Attempt an uppercut. Falls back to blocking if out of stamina.""" result = attempt_attack(attacker, defender, UPPERCUT_DAMAGE, UPPERCUT_STAMINA_COST, UPPERCUT_MISS_SIDES) if result == AttackResult.NO_STAMINA: do_block(attacker) return result

def do_block(fighter: Fighter) -> None: """Recover stamina and enter a blocking stance.""" fighter.stamina += BLOCK_STAMINA_GAIN fighter.blocking = True

def player_turn(player: Fighter, enemy: Fighter) -> GameState: """Show status, prompt for an action, and resolve it.""" print("----------") print(f"enemy health = {enemy.hp}") print(f"player health = {player.hp}") print(f"player stamina = {player.stamina}")

print("actions:") print(f" 1. jab (costs {JAB_STAMINA_COST} stamina, deals {JAB_DAMAGE} damage)") print(f" 2. uppercut (costs {UPPERCUT_STAMINA_COST} stamina, deals {UPPERCUT_DAMAGE} damage)") print(f" 3. block (gains {BLOCK_STAMINA_GAIN} stamina)") choice = input(" > ")

player.blocking = False

if choice == "1": result = do_jab(player, enemy) if result == AttackResult.NO_STAMINA: print("not enough stamina — blocking instead") elif result == AttackResult.MISS: print("you miss!") else: print(f"you land a jab for {JAB_DAMAGE} damage")

elif choice == "2": result = do_uppercut(player, enemy) if result == AttackResult.NO_STAMINA: print("not enough stamina — blocking instead") elif result == AttackResult.MISS: print("you miss!") else: print(f"you land an uppercut for {UPPERCUT_DAMAGE} damage")

elif choice == "3": do_block(player) print(f"you brace and recover {BLOCK_STAMINA_GAIN} stamina")

return GameState.PLAYER_WIN if enemy.hp GameState: """Pick a random action for the enemy and resolve it. To make the AI smarter, replace the randint with a strategy function.""" enemy_action = random.randint(1, 3) print("----------")

if enemy_action == 1: print("the enemy throws a jab") result = do_jab(enemy, player) if result == AttackResult.NO_STAMINA: print("the enemy doesn't have enough stamina — blocks instead") elif result == AttackResult.MISS: print("the enemy misses!") elif result == AttackResult.BLOCKED: print(f"you blocked — only took {int(JAB_DAMAGE
BLOCKDAMAGEMULTIPLIER)} damage") else: print(f"the enemy lands a jab for {JABDAMAGE} damage")

elif enemy
action == 2: print("the enemy throws an uppercut") result = douppercut(enemy, player) if result == AttackResult.NOSTAMINA: print("the enemy doesn't have enough stamina — blocks instead") elif result == AttackResult.MISS: print("the enemy misses!") elif result == AttackResult.BLOCKED: print(f"you blocked — only took {int(UPPERCUTDAMAGE * BLOCKDAMAGEMULTIPLIER)} damage") else: print(f"the enemy lands an uppercut for {UPPERCUTDAMAGE} damage")

elif enemyaction == 3: doblock(enemy) print(f"the enemy blocks — +{BLOCKSTAMINAGAIN} enemy stamina")

return GameState.ENEMYWIN if player.hp None: player = Fighter(name="Player") enemy = Fighter(name="Enemy")

state = GameState.PLAYER
TURN

while state not in (GameState.PLAYERWIN, GameState.ENEMYWIN): if state == GameState.PLAYERTURN: state = playerturn(player, enemy) elif state == GameState.ENEMYTURN: state = enemyturn(player, enemy)

# Results print("==========") if state == GameState.PLAYER_WIN: print("You win!") else: print("You lose!")

if name == "main": main()

April 10, 2026 Score: 0 Rep: 1,237 Quality: Low Completeness: 60%

Life is more beautiful when there are plenty of functions :)

Avoid repeating code...

Make code more readable...

Simplify modification and correction of errors...

import random

def getPlayerInitialState( name, ishuman ):

# we include the player's name and type to # make the code or as agnostic as possible return [ 100, 100, "", name, is
human ]

players = [ getPlayerInitialState( "player", True ), getPlayerInitialState( "enemy", False ) ]

def action( playera, playerb, hit ):

# depending on whether the player is human or not, # we use different mechanisms to instantiate "playera" if playera[ 4 ]: playera[ 2 ] = input( """ actions: 1. jab takes 5 stamina deals 10 damage 2. uppercut takes 35 stamina deals 30 damage 3. block gives 10 stamina """) else: playera[ 2 ] = random.randint( 1, 3 )

# I have not been able to understand the mechanics of # the game, apparently, according to your code, the # code that is executed when it is the user's turn or # the machine's is different, it does not seem very # logical to me...

def showstates(): for player in players: print( f"{player[ 3 ]}:" ) print( f" health = {player[ 0 ]}" ) print( f" stamina = {player[ 1 ]}\n" )

def play(): hit = [ 0, 0 ] while True: show
states() hit = [ random.randint( 1, 4 ), random.randint( 1, 2 ) ]

# by calling "action" with the parameters reversed, # we achieve the same effect as using a variable to # determine the turn, if one of the calls returns # "true", we exit the loop if action( players[ 0 ], players[ 1 ], hit ): return

if action( players[ 1 ], players[ 0 ], hit ): return

play()
April 10, 2026 Score: 0 Rep: 16 Quality: Low Completeness: 0%

There, I replaced the images with code blocks.