Text-Turn based dueling game

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
5
down vote

favorite












I have recently started to learn python, and I have made my first fighting duel game. I'm planning on adding more stuff in the future like shops and items so you get a way to spend gold, but for now the current features are:




  • Character creation (with saving and loading),


  • Upgrading Str/Def,

  • Keeping Score


  • Battling AI or Battling 1v1.

  • (you also get rewards for winning)

But for now I'm happy with my progress. Please review my code!



import random
import json
import time
r = random
#INSTRUCTIONS FOR FIRST TIME USE
#MAKE 3 COMPUTER ACCOUNTS NAMED "Computer_Easy", "Computer_Med" and "Computer_Hard" AND SET THEIR STATS HOWEVER YOU LIKE! OTHERWISE UNABLE TO PLAY VS AI
class Character():
#Change value of default if you want people to start with higher str/def when they make their account.
def __init__(self, name, default=1, health=None, strength=None,
defence=None, gold=0, exp=0, wins=0, losses=0,
):
self.name = name
self.health = 100
self.strength = default if strength is None else strength
self.defence = default if defence is None else defence
self.gold = 0
self.exp = 0
self.wins = 0
self.losses = 0

def make_account(self, name): #Create a new user to /accounts folder with default stats as listed above
save_name = name
path = 'accounts/0.json'.format(save_name)
data =
"health": self.health,
"strength": self.strength,
"defence": self.defence,
"gold": self.gold,
"exp": self.exp,
"wins": self.wins,
"losses": self.losses,

with open(path, 'w+') as f:
json.dump(data, f)

def load_account(self, name):
load_name = name
path_two = 'accounts/0.json'.format(load_name)
with open(path_two, 'r') as f:
data = json.load(f)
return data

def upgrade_stat(self, name): #Upgrade either defence or strength
target = raw_input("What stat do you want to upgrade?")
if target in "health", "gold", "exp", "wins", "losses":
print("you cannot do that!")
return
load_name = name
path_two = 'accounts/0.json'.format(load_name)
with open(path_two, 'r') as f:
data = json.load(f)
if data["exp"] < 100:
print("You don't have enough xp!")
else:
data["exp"] -= 100
data[target] += 1
with open (path_two, 'w+') as g:
json.dump(data, g)


def calculate_damage(self, damage_amount, attacker, defender):
attacker_stats = self.load_account(name=attacker)
defender_stats = self.load_account(name=defender)

#You get damage boost, depending on attacker strength level and defender defence level.
damage_amount_boost = (attacker_stats["strength"] * damage_amount / (attacker_stats["strength"] + defender_stats["defence"])) + damage_amount
if (damage_amount_boost > self.health):
overkill = abs(self.health - damage_amount_boost)
self.health = 0
if (overkill > 0):
print("0 takes fatal damage from 1, with 2 overkill!"
.format(self.name.capitalize(), attacker, overkill))
else:
print("0 takes fatal damage from 1!"
.format(self.name.capitalize(), attacker))
else:
self.health -= damage_amount_boost
print("0 takes 1 damage from 2!"
.format(self.name.capitalize(), damage_amount_boost, attacker))

def calculate_heal(self, heal_amount):
if (heal_amount + self.health > 100):
self.health = 100
print("0 heals back to full health!"
.format(self.name.capitalize()))
else:
self.health += heal_amount
print("0 heals for 1!"
.format(self.name.capitalize(), heal_amount))

def parse_int(input):
try:
int(input)
return True
except ValueError:
return False

def get_selection():
valid_input = False
while (valid_input is False):
print()
choice = input("Select an attack: ")
if (parse_int(choice) is True):
return int(choice)
else:
print("The input was invalid. Please try again.")

def get_computer_selection(health):
sleep_time = random.randrange(2, 5)
print("Computer thinking...")
time.sleep(sleep_time)

if (health <= 35):
# Have the computer heal ~50% of its turns when <= 35
result = random.randint(1, 6)
if (result % 2 == 0):
return 3
else:
return random.randint(1, 2)
elif (health == 100):
return random.randint(1, 2)
else:
return random.randint(1, 3)

def play_round_ai(computer, human):
game_in_progress = True
current_player = computer
movesprint = '1. Mild, 2. Hard, 3. Heal'

while game_in_progress:
if (current_player == computer):
current_player = human
else:
current_player = computer
print(
"You have 0 health remaining and the "
"computer has 1 health remaining."
.format(human.health, computer.health))
if (current_player == human):
print(movesprint)
move = get_selection()
else:
move = get_computer_selection(computer.health)

if (move == 1):
damage = random.randrange(12, 22)
if (current_player == human):
computer.calculate_damage(damage, human.name, computer.name)
else:
human.calculate_damage(damage, computer.name, human.name)
elif (move == 2):
damage = random.randrange(5, 35)
if (current_player == human):
computer.calculate_damage(damage, human.name, computer.name)
else:
human.calculate_damage(damage, computer.name, human.name)
elif (move == 3):
heal = random.randrange(15, 28)
current_player.calculate_heal(heal)
else:
print ("The input was not valid. Please select a choice again.")

if (human.health == 0):
print("Sorry, you lose!")
computer.wins += 1
load_names = human.name
paths = 'accounts/0.json'.format(load_names)
with open(paths, 'r') as f:
data = json.load(f)
data["losses"] += 1
with open(paths, 'w+') as g:
json.dump(data, g)
game_in_progress = False

if (computer.health == 0):
print("Congratulations, you beat the computer!")
human.wins += 1
load_names = human.name
paths = 'accounts/0.json'.format(load_names)
with open(paths, 'r') as f:
data = json.load(f)
data["exp"] += 25
data["gold"] += 100
data["wins"] += 1
with open(paths, 'w+') as g:
json.dump(data, g)
game_in_progress = False

def play_round_multiplayer(player2, player1):
game_in_progress = True
current_player = player2
movesprint = '1. Mild, 2. Hard, 3. Heal'

while game_in_progress:
if (current_player == player2):
current_player = player1
else:
current_player = player2
#print()
print(
"You have 0 health remaining and the "
"player2 has 1 health remaining."
.format(player1.health, player2.health))
#print()
if (current_player == player1):
print(movesprint)
move = get_selection()
else:
print(movesprint)
move = get_selection()

if (move == 1):
damage = random.randrange(12, 22)
if (current_player == player1):
player2.calculate_damage(damage, player1.name, player2.name)
else:
player1.calculate_damage(damage, player2.name, player1.name)
elif (move == 2):
damage = random.randrange(5, 35)
if (current_player == player1):
player2.calculate_damage(damage, player1.name, player2.name)
else:
player1.calculate_damage(damage, player2.name, player1.name)
elif (move == 3):
heal = random.randrange(15, 28)
current_player.calculate_heal(heal)
else:
print ("The input was not valid. Please select a choice again.")

if (player1.health == 0):
print("0 wins".format(player2.name))
player2.wins += 1
winner_name = player2.name
loser_name = player1.name
winner_path = 'accounts/0.json'.format(winner_name)
loser_path = 'accounts/0.json'.format(loser_name)
with open(winner_path, 'r') as f:
data = json.load(f)
data["exp"] += 25
data["gold"] += 100
data["wins"] += 1
with open(winner_path, 'w+') as g:
json.dump(data, g)
with open(loser_path, 'r') as f:
data = json.load(f)
data["losses"] += 1
with open(loser_path, 'w+') as g:
json.dump(data, g)
game_in_progress = False

if (player2.health == 0):
print("0 wins".format(player1.name))
player1.wins += 1
winner_name = player1.name
loser_name = player2.name
winner_path = 'accounts/0.json'.format(winner_name)
loser_path = 'accounts/0.json'.format(loser_name)
with open(winner_path, 'r') as f:
data = json.load(f)
data["exp"] += 25
data["gold"] += 100
data["wins"] += 1
with open(winner_path, 'w+') as g:
json.dump(data, g)
with open(loser_path, 'r') as f:
data = json.load(f)
data["losses"] += 1
with open(loser_path, 'w+') as g:
json.dump(data, g)
game_in_progress = False

def start_game_ai(name): #Play vs Ai, which you select your difficulty.
target = raw_input("Easy, med or hard?")
if target == "easy":
computer = Character("Computer_Easy") #Make sure you have made all of these accounts in folder Accounts
if target == "med": #Set stats however you like
computer = Character("Computer_Med")
if target == "hard":
computer = Character("Computer_Hard")
human = Character(name)

keep_playing = True

while (keep_playing is True):
print("Current Score:")
print("You - 0".format(human.wins))
print("Computer - 0".format(computer.wins))

computer.health = 100
human.health = 100

play_round_ai(computer, human)
print()
response = raw_input("Play another round?(Y/N)")
if (response.lower() == "n"):
break

def start_game_multiplayer(name, target): #Play a local 1v1 game.
player2 = Character(target)
player1 = Character(name)

keep_playing = True

while (keep_playing is True):
print("Current Score:")
print("Player1 - 0".format(player1.wins))
print("Player2 - 0".format(player2.wins))
player2.health = 100
player1.health = 100
play_round_multiplayer(player2, player1)
#print()
response = raw_input("Play another 1v1? (y/n)")
if (response == "y"):
continue
else:
break

def options(): #Main menu
name = raw_input("Username to load or create?")
print("What do you want to do? If this is your first time, type 5 to create your new account!")
move = raw_input("1. Battle AI | 2. List stats | 3. Play 1v1 | 4. Upgrade str/def | 5. Make new user")
if move == "1":
print("Make sure you already have made all Computer accounts! (Computer_Easy, Computer_Med, Computer_Hard)")
start_game_ai(name)
if move == "2":
stats = Character(name).load_account(name)
print stats
return
if move == "3":
target = raw_input("Who do you want to fight?")
start_game_multiplayer(name, target)
if move == "4":
Character(name).upgrade_stat(name)
stats = Character(name).load_account(name)
print stats
if move == "5":
Character(name).make_account(name)
else:
print("Exiting..")
return

options()






share|improve this question



























    up vote
    5
    down vote

    favorite












    I have recently started to learn python, and I have made my first fighting duel game. I'm planning on adding more stuff in the future like shops and items so you get a way to spend gold, but for now the current features are:




    • Character creation (with saving and loading),


    • Upgrading Str/Def,

    • Keeping Score


    • Battling AI or Battling 1v1.

    • (you also get rewards for winning)

    But for now I'm happy with my progress. Please review my code!



    import random
    import json
    import time
    r = random
    #INSTRUCTIONS FOR FIRST TIME USE
    #MAKE 3 COMPUTER ACCOUNTS NAMED "Computer_Easy", "Computer_Med" and "Computer_Hard" AND SET THEIR STATS HOWEVER YOU LIKE! OTHERWISE UNABLE TO PLAY VS AI
    class Character():
    #Change value of default if you want people to start with higher str/def when they make their account.
    def __init__(self, name, default=1, health=None, strength=None,
    defence=None, gold=0, exp=0, wins=0, losses=0,
    ):
    self.name = name
    self.health = 100
    self.strength = default if strength is None else strength
    self.defence = default if defence is None else defence
    self.gold = 0
    self.exp = 0
    self.wins = 0
    self.losses = 0

    def make_account(self, name): #Create a new user to /accounts folder with default stats as listed above
    save_name = name
    path = 'accounts/0.json'.format(save_name)
    data =
    "health": self.health,
    "strength": self.strength,
    "defence": self.defence,
    "gold": self.gold,
    "exp": self.exp,
    "wins": self.wins,
    "losses": self.losses,

    with open(path, 'w+') as f:
    json.dump(data, f)

    def load_account(self, name):
    load_name = name
    path_two = 'accounts/0.json'.format(load_name)
    with open(path_two, 'r') as f:
    data = json.load(f)
    return data

    def upgrade_stat(self, name): #Upgrade either defence or strength
    target = raw_input("What stat do you want to upgrade?")
    if target in "health", "gold", "exp", "wins", "losses":
    print("you cannot do that!")
    return
    load_name = name
    path_two = 'accounts/0.json'.format(load_name)
    with open(path_two, 'r') as f:
    data = json.load(f)
    if data["exp"] < 100:
    print("You don't have enough xp!")
    else:
    data["exp"] -= 100
    data[target] += 1
    with open (path_two, 'w+') as g:
    json.dump(data, g)


    def calculate_damage(self, damage_amount, attacker, defender):
    attacker_stats = self.load_account(name=attacker)
    defender_stats = self.load_account(name=defender)

    #You get damage boost, depending on attacker strength level and defender defence level.
    damage_amount_boost = (attacker_stats["strength"] * damage_amount / (attacker_stats["strength"] + defender_stats["defence"])) + damage_amount
    if (damage_amount_boost > self.health):
    overkill = abs(self.health - damage_amount_boost)
    self.health = 0
    if (overkill > 0):
    print("0 takes fatal damage from 1, with 2 overkill!"
    .format(self.name.capitalize(), attacker, overkill))
    else:
    print("0 takes fatal damage from 1!"
    .format(self.name.capitalize(), attacker))
    else:
    self.health -= damage_amount_boost
    print("0 takes 1 damage from 2!"
    .format(self.name.capitalize(), damage_amount_boost, attacker))

    def calculate_heal(self, heal_amount):
    if (heal_amount + self.health > 100):
    self.health = 100
    print("0 heals back to full health!"
    .format(self.name.capitalize()))
    else:
    self.health += heal_amount
    print("0 heals for 1!"
    .format(self.name.capitalize(), heal_amount))

    def parse_int(input):
    try:
    int(input)
    return True
    except ValueError:
    return False

    def get_selection():
    valid_input = False
    while (valid_input is False):
    print()
    choice = input("Select an attack: ")
    if (parse_int(choice) is True):
    return int(choice)
    else:
    print("The input was invalid. Please try again.")

    def get_computer_selection(health):
    sleep_time = random.randrange(2, 5)
    print("Computer thinking...")
    time.sleep(sleep_time)

    if (health <= 35):
    # Have the computer heal ~50% of its turns when <= 35
    result = random.randint(1, 6)
    if (result % 2 == 0):
    return 3
    else:
    return random.randint(1, 2)
    elif (health == 100):
    return random.randint(1, 2)
    else:
    return random.randint(1, 3)

    def play_round_ai(computer, human):
    game_in_progress = True
    current_player = computer
    movesprint = '1. Mild, 2. Hard, 3. Heal'

    while game_in_progress:
    if (current_player == computer):
    current_player = human
    else:
    current_player = computer
    print(
    "You have 0 health remaining and the "
    "computer has 1 health remaining."
    .format(human.health, computer.health))
    if (current_player == human):
    print(movesprint)
    move = get_selection()
    else:
    move = get_computer_selection(computer.health)

    if (move == 1):
    damage = random.randrange(12, 22)
    if (current_player == human):
    computer.calculate_damage(damage, human.name, computer.name)
    else:
    human.calculate_damage(damage, computer.name, human.name)
    elif (move == 2):
    damage = random.randrange(5, 35)
    if (current_player == human):
    computer.calculate_damage(damage, human.name, computer.name)
    else:
    human.calculate_damage(damage, computer.name, human.name)
    elif (move == 3):
    heal = random.randrange(15, 28)
    current_player.calculate_heal(heal)
    else:
    print ("The input was not valid. Please select a choice again.")

    if (human.health == 0):
    print("Sorry, you lose!")
    computer.wins += 1
    load_names = human.name
    paths = 'accounts/0.json'.format(load_names)
    with open(paths, 'r') as f:
    data = json.load(f)
    data["losses"] += 1
    with open(paths, 'w+') as g:
    json.dump(data, g)
    game_in_progress = False

    if (computer.health == 0):
    print("Congratulations, you beat the computer!")
    human.wins += 1
    load_names = human.name
    paths = 'accounts/0.json'.format(load_names)
    with open(paths, 'r') as f:
    data = json.load(f)
    data["exp"] += 25
    data["gold"] += 100
    data["wins"] += 1
    with open(paths, 'w+') as g:
    json.dump(data, g)
    game_in_progress = False

    def play_round_multiplayer(player2, player1):
    game_in_progress = True
    current_player = player2
    movesprint = '1. Mild, 2. Hard, 3. Heal'

    while game_in_progress:
    if (current_player == player2):
    current_player = player1
    else:
    current_player = player2
    #print()
    print(
    "You have 0 health remaining and the "
    "player2 has 1 health remaining."
    .format(player1.health, player2.health))
    #print()
    if (current_player == player1):
    print(movesprint)
    move = get_selection()
    else:
    print(movesprint)
    move = get_selection()

    if (move == 1):
    damage = random.randrange(12, 22)
    if (current_player == player1):
    player2.calculate_damage(damage, player1.name, player2.name)
    else:
    player1.calculate_damage(damage, player2.name, player1.name)
    elif (move == 2):
    damage = random.randrange(5, 35)
    if (current_player == player1):
    player2.calculate_damage(damage, player1.name, player2.name)
    else:
    player1.calculate_damage(damage, player2.name, player1.name)
    elif (move == 3):
    heal = random.randrange(15, 28)
    current_player.calculate_heal(heal)
    else:
    print ("The input was not valid. Please select a choice again.")

    if (player1.health == 0):
    print("0 wins".format(player2.name))
    player2.wins += 1
    winner_name = player2.name
    loser_name = player1.name
    winner_path = 'accounts/0.json'.format(winner_name)
    loser_path = 'accounts/0.json'.format(loser_name)
    with open(winner_path, 'r') as f:
    data = json.load(f)
    data["exp"] += 25
    data["gold"] += 100
    data["wins"] += 1
    with open(winner_path, 'w+') as g:
    json.dump(data, g)
    with open(loser_path, 'r') as f:
    data = json.load(f)
    data["losses"] += 1
    with open(loser_path, 'w+') as g:
    json.dump(data, g)
    game_in_progress = False

    if (player2.health == 0):
    print("0 wins".format(player1.name))
    player1.wins += 1
    winner_name = player1.name
    loser_name = player2.name
    winner_path = 'accounts/0.json'.format(winner_name)
    loser_path = 'accounts/0.json'.format(loser_name)
    with open(winner_path, 'r') as f:
    data = json.load(f)
    data["exp"] += 25
    data["gold"] += 100
    data["wins"] += 1
    with open(winner_path, 'w+') as g:
    json.dump(data, g)
    with open(loser_path, 'r') as f:
    data = json.load(f)
    data["losses"] += 1
    with open(loser_path, 'w+') as g:
    json.dump(data, g)
    game_in_progress = False

    def start_game_ai(name): #Play vs Ai, which you select your difficulty.
    target = raw_input("Easy, med or hard?")
    if target == "easy":
    computer = Character("Computer_Easy") #Make sure you have made all of these accounts in folder Accounts
    if target == "med": #Set stats however you like
    computer = Character("Computer_Med")
    if target == "hard":
    computer = Character("Computer_Hard")
    human = Character(name)

    keep_playing = True

    while (keep_playing is True):
    print("Current Score:")
    print("You - 0".format(human.wins))
    print("Computer - 0".format(computer.wins))

    computer.health = 100
    human.health = 100

    play_round_ai(computer, human)
    print()
    response = raw_input("Play another round?(Y/N)")
    if (response.lower() == "n"):
    break

    def start_game_multiplayer(name, target): #Play a local 1v1 game.
    player2 = Character(target)
    player1 = Character(name)

    keep_playing = True

    while (keep_playing is True):
    print("Current Score:")
    print("Player1 - 0".format(player1.wins))
    print("Player2 - 0".format(player2.wins))
    player2.health = 100
    player1.health = 100
    play_round_multiplayer(player2, player1)
    #print()
    response = raw_input("Play another 1v1? (y/n)")
    if (response == "y"):
    continue
    else:
    break

    def options(): #Main menu
    name = raw_input("Username to load or create?")
    print("What do you want to do? If this is your first time, type 5 to create your new account!")
    move = raw_input("1. Battle AI | 2. List stats | 3. Play 1v1 | 4. Upgrade str/def | 5. Make new user")
    if move == "1":
    print("Make sure you already have made all Computer accounts! (Computer_Easy, Computer_Med, Computer_Hard)")
    start_game_ai(name)
    if move == "2":
    stats = Character(name).load_account(name)
    print stats
    return
    if move == "3":
    target = raw_input("Who do you want to fight?")
    start_game_multiplayer(name, target)
    if move == "4":
    Character(name).upgrade_stat(name)
    stats = Character(name).load_account(name)
    print stats
    if move == "5":
    Character(name).make_account(name)
    else:
    print("Exiting..")
    return

    options()






    share|improve this question























      up vote
      5
      down vote

      favorite









      up vote
      5
      down vote

      favorite











      I have recently started to learn python, and I have made my first fighting duel game. I'm planning on adding more stuff in the future like shops and items so you get a way to spend gold, but for now the current features are:




      • Character creation (with saving and loading),


      • Upgrading Str/Def,

      • Keeping Score


      • Battling AI or Battling 1v1.

      • (you also get rewards for winning)

      But for now I'm happy with my progress. Please review my code!



      import random
      import json
      import time
      r = random
      #INSTRUCTIONS FOR FIRST TIME USE
      #MAKE 3 COMPUTER ACCOUNTS NAMED "Computer_Easy", "Computer_Med" and "Computer_Hard" AND SET THEIR STATS HOWEVER YOU LIKE! OTHERWISE UNABLE TO PLAY VS AI
      class Character():
      #Change value of default if you want people to start with higher str/def when they make their account.
      def __init__(self, name, default=1, health=None, strength=None,
      defence=None, gold=0, exp=0, wins=0, losses=0,
      ):
      self.name = name
      self.health = 100
      self.strength = default if strength is None else strength
      self.defence = default if defence is None else defence
      self.gold = 0
      self.exp = 0
      self.wins = 0
      self.losses = 0

      def make_account(self, name): #Create a new user to /accounts folder with default stats as listed above
      save_name = name
      path = 'accounts/0.json'.format(save_name)
      data =
      "health": self.health,
      "strength": self.strength,
      "defence": self.defence,
      "gold": self.gold,
      "exp": self.exp,
      "wins": self.wins,
      "losses": self.losses,

      with open(path, 'w+') as f:
      json.dump(data, f)

      def load_account(self, name):
      load_name = name
      path_two = 'accounts/0.json'.format(load_name)
      with open(path_two, 'r') as f:
      data = json.load(f)
      return data

      def upgrade_stat(self, name): #Upgrade either defence or strength
      target = raw_input("What stat do you want to upgrade?")
      if target in "health", "gold", "exp", "wins", "losses":
      print("you cannot do that!")
      return
      load_name = name
      path_two = 'accounts/0.json'.format(load_name)
      with open(path_two, 'r') as f:
      data = json.load(f)
      if data["exp"] < 100:
      print("You don't have enough xp!")
      else:
      data["exp"] -= 100
      data[target] += 1
      with open (path_two, 'w+') as g:
      json.dump(data, g)


      def calculate_damage(self, damage_amount, attacker, defender):
      attacker_stats = self.load_account(name=attacker)
      defender_stats = self.load_account(name=defender)

      #You get damage boost, depending on attacker strength level and defender defence level.
      damage_amount_boost = (attacker_stats["strength"] * damage_amount / (attacker_stats["strength"] + defender_stats["defence"])) + damage_amount
      if (damage_amount_boost > self.health):
      overkill = abs(self.health - damage_amount_boost)
      self.health = 0
      if (overkill > 0):
      print("0 takes fatal damage from 1, with 2 overkill!"
      .format(self.name.capitalize(), attacker, overkill))
      else:
      print("0 takes fatal damage from 1!"
      .format(self.name.capitalize(), attacker))
      else:
      self.health -= damage_amount_boost
      print("0 takes 1 damage from 2!"
      .format(self.name.capitalize(), damage_amount_boost, attacker))

      def calculate_heal(self, heal_amount):
      if (heal_amount + self.health > 100):
      self.health = 100
      print("0 heals back to full health!"
      .format(self.name.capitalize()))
      else:
      self.health += heal_amount
      print("0 heals for 1!"
      .format(self.name.capitalize(), heal_amount))

      def parse_int(input):
      try:
      int(input)
      return True
      except ValueError:
      return False

      def get_selection():
      valid_input = False
      while (valid_input is False):
      print()
      choice = input("Select an attack: ")
      if (parse_int(choice) is True):
      return int(choice)
      else:
      print("The input was invalid. Please try again.")

      def get_computer_selection(health):
      sleep_time = random.randrange(2, 5)
      print("Computer thinking...")
      time.sleep(sleep_time)

      if (health <= 35):
      # Have the computer heal ~50% of its turns when <= 35
      result = random.randint(1, 6)
      if (result % 2 == 0):
      return 3
      else:
      return random.randint(1, 2)
      elif (health == 100):
      return random.randint(1, 2)
      else:
      return random.randint(1, 3)

      def play_round_ai(computer, human):
      game_in_progress = True
      current_player = computer
      movesprint = '1. Mild, 2. Hard, 3. Heal'

      while game_in_progress:
      if (current_player == computer):
      current_player = human
      else:
      current_player = computer
      print(
      "You have 0 health remaining and the "
      "computer has 1 health remaining."
      .format(human.health, computer.health))
      if (current_player == human):
      print(movesprint)
      move = get_selection()
      else:
      move = get_computer_selection(computer.health)

      if (move == 1):
      damage = random.randrange(12, 22)
      if (current_player == human):
      computer.calculate_damage(damage, human.name, computer.name)
      else:
      human.calculate_damage(damage, computer.name, human.name)
      elif (move == 2):
      damage = random.randrange(5, 35)
      if (current_player == human):
      computer.calculate_damage(damage, human.name, computer.name)
      else:
      human.calculate_damage(damage, computer.name, human.name)
      elif (move == 3):
      heal = random.randrange(15, 28)
      current_player.calculate_heal(heal)
      else:
      print ("The input was not valid. Please select a choice again.")

      if (human.health == 0):
      print("Sorry, you lose!")
      computer.wins += 1
      load_names = human.name
      paths = 'accounts/0.json'.format(load_names)
      with open(paths, 'r') as f:
      data = json.load(f)
      data["losses"] += 1
      with open(paths, 'w+') as g:
      json.dump(data, g)
      game_in_progress = False

      if (computer.health == 0):
      print("Congratulations, you beat the computer!")
      human.wins += 1
      load_names = human.name
      paths = 'accounts/0.json'.format(load_names)
      with open(paths, 'r') as f:
      data = json.load(f)
      data["exp"] += 25
      data["gold"] += 100
      data["wins"] += 1
      with open(paths, 'w+') as g:
      json.dump(data, g)
      game_in_progress = False

      def play_round_multiplayer(player2, player1):
      game_in_progress = True
      current_player = player2
      movesprint = '1. Mild, 2. Hard, 3. Heal'

      while game_in_progress:
      if (current_player == player2):
      current_player = player1
      else:
      current_player = player2
      #print()
      print(
      "You have 0 health remaining and the "
      "player2 has 1 health remaining."
      .format(player1.health, player2.health))
      #print()
      if (current_player == player1):
      print(movesprint)
      move = get_selection()
      else:
      print(movesprint)
      move = get_selection()

      if (move == 1):
      damage = random.randrange(12, 22)
      if (current_player == player1):
      player2.calculate_damage(damage, player1.name, player2.name)
      else:
      player1.calculate_damage(damage, player2.name, player1.name)
      elif (move == 2):
      damage = random.randrange(5, 35)
      if (current_player == player1):
      player2.calculate_damage(damage, player1.name, player2.name)
      else:
      player1.calculate_damage(damage, player2.name, player1.name)
      elif (move == 3):
      heal = random.randrange(15, 28)
      current_player.calculate_heal(heal)
      else:
      print ("The input was not valid. Please select a choice again.")

      if (player1.health == 0):
      print("0 wins".format(player2.name))
      player2.wins += 1
      winner_name = player2.name
      loser_name = player1.name
      winner_path = 'accounts/0.json'.format(winner_name)
      loser_path = 'accounts/0.json'.format(loser_name)
      with open(winner_path, 'r') as f:
      data = json.load(f)
      data["exp"] += 25
      data["gold"] += 100
      data["wins"] += 1
      with open(winner_path, 'w+') as g:
      json.dump(data, g)
      with open(loser_path, 'r') as f:
      data = json.load(f)
      data["losses"] += 1
      with open(loser_path, 'w+') as g:
      json.dump(data, g)
      game_in_progress = False

      if (player2.health == 0):
      print("0 wins".format(player1.name))
      player1.wins += 1
      winner_name = player1.name
      loser_name = player2.name
      winner_path = 'accounts/0.json'.format(winner_name)
      loser_path = 'accounts/0.json'.format(loser_name)
      with open(winner_path, 'r') as f:
      data = json.load(f)
      data["exp"] += 25
      data["gold"] += 100
      data["wins"] += 1
      with open(winner_path, 'w+') as g:
      json.dump(data, g)
      with open(loser_path, 'r') as f:
      data = json.load(f)
      data["losses"] += 1
      with open(loser_path, 'w+') as g:
      json.dump(data, g)
      game_in_progress = False

      def start_game_ai(name): #Play vs Ai, which you select your difficulty.
      target = raw_input("Easy, med or hard?")
      if target == "easy":
      computer = Character("Computer_Easy") #Make sure you have made all of these accounts in folder Accounts
      if target == "med": #Set stats however you like
      computer = Character("Computer_Med")
      if target == "hard":
      computer = Character("Computer_Hard")
      human = Character(name)

      keep_playing = True

      while (keep_playing is True):
      print("Current Score:")
      print("You - 0".format(human.wins))
      print("Computer - 0".format(computer.wins))

      computer.health = 100
      human.health = 100

      play_round_ai(computer, human)
      print()
      response = raw_input("Play another round?(Y/N)")
      if (response.lower() == "n"):
      break

      def start_game_multiplayer(name, target): #Play a local 1v1 game.
      player2 = Character(target)
      player1 = Character(name)

      keep_playing = True

      while (keep_playing is True):
      print("Current Score:")
      print("Player1 - 0".format(player1.wins))
      print("Player2 - 0".format(player2.wins))
      player2.health = 100
      player1.health = 100
      play_round_multiplayer(player2, player1)
      #print()
      response = raw_input("Play another 1v1? (y/n)")
      if (response == "y"):
      continue
      else:
      break

      def options(): #Main menu
      name = raw_input("Username to load or create?")
      print("What do you want to do? If this is your first time, type 5 to create your new account!")
      move = raw_input("1. Battle AI | 2. List stats | 3. Play 1v1 | 4. Upgrade str/def | 5. Make new user")
      if move == "1":
      print("Make sure you already have made all Computer accounts! (Computer_Easy, Computer_Med, Computer_Hard)")
      start_game_ai(name)
      if move == "2":
      stats = Character(name).load_account(name)
      print stats
      return
      if move == "3":
      target = raw_input("Who do you want to fight?")
      start_game_multiplayer(name, target)
      if move == "4":
      Character(name).upgrade_stat(name)
      stats = Character(name).load_account(name)
      print stats
      if move == "5":
      Character(name).make_account(name)
      else:
      print("Exiting..")
      return

      options()






      share|improve this question













      I have recently started to learn python, and I have made my first fighting duel game. I'm planning on adding more stuff in the future like shops and items so you get a way to spend gold, but for now the current features are:




      • Character creation (with saving and loading),


      • Upgrading Str/Def,

      • Keeping Score


      • Battling AI or Battling 1v1.

      • (you also get rewards for winning)

      But for now I'm happy with my progress. Please review my code!



      import random
      import json
      import time
      r = random
      #INSTRUCTIONS FOR FIRST TIME USE
      #MAKE 3 COMPUTER ACCOUNTS NAMED "Computer_Easy", "Computer_Med" and "Computer_Hard" AND SET THEIR STATS HOWEVER YOU LIKE! OTHERWISE UNABLE TO PLAY VS AI
      class Character():
      #Change value of default if you want people to start with higher str/def when they make their account.
      def __init__(self, name, default=1, health=None, strength=None,
      defence=None, gold=0, exp=0, wins=0, losses=0,
      ):
      self.name = name
      self.health = 100
      self.strength = default if strength is None else strength
      self.defence = default if defence is None else defence
      self.gold = 0
      self.exp = 0
      self.wins = 0
      self.losses = 0

      def make_account(self, name): #Create a new user to /accounts folder with default stats as listed above
      save_name = name
      path = 'accounts/0.json'.format(save_name)
      data =
      "health": self.health,
      "strength": self.strength,
      "defence": self.defence,
      "gold": self.gold,
      "exp": self.exp,
      "wins": self.wins,
      "losses": self.losses,

      with open(path, 'w+') as f:
      json.dump(data, f)

      def load_account(self, name):
      load_name = name
      path_two = 'accounts/0.json'.format(load_name)
      with open(path_two, 'r') as f:
      data = json.load(f)
      return data

      def upgrade_stat(self, name): #Upgrade either defence or strength
      target = raw_input("What stat do you want to upgrade?")
      if target in "health", "gold", "exp", "wins", "losses":
      print("you cannot do that!")
      return
      load_name = name
      path_two = 'accounts/0.json'.format(load_name)
      with open(path_two, 'r') as f:
      data = json.load(f)
      if data["exp"] < 100:
      print("You don't have enough xp!")
      else:
      data["exp"] -= 100
      data[target] += 1
      with open (path_two, 'w+') as g:
      json.dump(data, g)


      def calculate_damage(self, damage_amount, attacker, defender):
      attacker_stats = self.load_account(name=attacker)
      defender_stats = self.load_account(name=defender)

      #You get damage boost, depending on attacker strength level and defender defence level.
      damage_amount_boost = (attacker_stats["strength"] * damage_amount / (attacker_stats["strength"] + defender_stats["defence"])) + damage_amount
      if (damage_amount_boost > self.health):
      overkill = abs(self.health - damage_amount_boost)
      self.health = 0
      if (overkill > 0):
      print("0 takes fatal damage from 1, with 2 overkill!"
      .format(self.name.capitalize(), attacker, overkill))
      else:
      print("0 takes fatal damage from 1!"
      .format(self.name.capitalize(), attacker))
      else:
      self.health -= damage_amount_boost
      print("0 takes 1 damage from 2!"
      .format(self.name.capitalize(), damage_amount_boost, attacker))

      def calculate_heal(self, heal_amount):
      if (heal_amount + self.health > 100):
      self.health = 100
      print("0 heals back to full health!"
      .format(self.name.capitalize()))
      else:
      self.health += heal_amount
      print("0 heals for 1!"
      .format(self.name.capitalize(), heal_amount))

      def parse_int(input):
      try:
      int(input)
      return True
      except ValueError:
      return False

      def get_selection():
      valid_input = False
      while (valid_input is False):
      print()
      choice = input("Select an attack: ")
      if (parse_int(choice) is True):
      return int(choice)
      else:
      print("The input was invalid. Please try again.")

      def get_computer_selection(health):
      sleep_time = random.randrange(2, 5)
      print("Computer thinking...")
      time.sleep(sleep_time)

      if (health <= 35):
      # Have the computer heal ~50% of its turns when <= 35
      result = random.randint(1, 6)
      if (result % 2 == 0):
      return 3
      else:
      return random.randint(1, 2)
      elif (health == 100):
      return random.randint(1, 2)
      else:
      return random.randint(1, 3)

      def play_round_ai(computer, human):
      game_in_progress = True
      current_player = computer
      movesprint = '1. Mild, 2. Hard, 3. Heal'

      while game_in_progress:
      if (current_player == computer):
      current_player = human
      else:
      current_player = computer
      print(
      "You have 0 health remaining and the "
      "computer has 1 health remaining."
      .format(human.health, computer.health))
      if (current_player == human):
      print(movesprint)
      move = get_selection()
      else:
      move = get_computer_selection(computer.health)

      if (move == 1):
      damage = random.randrange(12, 22)
      if (current_player == human):
      computer.calculate_damage(damage, human.name, computer.name)
      else:
      human.calculate_damage(damage, computer.name, human.name)
      elif (move == 2):
      damage = random.randrange(5, 35)
      if (current_player == human):
      computer.calculate_damage(damage, human.name, computer.name)
      else:
      human.calculate_damage(damage, computer.name, human.name)
      elif (move == 3):
      heal = random.randrange(15, 28)
      current_player.calculate_heal(heal)
      else:
      print ("The input was not valid. Please select a choice again.")

      if (human.health == 0):
      print("Sorry, you lose!")
      computer.wins += 1
      load_names = human.name
      paths = 'accounts/0.json'.format(load_names)
      with open(paths, 'r') as f:
      data = json.load(f)
      data["losses"] += 1
      with open(paths, 'w+') as g:
      json.dump(data, g)
      game_in_progress = False

      if (computer.health == 0):
      print("Congratulations, you beat the computer!")
      human.wins += 1
      load_names = human.name
      paths = 'accounts/0.json'.format(load_names)
      with open(paths, 'r') as f:
      data = json.load(f)
      data["exp"] += 25
      data["gold"] += 100
      data["wins"] += 1
      with open(paths, 'w+') as g:
      json.dump(data, g)
      game_in_progress = False

      def play_round_multiplayer(player2, player1):
      game_in_progress = True
      current_player = player2
      movesprint = '1. Mild, 2. Hard, 3. Heal'

      while game_in_progress:
      if (current_player == player2):
      current_player = player1
      else:
      current_player = player2
      #print()
      print(
      "You have 0 health remaining and the "
      "player2 has 1 health remaining."
      .format(player1.health, player2.health))
      #print()
      if (current_player == player1):
      print(movesprint)
      move = get_selection()
      else:
      print(movesprint)
      move = get_selection()

      if (move == 1):
      damage = random.randrange(12, 22)
      if (current_player == player1):
      player2.calculate_damage(damage, player1.name, player2.name)
      else:
      player1.calculate_damage(damage, player2.name, player1.name)
      elif (move == 2):
      damage = random.randrange(5, 35)
      if (current_player == player1):
      player2.calculate_damage(damage, player1.name, player2.name)
      else:
      player1.calculate_damage(damage, player2.name, player1.name)
      elif (move == 3):
      heal = random.randrange(15, 28)
      current_player.calculate_heal(heal)
      else:
      print ("The input was not valid. Please select a choice again.")

      if (player1.health == 0):
      print("0 wins".format(player2.name))
      player2.wins += 1
      winner_name = player2.name
      loser_name = player1.name
      winner_path = 'accounts/0.json'.format(winner_name)
      loser_path = 'accounts/0.json'.format(loser_name)
      with open(winner_path, 'r') as f:
      data = json.load(f)
      data["exp"] += 25
      data["gold"] += 100
      data["wins"] += 1
      with open(winner_path, 'w+') as g:
      json.dump(data, g)
      with open(loser_path, 'r') as f:
      data = json.load(f)
      data["losses"] += 1
      with open(loser_path, 'w+') as g:
      json.dump(data, g)
      game_in_progress = False

      if (player2.health == 0):
      print("0 wins".format(player1.name))
      player1.wins += 1
      winner_name = player1.name
      loser_name = player2.name
      winner_path = 'accounts/0.json'.format(winner_name)
      loser_path = 'accounts/0.json'.format(loser_name)
      with open(winner_path, 'r') as f:
      data = json.load(f)
      data["exp"] += 25
      data["gold"] += 100
      data["wins"] += 1
      with open(winner_path, 'w+') as g:
      json.dump(data, g)
      with open(loser_path, 'r') as f:
      data = json.load(f)
      data["losses"] += 1
      with open(loser_path, 'w+') as g:
      json.dump(data, g)
      game_in_progress = False

      def start_game_ai(name): #Play vs Ai, which you select your difficulty.
      target = raw_input("Easy, med or hard?")
      if target == "easy":
      computer = Character("Computer_Easy") #Make sure you have made all of these accounts in folder Accounts
      if target == "med": #Set stats however you like
      computer = Character("Computer_Med")
      if target == "hard":
      computer = Character("Computer_Hard")
      human = Character(name)

      keep_playing = True

      while (keep_playing is True):
      print("Current Score:")
      print("You - 0".format(human.wins))
      print("Computer - 0".format(computer.wins))

      computer.health = 100
      human.health = 100

      play_round_ai(computer, human)
      print()
      response = raw_input("Play another round?(Y/N)")
      if (response.lower() == "n"):
      break

      def start_game_multiplayer(name, target): #Play a local 1v1 game.
      player2 = Character(target)
      player1 = Character(name)

      keep_playing = True

      while (keep_playing is True):
      print("Current Score:")
      print("Player1 - 0".format(player1.wins))
      print("Player2 - 0".format(player2.wins))
      player2.health = 100
      player1.health = 100
      play_round_multiplayer(player2, player1)
      #print()
      response = raw_input("Play another 1v1? (y/n)")
      if (response == "y"):
      continue
      else:
      break

      def options(): #Main menu
      name = raw_input("Username to load or create?")
      print("What do you want to do? If this is your first time, type 5 to create your new account!")
      move = raw_input("1. Battle AI | 2. List stats | 3. Play 1v1 | 4. Upgrade str/def | 5. Make new user")
      if move == "1":
      print("Make sure you already have made all Computer accounts! (Computer_Easy, Computer_Med, Computer_Hard)")
      start_game_ai(name)
      if move == "2":
      stats = Character(name).load_account(name)
      print stats
      return
      if move == "3":
      target = raw_input("Who do you want to fight?")
      start_game_multiplayer(name, target)
      if move == "4":
      Character(name).upgrade_stat(name)
      stats = Character(name).load_account(name)
      print stats
      if move == "5":
      Character(name).make_account(name)
      else:
      print("Exiting..")
      return

      options()








      share|improve this question












      share|improve this question




      share|improve this question








      edited Jul 11 at 17:44









      200_success

      123k14143399




      123k14143399









      asked Jul 11 at 14:56









      VissyHunter

      263




      263




















          3 Answers
          3






          active

          oldest

          votes

















          up vote
          5
          down vote













          Currently your code is a bit all over the place. You have a Character class that can keep track of how much e.g. exp a character has. But when it comes to adding exp, you instead use a data dictionary.



          Also, instead of saving the Character to file, you save that dictionary instead. The only thing where you actually use that class is to get the characters name.



          So you have two options:



          1. Get rid of the class and always use the data dictionary.

          2. Make all of those things something the class handles.

          I would choose option 2 here.



          Here is a start on that road:



          import random
          import json
          import time
          r = random
          # INSTRUCTIONS FOR FIRST TIME USE
          # MAKE 3 COMPUTER ACCOUNTS NAMED "Computer_Easy", "Computer_Med" and
          # "Computer_Hard" AND SET THEIR STATS HOWEVER YOU LIKE! OTHERWISE UNABLE
          # TO PLAY VS AI


          class CharacterDoesNotExist(Exception):
          pass


          class Character(object):
          # Change value of default if you want people to start with higher str/def
          # when they make their account.
          path = 'accounts/.json'
          mild_attack = 12, 22
          hard_attack = 5, 35
          heal_amount = 15, 28
          default = 1

          def __init__(self, name, health=None, strength=None,
          defence=None, gold=0, exp=0, wins=0, losses=0):
          self.name = name
          self.health = 100 if health is None else health
          self.strength = self.default if strength is None else strength
          self.defence = self.default if defence is None else defence
          self.gold = 0 if gold is None else gold
          self.exp = 0 if exp is None else exp
          self.wins = 0 if wins is None else wins
          self.losses = 0 if losses is None else wins

          @classmethod
          def load(cls, name):
          path = cls.path.format(name)
          try:
          with open(path) as f:
          return cls(**json.load(f))
          except Exception:
          raise CharacterDoesNotExist(name)

          def save(self):
          path = self.path.format(self.name)
          with open(path, 'w+') as f:
          json.dump(self.__dict__, f)

          def __str__(self):
          return self.name.capitalize()

          def upgrade_stat(self): # Upgrade either defence or strength
          if self.exp < 100:
          print("You don't have enough exp!")
          return
          target = raw_input("What stat do you want to upgrade?")
          if target not in ("strength", "defence"):
          print("You cannot do that!")
          else:
          self.exp -= 100
          setattr(self, target, getattr(self, target) + 1)
          self.save()

          def attack(self, defender, damage_amount):
          # You get damage boost, depending on attacker strength level and
          # defender defence level.
          damage_amount_boost = (self.strength * damage_amount /
          (self.strength + defender.defence)) + damage_amount
          if damage_amount_boost > defender.health:
          overkill = abs(self.health - damage_amount_boost)
          defender.health = 0
          if overkill > 0:
          print(" takes fatal damage from , with overkill!".format(
          defender, self, overkill))
          else:
          print(" takes fatal damage from !".format(defender, self))
          else:
          defender.health -= damage_amount_boost
          print(" takes damage from !".format(
          defender, damage_amount_boost, self))

          def heal(self, heal_amount):
          if (heal_amount + self.health > 100):
          self.health = 100
          print(" heals back to full health!".format(self))
          else:
          self.health += heal_amount
          print(" heals for !".format(self, heal_amount))

          def get_selection(self):
          print 'Avalaible moves: 1. Mild Attack, 2. Hard Attack, 3. Heal'
          while True:
          try:
          choice = int(input("Select a move: "))
          if not 1 <= choice <= 3:
          continue
          return choice
          except ValueError:
          print("The input was invalid. Please try again.")

          def make_move(self, player2):
          choice = self.get_selection()
          if choice == 1:
          # mild attack
          damage = random.randint(*self.mild_attack)
          self.attack(player2, damage)
          elif choice == 2:
          # mild attack
          damage = random.randint(*self.hard_attack)
          self.attack(player2, damage)
          elif choice == 3:
          # mild attack
          heal = random.randint(*self.heal_amount)
          self.heal(heal)

          def win(self):
          self.wins += 1
          self.exp += 25
          self.gold += 100
          self.save()

          def loose(self):
          self.losses += 1
          self.save()


          class Computer(Character):

          def get_selection(self):
          print("Computer thinking...")
          time.sleep(random.randrange(2, 5))

          if self.health <= 35:
          # Have the computer heal ~50% of its turns when <= 35
          if random.random() >= 0.5:
          return 3
          return random.randint(1, 2)
          elif self.health == 100:
          return random.randint(1, 2)
          return random.randint(1, 3)

          def win(self):
          self.wins += 1

          def loose(self):
          self.losses += 1


          def play_round(player1, player2):
          player1.health = player2.health = 100
          while True:
          print("n has health remaining and has health remaining.".format(
          player1, player1.health, player2, player2.health))
          for _ in range(2):
          player1.make_move(player2)
          if player2.health <= 0:
          print(" looses!".format(player2))
          player1.win()
          player2.loose()
          return
          # swap the players
          player1, player2 = player2, player1


          # Play vs Ai, which you select your difficulty.
          def play_vs_ai(human, computer):
          while True:
          print "Current Score:"
          print "You - ".format(human.wins)
          print "Computer - ".format(computer.wins)
          play_round(computer, human)
          print
          if raw_input("Play another round?(Y/N)").lower() == "n":
          break


          def play_1_vs_1(player1, player2): # Play a local 1v1 game.
          while True:
          print "Current Score:"
          print "Player1 - ".format(player1.wins)
          print "Player2 - ".format(player2.wins)
          play_round(player1, player1)
          print
          if raw_input("Play another 1v1? (y/n)").lower() != "y":
          break


          def main_menu(): # Main menu
          name = raw_input("Username to load or create?")
          try:
          player1 = Character.load(name)
          except CharacterDoesNotExist:
          player1 = Character(name)
          player1.save()
          while True:
          print("What do you want to do?")
          move = raw_input(
          "1. Battle AI | 2. List stats | 3. Play 1v1 | 4. Upgrade str/def")
          if move == "1":
          target = raw_input("Easy, med or hard?")
          if target.lower() == "easy":
          computer = Computer("Computer_Easy")
          elif target.lower() == "med": # Set stats however you like
          computer = Computer("Computer_Med", strength=2, defence=3)
          elif target.lower() == "hard":
          computer = Computer("Computer_Hard", strength=5, defence=4)
          play_vs_ai(player1, computer)
          elif move == "2":
          print player1.__dict__
          elif move == "3":
          target = raw_input("Who do you want to fight?")
          try:
          player2 = Character.load(target)
          except CharacterDoesNotExist:
          player2 = Character(target)
          player2.save()
          play_1_vs_1(player1, player2)
          elif move == "4":
          while True:
          player = raw_input("Which player: or ")
          if player == player1.name:
          player1.upgrade_stat()
          break
          # elif player == player2.name:
          # player2.upgrade_stat()
          # break
          else:
          print("Exiting..")
          return
          if __name__ == "__main__":
          main_menu()


          Some notable changes:



          • The Character class inherits from object, making it a new-style class.

          • This uses a Computer class that inherits from Character and overrides some methods to allow the computer to make its decisions and prevent it from saving its wins and losses.

          • It has a classmethod load that loads a character from a file and a save method to save it.

          • The __str__ magic method makes sure that when we print a character that we see their name

          • Instead of disallowing some stats (like wins) to be upgraded, explicitly allow only strength and defence to be upgraded (whitelist vs blacklist).

          • A Character can attack and heal. By how much is encoded as a class variable.

          • Some of the attributes can be reached like for a dict, to ease the upgrading of a stat.

          • There is a make_move function that performs a characters move, given a choice of moves.

          • The play_round function is generic enough that it does not care if both players are humans or even both are computers.

          • The only thing that does not currently work is upgrading the stats of player 2, if they are human.

          • You don't need to specify the position in str.format strings, if you use them in the order you pass it in. In other words "0 1".format(1, 2) and " ".format(1, 2) are equivalent.

          • It uses a if __name__ == "__main__": guard to allow importing from this module.

          • A new character is automatically created if the loading fails.

          • The AI players have default values now. Whether or not they make sense, I don't know (I managed to consistently beat the easy AI...).

          • Consistently use print as a statement, as it was in Python 2.

          Some things which you should still change:



          • Make all those comments above your functions into docstrings.

          • Port this to Python 3, as Python 2 will be EOL soon.





          share|improve this answer



















          • 2




            Instead of printing a __dict__ prefer using vars. Also, if defining __getitem__ and __setitem__ is only useful for self[target] += 1 in upgrade_stat you shoul favor getattr and/or hasattr instead and handle a failure the same as a restricted attribute. Besides, you may want to check for the XP amount before asking what to upgrade.
            – Mathias Ettinger
            Jul 12 at 7:12










          • @MathiasEttinger: Agree, when I was writing it I thought I might need to set and get more attributes. Removed those methods entirely and replaced them with a call to setattr and getattr. Btw, I am checking that the user has enough exp.
            – Graipher
            Jul 12 at 8:57






          • 1




            But the check comes after asking the question ;)
            – Mathias Ettinger
            Jul 12 at 9:00

















          up vote
          4
          down vote














          1. parse_int() has no reason to be a function, as it doesn't simplify anything. get_selection() could look like this:



            def get_selection():
            valid_input = False
            while (valid_input is False):
            print()
            choice = input("Select an attack: ")
            try:
            return int(choice)
            except ValueError:
            print("The input was invalid. Please try again.")


          2. For comparing object identity (i.e. current_player == player2 or current_player == computer) use is. this checks if the objects are the same, rather than if they have the same values. In your case, because you did not override == they should currently act the same.


          3. You can abstract out a single human or computer turn as a function, so that the different combinations of human computer play are all the same code. This will also make it easier to do AI vs. AI duels.


          4. Try to separate the game code from the output code. What if you or someone else wanted to make a different user interface for your game? First try to remove printing from the Character class, then try to make a quiet turn function that handles dueling using arguments and return values.


          5. Instead of r = random you can do import random as r. In my opinion however, it is not a good idea to change the name of a module as it makes it harder for readers to figure out which module you are using.






          share|improve this answer






























            up vote
            2
            down vote













            Try to eliminate repetitions. For example, you have a lot of “generate filename, open, read/write” statements. Instead, create a separate class which could use along the lines of



            storage = FileStorage(name) # reads "accounts/name.json" into storage.data
            storage.data["something"] = whatever
            storage.save()


            Where else are you repeating yourself a lot? You have



            if (current_player == human):
            computer.calculate_damage(damage, human.name, computer.name)
            else:
            human.calculate_damage(damage, computer.name, human.name)


            But you can simplify this to



            active_player, non_active_player = human, computer

            ...

            active_player.calculate_damage(damage, active_player.name, non_active_player.name)

            ...

            # and when the turn ends:
            active_player, non_active_player = non_active_player, active_player


            And so on.



            Repetition is bad because whenever you want to make a change you have to do it in multiple places, and you risk failing to update all the places or updating some of them differently from others.






            share|improve this answer





















              Your Answer




              StackExchange.ifUsing("editor", function ()
              return StackExchange.using("mathjaxEditing", function ()
              StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
              StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
              );
              );
              , "mathjax-editing");

              StackExchange.ifUsing("editor", function ()
              StackExchange.using("externalEditor", function ()
              StackExchange.using("snippets", function ()
              StackExchange.snippets.init();
              );
              );
              , "code-snippets");

              StackExchange.ready(function()
              var channelOptions =
              tags: "".split(" "),
              id: "196"
              ;
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function()
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled)
              StackExchange.using("snippets", function()
              createEditor();
              );

              else
              createEditor();

              );

              function createEditor()
              StackExchange.prepareEditor(
              heartbeatType: 'answer',
              convertImagesToLinks: false,
              noModals: false,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: null,
              bindNavPrevention: true,
              postfix: "",
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              );



              );








               

              draft saved


              draft discarded


















              StackExchange.ready(
              function ()
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f198293%2ftext-turn-based-dueling-game%23new-answer', 'question_page');

              );

              Post as a guest






























              3 Answers
              3






              active

              oldest

              votes








              3 Answers
              3






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes








              up vote
              5
              down vote













              Currently your code is a bit all over the place. You have a Character class that can keep track of how much e.g. exp a character has. But when it comes to adding exp, you instead use a data dictionary.



              Also, instead of saving the Character to file, you save that dictionary instead. The only thing where you actually use that class is to get the characters name.



              So you have two options:



              1. Get rid of the class and always use the data dictionary.

              2. Make all of those things something the class handles.

              I would choose option 2 here.



              Here is a start on that road:



              import random
              import json
              import time
              r = random
              # INSTRUCTIONS FOR FIRST TIME USE
              # MAKE 3 COMPUTER ACCOUNTS NAMED "Computer_Easy", "Computer_Med" and
              # "Computer_Hard" AND SET THEIR STATS HOWEVER YOU LIKE! OTHERWISE UNABLE
              # TO PLAY VS AI


              class CharacterDoesNotExist(Exception):
              pass


              class Character(object):
              # Change value of default if you want people to start with higher str/def
              # when they make their account.
              path = 'accounts/.json'
              mild_attack = 12, 22
              hard_attack = 5, 35
              heal_amount = 15, 28
              default = 1

              def __init__(self, name, health=None, strength=None,
              defence=None, gold=0, exp=0, wins=0, losses=0):
              self.name = name
              self.health = 100 if health is None else health
              self.strength = self.default if strength is None else strength
              self.defence = self.default if defence is None else defence
              self.gold = 0 if gold is None else gold
              self.exp = 0 if exp is None else exp
              self.wins = 0 if wins is None else wins
              self.losses = 0 if losses is None else wins

              @classmethod
              def load(cls, name):
              path = cls.path.format(name)
              try:
              with open(path) as f:
              return cls(**json.load(f))
              except Exception:
              raise CharacterDoesNotExist(name)

              def save(self):
              path = self.path.format(self.name)
              with open(path, 'w+') as f:
              json.dump(self.__dict__, f)

              def __str__(self):
              return self.name.capitalize()

              def upgrade_stat(self): # Upgrade either defence or strength
              if self.exp < 100:
              print("You don't have enough exp!")
              return
              target = raw_input("What stat do you want to upgrade?")
              if target not in ("strength", "defence"):
              print("You cannot do that!")
              else:
              self.exp -= 100
              setattr(self, target, getattr(self, target) + 1)
              self.save()

              def attack(self, defender, damage_amount):
              # You get damage boost, depending on attacker strength level and
              # defender defence level.
              damage_amount_boost = (self.strength * damage_amount /
              (self.strength + defender.defence)) + damage_amount
              if damage_amount_boost > defender.health:
              overkill = abs(self.health - damage_amount_boost)
              defender.health = 0
              if overkill > 0:
              print(" takes fatal damage from , with overkill!".format(
              defender, self, overkill))
              else:
              print(" takes fatal damage from !".format(defender, self))
              else:
              defender.health -= damage_amount_boost
              print(" takes damage from !".format(
              defender, damage_amount_boost, self))

              def heal(self, heal_amount):
              if (heal_amount + self.health > 100):
              self.health = 100
              print(" heals back to full health!".format(self))
              else:
              self.health += heal_amount
              print(" heals for !".format(self, heal_amount))

              def get_selection(self):
              print 'Avalaible moves: 1. Mild Attack, 2. Hard Attack, 3. Heal'
              while True:
              try:
              choice = int(input("Select a move: "))
              if not 1 <= choice <= 3:
              continue
              return choice
              except ValueError:
              print("The input was invalid. Please try again.")

              def make_move(self, player2):
              choice = self.get_selection()
              if choice == 1:
              # mild attack
              damage = random.randint(*self.mild_attack)
              self.attack(player2, damage)
              elif choice == 2:
              # mild attack
              damage = random.randint(*self.hard_attack)
              self.attack(player2, damage)
              elif choice == 3:
              # mild attack
              heal = random.randint(*self.heal_amount)
              self.heal(heal)

              def win(self):
              self.wins += 1
              self.exp += 25
              self.gold += 100
              self.save()

              def loose(self):
              self.losses += 1
              self.save()


              class Computer(Character):

              def get_selection(self):
              print("Computer thinking...")
              time.sleep(random.randrange(2, 5))

              if self.health <= 35:
              # Have the computer heal ~50% of its turns when <= 35
              if random.random() >= 0.5:
              return 3
              return random.randint(1, 2)
              elif self.health == 100:
              return random.randint(1, 2)
              return random.randint(1, 3)

              def win(self):
              self.wins += 1

              def loose(self):
              self.losses += 1


              def play_round(player1, player2):
              player1.health = player2.health = 100
              while True:
              print("n has health remaining and has health remaining.".format(
              player1, player1.health, player2, player2.health))
              for _ in range(2):
              player1.make_move(player2)
              if player2.health <= 0:
              print(" looses!".format(player2))
              player1.win()
              player2.loose()
              return
              # swap the players
              player1, player2 = player2, player1


              # Play vs Ai, which you select your difficulty.
              def play_vs_ai(human, computer):
              while True:
              print "Current Score:"
              print "You - ".format(human.wins)
              print "Computer - ".format(computer.wins)
              play_round(computer, human)
              print
              if raw_input("Play another round?(Y/N)").lower() == "n":
              break


              def play_1_vs_1(player1, player2): # Play a local 1v1 game.
              while True:
              print "Current Score:"
              print "Player1 - ".format(player1.wins)
              print "Player2 - ".format(player2.wins)
              play_round(player1, player1)
              print
              if raw_input("Play another 1v1? (y/n)").lower() != "y":
              break


              def main_menu(): # Main menu
              name = raw_input("Username to load or create?")
              try:
              player1 = Character.load(name)
              except CharacterDoesNotExist:
              player1 = Character(name)
              player1.save()
              while True:
              print("What do you want to do?")
              move = raw_input(
              "1. Battle AI | 2. List stats | 3. Play 1v1 | 4. Upgrade str/def")
              if move == "1":
              target = raw_input("Easy, med or hard?")
              if target.lower() == "easy":
              computer = Computer("Computer_Easy")
              elif target.lower() == "med": # Set stats however you like
              computer = Computer("Computer_Med", strength=2, defence=3)
              elif target.lower() == "hard":
              computer = Computer("Computer_Hard", strength=5, defence=4)
              play_vs_ai(player1, computer)
              elif move == "2":
              print player1.__dict__
              elif move == "3":
              target = raw_input("Who do you want to fight?")
              try:
              player2 = Character.load(target)
              except CharacterDoesNotExist:
              player2 = Character(target)
              player2.save()
              play_1_vs_1(player1, player2)
              elif move == "4":
              while True:
              player = raw_input("Which player: or ")
              if player == player1.name:
              player1.upgrade_stat()
              break
              # elif player == player2.name:
              # player2.upgrade_stat()
              # break
              else:
              print("Exiting..")
              return
              if __name__ == "__main__":
              main_menu()


              Some notable changes:



              • The Character class inherits from object, making it a new-style class.

              • This uses a Computer class that inherits from Character and overrides some methods to allow the computer to make its decisions and prevent it from saving its wins and losses.

              • It has a classmethod load that loads a character from a file and a save method to save it.

              • The __str__ magic method makes sure that when we print a character that we see their name

              • Instead of disallowing some stats (like wins) to be upgraded, explicitly allow only strength and defence to be upgraded (whitelist vs blacklist).

              • A Character can attack and heal. By how much is encoded as a class variable.

              • Some of the attributes can be reached like for a dict, to ease the upgrading of a stat.

              • There is a make_move function that performs a characters move, given a choice of moves.

              • The play_round function is generic enough that it does not care if both players are humans or even both are computers.

              • The only thing that does not currently work is upgrading the stats of player 2, if they are human.

              • You don't need to specify the position in str.format strings, if you use them in the order you pass it in. In other words "0 1".format(1, 2) and " ".format(1, 2) are equivalent.

              • It uses a if __name__ == "__main__": guard to allow importing from this module.

              • A new character is automatically created if the loading fails.

              • The AI players have default values now. Whether or not they make sense, I don't know (I managed to consistently beat the easy AI...).

              • Consistently use print as a statement, as it was in Python 2.

              Some things which you should still change:



              • Make all those comments above your functions into docstrings.

              • Port this to Python 3, as Python 2 will be EOL soon.





              share|improve this answer



















              • 2




                Instead of printing a __dict__ prefer using vars. Also, if defining __getitem__ and __setitem__ is only useful for self[target] += 1 in upgrade_stat you shoul favor getattr and/or hasattr instead and handle a failure the same as a restricted attribute. Besides, you may want to check for the XP amount before asking what to upgrade.
                – Mathias Ettinger
                Jul 12 at 7:12










              • @MathiasEttinger: Agree, when I was writing it I thought I might need to set and get more attributes. Removed those methods entirely and replaced them with a call to setattr and getattr. Btw, I am checking that the user has enough exp.
                – Graipher
                Jul 12 at 8:57






              • 1




                But the check comes after asking the question ;)
                – Mathias Ettinger
                Jul 12 at 9:00














              up vote
              5
              down vote













              Currently your code is a bit all over the place. You have a Character class that can keep track of how much e.g. exp a character has. But when it comes to adding exp, you instead use a data dictionary.



              Also, instead of saving the Character to file, you save that dictionary instead. The only thing where you actually use that class is to get the characters name.



              So you have two options:



              1. Get rid of the class and always use the data dictionary.

              2. Make all of those things something the class handles.

              I would choose option 2 here.



              Here is a start on that road:



              import random
              import json
              import time
              r = random
              # INSTRUCTIONS FOR FIRST TIME USE
              # MAKE 3 COMPUTER ACCOUNTS NAMED "Computer_Easy", "Computer_Med" and
              # "Computer_Hard" AND SET THEIR STATS HOWEVER YOU LIKE! OTHERWISE UNABLE
              # TO PLAY VS AI


              class CharacterDoesNotExist(Exception):
              pass


              class Character(object):
              # Change value of default if you want people to start with higher str/def
              # when they make their account.
              path = 'accounts/.json'
              mild_attack = 12, 22
              hard_attack = 5, 35
              heal_amount = 15, 28
              default = 1

              def __init__(self, name, health=None, strength=None,
              defence=None, gold=0, exp=0, wins=0, losses=0):
              self.name = name
              self.health = 100 if health is None else health
              self.strength = self.default if strength is None else strength
              self.defence = self.default if defence is None else defence
              self.gold = 0 if gold is None else gold
              self.exp = 0 if exp is None else exp
              self.wins = 0 if wins is None else wins
              self.losses = 0 if losses is None else wins

              @classmethod
              def load(cls, name):
              path = cls.path.format(name)
              try:
              with open(path) as f:
              return cls(**json.load(f))
              except Exception:
              raise CharacterDoesNotExist(name)

              def save(self):
              path = self.path.format(self.name)
              with open(path, 'w+') as f:
              json.dump(self.__dict__, f)

              def __str__(self):
              return self.name.capitalize()

              def upgrade_stat(self): # Upgrade either defence or strength
              if self.exp < 100:
              print("You don't have enough exp!")
              return
              target = raw_input("What stat do you want to upgrade?")
              if target not in ("strength", "defence"):
              print("You cannot do that!")
              else:
              self.exp -= 100
              setattr(self, target, getattr(self, target) + 1)
              self.save()

              def attack(self, defender, damage_amount):
              # You get damage boost, depending on attacker strength level and
              # defender defence level.
              damage_amount_boost = (self.strength * damage_amount /
              (self.strength + defender.defence)) + damage_amount
              if damage_amount_boost > defender.health:
              overkill = abs(self.health - damage_amount_boost)
              defender.health = 0
              if overkill > 0:
              print(" takes fatal damage from , with overkill!".format(
              defender, self, overkill))
              else:
              print(" takes fatal damage from !".format(defender, self))
              else:
              defender.health -= damage_amount_boost
              print(" takes damage from !".format(
              defender, damage_amount_boost, self))

              def heal(self, heal_amount):
              if (heal_amount + self.health > 100):
              self.health = 100
              print(" heals back to full health!".format(self))
              else:
              self.health += heal_amount
              print(" heals for !".format(self, heal_amount))

              def get_selection(self):
              print 'Avalaible moves: 1. Mild Attack, 2. Hard Attack, 3. Heal'
              while True:
              try:
              choice = int(input("Select a move: "))
              if not 1 <= choice <= 3:
              continue
              return choice
              except ValueError:
              print("The input was invalid. Please try again.")

              def make_move(self, player2):
              choice = self.get_selection()
              if choice == 1:
              # mild attack
              damage = random.randint(*self.mild_attack)
              self.attack(player2, damage)
              elif choice == 2:
              # mild attack
              damage = random.randint(*self.hard_attack)
              self.attack(player2, damage)
              elif choice == 3:
              # mild attack
              heal = random.randint(*self.heal_amount)
              self.heal(heal)

              def win(self):
              self.wins += 1
              self.exp += 25
              self.gold += 100
              self.save()

              def loose(self):
              self.losses += 1
              self.save()


              class Computer(Character):

              def get_selection(self):
              print("Computer thinking...")
              time.sleep(random.randrange(2, 5))

              if self.health <= 35:
              # Have the computer heal ~50% of its turns when <= 35
              if random.random() >= 0.5:
              return 3
              return random.randint(1, 2)
              elif self.health == 100:
              return random.randint(1, 2)
              return random.randint(1, 3)

              def win(self):
              self.wins += 1

              def loose(self):
              self.losses += 1


              def play_round(player1, player2):
              player1.health = player2.health = 100
              while True:
              print("n has health remaining and has health remaining.".format(
              player1, player1.health, player2, player2.health))
              for _ in range(2):
              player1.make_move(player2)
              if player2.health <= 0:
              print(" looses!".format(player2))
              player1.win()
              player2.loose()
              return
              # swap the players
              player1, player2 = player2, player1


              # Play vs Ai, which you select your difficulty.
              def play_vs_ai(human, computer):
              while True:
              print "Current Score:"
              print "You - ".format(human.wins)
              print "Computer - ".format(computer.wins)
              play_round(computer, human)
              print
              if raw_input("Play another round?(Y/N)").lower() == "n":
              break


              def play_1_vs_1(player1, player2): # Play a local 1v1 game.
              while True:
              print "Current Score:"
              print "Player1 - ".format(player1.wins)
              print "Player2 - ".format(player2.wins)
              play_round(player1, player1)
              print
              if raw_input("Play another 1v1? (y/n)").lower() != "y":
              break


              def main_menu(): # Main menu
              name = raw_input("Username to load or create?")
              try:
              player1 = Character.load(name)
              except CharacterDoesNotExist:
              player1 = Character(name)
              player1.save()
              while True:
              print("What do you want to do?")
              move = raw_input(
              "1. Battle AI | 2. List stats | 3. Play 1v1 | 4. Upgrade str/def")
              if move == "1":
              target = raw_input("Easy, med or hard?")
              if target.lower() == "easy":
              computer = Computer("Computer_Easy")
              elif target.lower() == "med": # Set stats however you like
              computer = Computer("Computer_Med", strength=2, defence=3)
              elif target.lower() == "hard":
              computer = Computer("Computer_Hard", strength=5, defence=4)
              play_vs_ai(player1, computer)
              elif move == "2":
              print player1.__dict__
              elif move == "3":
              target = raw_input("Who do you want to fight?")
              try:
              player2 = Character.load(target)
              except CharacterDoesNotExist:
              player2 = Character(target)
              player2.save()
              play_1_vs_1(player1, player2)
              elif move == "4":
              while True:
              player = raw_input("Which player: or ")
              if player == player1.name:
              player1.upgrade_stat()
              break
              # elif player == player2.name:
              # player2.upgrade_stat()
              # break
              else:
              print("Exiting..")
              return
              if __name__ == "__main__":
              main_menu()


              Some notable changes:



              • The Character class inherits from object, making it a new-style class.

              • This uses a Computer class that inherits from Character and overrides some methods to allow the computer to make its decisions and prevent it from saving its wins and losses.

              • It has a classmethod load that loads a character from a file and a save method to save it.

              • The __str__ magic method makes sure that when we print a character that we see their name

              • Instead of disallowing some stats (like wins) to be upgraded, explicitly allow only strength and defence to be upgraded (whitelist vs blacklist).

              • A Character can attack and heal. By how much is encoded as a class variable.

              • Some of the attributes can be reached like for a dict, to ease the upgrading of a stat.

              • There is a make_move function that performs a characters move, given a choice of moves.

              • The play_round function is generic enough that it does not care if both players are humans or even both are computers.

              • The only thing that does not currently work is upgrading the stats of player 2, if they are human.

              • You don't need to specify the position in str.format strings, if you use them in the order you pass it in. In other words "0 1".format(1, 2) and " ".format(1, 2) are equivalent.

              • It uses a if __name__ == "__main__": guard to allow importing from this module.

              • A new character is automatically created if the loading fails.

              • The AI players have default values now. Whether or not they make sense, I don't know (I managed to consistently beat the easy AI...).

              • Consistently use print as a statement, as it was in Python 2.

              Some things which you should still change:



              • Make all those comments above your functions into docstrings.

              • Port this to Python 3, as Python 2 will be EOL soon.





              share|improve this answer



















              • 2




                Instead of printing a __dict__ prefer using vars. Also, if defining __getitem__ and __setitem__ is only useful for self[target] += 1 in upgrade_stat you shoul favor getattr and/or hasattr instead and handle a failure the same as a restricted attribute. Besides, you may want to check for the XP amount before asking what to upgrade.
                – Mathias Ettinger
                Jul 12 at 7:12










              • @MathiasEttinger: Agree, when I was writing it I thought I might need to set and get more attributes. Removed those methods entirely and replaced them with a call to setattr and getattr. Btw, I am checking that the user has enough exp.
                – Graipher
                Jul 12 at 8:57






              • 1




                But the check comes after asking the question ;)
                – Mathias Ettinger
                Jul 12 at 9:00












              up vote
              5
              down vote










              up vote
              5
              down vote









              Currently your code is a bit all over the place. You have a Character class that can keep track of how much e.g. exp a character has. But when it comes to adding exp, you instead use a data dictionary.



              Also, instead of saving the Character to file, you save that dictionary instead. The only thing where you actually use that class is to get the characters name.



              So you have two options:



              1. Get rid of the class and always use the data dictionary.

              2. Make all of those things something the class handles.

              I would choose option 2 here.



              Here is a start on that road:



              import random
              import json
              import time
              r = random
              # INSTRUCTIONS FOR FIRST TIME USE
              # MAKE 3 COMPUTER ACCOUNTS NAMED "Computer_Easy", "Computer_Med" and
              # "Computer_Hard" AND SET THEIR STATS HOWEVER YOU LIKE! OTHERWISE UNABLE
              # TO PLAY VS AI


              class CharacterDoesNotExist(Exception):
              pass


              class Character(object):
              # Change value of default if you want people to start with higher str/def
              # when they make their account.
              path = 'accounts/.json'
              mild_attack = 12, 22
              hard_attack = 5, 35
              heal_amount = 15, 28
              default = 1

              def __init__(self, name, health=None, strength=None,
              defence=None, gold=0, exp=0, wins=0, losses=0):
              self.name = name
              self.health = 100 if health is None else health
              self.strength = self.default if strength is None else strength
              self.defence = self.default if defence is None else defence
              self.gold = 0 if gold is None else gold
              self.exp = 0 if exp is None else exp
              self.wins = 0 if wins is None else wins
              self.losses = 0 if losses is None else wins

              @classmethod
              def load(cls, name):
              path = cls.path.format(name)
              try:
              with open(path) as f:
              return cls(**json.load(f))
              except Exception:
              raise CharacterDoesNotExist(name)

              def save(self):
              path = self.path.format(self.name)
              with open(path, 'w+') as f:
              json.dump(self.__dict__, f)

              def __str__(self):
              return self.name.capitalize()

              def upgrade_stat(self): # Upgrade either defence or strength
              if self.exp < 100:
              print("You don't have enough exp!")
              return
              target = raw_input("What stat do you want to upgrade?")
              if target not in ("strength", "defence"):
              print("You cannot do that!")
              else:
              self.exp -= 100
              setattr(self, target, getattr(self, target) + 1)
              self.save()

              def attack(self, defender, damage_amount):
              # You get damage boost, depending on attacker strength level and
              # defender defence level.
              damage_amount_boost = (self.strength * damage_amount /
              (self.strength + defender.defence)) + damage_amount
              if damage_amount_boost > defender.health:
              overkill = abs(self.health - damage_amount_boost)
              defender.health = 0
              if overkill > 0:
              print(" takes fatal damage from , with overkill!".format(
              defender, self, overkill))
              else:
              print(" takes fatal damage from !".format(defender, self))
              else:
              defender.health -= damage_amount_boost
              print(" takes damage from !".format(
              defender, damage_amount_boost, self))

              def heal(self, heal_amount):
              if (heal_amount + self.health > 100):
              self.health = 100
              print(" heals back to full health!".format(self))
              else:
              self.health += heal_amount
              print(" heals for !".format(self, heal_amount))

              def get_selection(self):
              print 'Avalaible moves: 1. Mild Attack, 2. Hard Attack, 3. Heal'
              while True:
              try:
              choice = int(input("Select a move: "))
              if not 1 <= choice <= 3:
              continue
              return choice
              except ValueError:
              print("The input was invalid. Please try again.")

              def make_move(self, player2):
              choice = self.get_selection()
              if choice == 1:
              # mild attack
              damage = random.randint(*self.mild_attack)
              self.attack(player2, damage)
              elif choice == 2:
              # mild attack
              damage = random.randint(*self.hard_attack)
              self.attack(player2, damage)
              elif choice == 3:
              # mild attack
              heal = random.randint(*self.heal_amount)
              self.heal(heal)

              def win(self):
              self.wins += 1
              self.exp += 25
              self.gold += 100
              self.save()

              def loose(self):
              self.losses += 1
              self.save()


              class Computer(Character):

              def get_selection(self):
              print("Computer thinking...")
              time.sleep(random.randrange(2, 5))

              if self.health <= 35:
              # Have the computer heal ~50% of its turns when <= 35
              if random.random() >= 0.5:
              return 3
              return random.randint(1, 2)
              elif self.health == 100:
              return random.randint(1, 2)
              return random.randint(1, 3)

              def win(self):
              self.wins += 1

              def loose(self):
              self.losses += 1


              def play_round(player1, player2):
              player1.health = player2.health = 100
              while True:
              print("n has health remaining and has health remaining.".format(
              player1, player1.health, player2, player2.health))
              for _ in range(2):
              player1.make_move(player2)
              if player2.health <= 0:
              print(" looses!".format(player2))
              player1.win()
              player2.loose()
              return
              # swap the players
              player1, player2 = player2, player1


              # Play vs Ai, which you select your difficulty.
              def play_vs_ai(human, computer):
              while True:
              print "Current Score:"
              print "You - ".format(human.wins)
              print "Computer - ".format(computer.wins)
              play_round(computer, human)
              print
              if raw_input("Play another round?(Y/N)").lower() == "n":
              break


              def play_1_vs_1(player1, player2): # Play a local 1v1 game.
              while True:
              print "Current Score:"
              print "Player1 - ".format(player1.wins)
              print "Player2 - ".format(player2.wins)
              play_round(player1, player1)
              print
              if raw_input("Play another 1v1? (y/n)").lower() != "y":
              break


              def main_menu(): # Main menu
              name = raw_input("Username to load or create?")
              try:
              player1 = Character.load(name)
              except CharacterDoesNotExist:
              player1 = Character(name)
              player1.save()
              while True:
              print("What do you want to do?")
              move = raw_input(
              "1. Battle AI | 2. List stats | 3. Play 1v1 | 4. Upgrade str/def")
              if move == "1":
              target = raw_input("Easy, med or hard?")
              if target.lower() == "easy":
              computer = Computer("Computer_Easy")
              elif target.lower() == "med": # Set stats however you like
              computer = Computer("Computer_Med", strength=2, defence=3)
              elif target.lower() == "hard":
              computer = Computer("Computer_Hard", strength=5, defence=4)
              play_vs_ai(player1, computer)
              elif move == "2":
              print player1.__dict__
              elif move == "3":
              target = raw_input("Who do you want to fight?")
              try:
              player2 = Character.load(target)
              except CharacterDoesNotExist:
              player2 = Character(target)
              player2.save()
              play_1_vs_1(player1, player2)
              elif move == "4":
              while True:
              player = raw_input("Which player: or ")
              if player == player1.name:
              player1.upgrade_stat()
              break
              # elif player == player2.name:
              # player2.upgrade_stat()
              # break
              else:
              print("Exiting..")
              return
              if __name__ == "__main__":
              main_menu()


              Some notable changes:



              • The Character class inherits from object, making it a new-style class.

              • This uses a Computer class that inherits from Character and overrides some methods to allow the computer to make its decisions and prevent it from saving its wins and losses.

              • It has a classmethod load that loads a character from a file and a save method to save it.

              • The __str__ magic method makes sure that when we print a character that we see their name

              • Instead of disallowing some stats (like wins) to be upgraded, explicitly allow only strength and defence to be upgraded (whitelist vs blacklist).

              • A Character can attack and heal. By how much is encoded as a class variable.

              • Some of the attributes can be reached like for a dict, to ease the upgrading of a stat.

              • There is a make_move function that performs a characters move, given a choice of moves.

              • The play_round function is generic enough that it does not care if both players are humans or even both are computers.

              • The only thing that does not currently work is upgrading the stats of player 2, if they are human.

              • You don't need to specify the position in str.format strings, if you use them in the order you pass it in. In other words "0 1".format(1, 2) and " ".format(1, 2) are equivalent.

              • It uses a if __name__ == "__main__": guard to allow importing from this module.

              • A new character is automatically created if the loading fails.

              • The AI players have default values now. Whether or not they make sense, I don't know (I managed to consistently beat the easy AI...).

              • Consistently use print as a statement, as it was in Python 2.

              Some things which you should still change:



              • Make all those comments above your functions into docstrings.

              • Port this to Python 3, as Python 2 will be EOL soon.





              share|improve this answer















              Currently your code is a bit all over the place. You have a Character class that can keep track of how much e.g. exp a character has. But when it comes to adding exp, you instead use a data dictionary.



              Also, instead of saving the Character to file, you save that dictionary instead. The only thing where you actually use that class is to get the characters name.



              So you have two options:



              1. Get rid of the class and always use the data dictionary.

              2. Make all of those things something the class handles.

              I would choose option 2 here.



              Here is a start on that road:



              import random
              import json
              import time
              r = random
              # INSTRUCTIONS FOR FIRST TIME USE
              # MAKE 3 COMPUTER ACCOUNTS NAMED "Computer_Easy", "Computer_Med" and
              # "Computer_Hard" AND SET THEIR STATS HOWEVER YOU LIKE! OTHERWISE UNABLE
              # TO PLAY VS AI


              class CharacterDoesNotExist(Exception):
              pass


              class Character(object):
              # Change value of default if you want people to start with higher str/def
              # when they make their account.
              path = 'accounts/.json'
              mild_attack = 12, 22
              hard_attack = 5, 35
              heal_amount = 15, 28
              default = 1

              def __init__(self, name, health=None, strength=None,
              defence=None, gold=0, exp=0, wins=0, losses=0):
              self.name = name
              self.health = 100 if health is None else health
              self.strength = self.default if strength is None else strength
              self.defence = self.default if defence is None else defence
              self.gold = 0 if gold is None else gold
              self.exp = 0 if exp is None else exp
              self.wins = 0 if wins is None else wins
              self.losses = 0 if losses is None else wins

              @classmethod
              def load(cls, name):
              path = cls.path.format(name)
              try:
              with open(path) as f:
              return cls(**json.load(f))
              except Exception:
              raise CharacterDoesNotExist(name)

              def save(self):
              path = self.path.format(self.name)
              with open(path, 'w+') as f:
              json.dump(self.__dict__, f)

              def __str__(self):
              return self.name.capitalize()

              def upgrade_stat(self): # Upgrade either defence or strength
              if self.exp < 100:
              print("You don't have enough exp!")
              return
              target = raw_input("What stat do you want to upgrade?")
              if target not in ("strength", "defence"):
              print("You cannot do that!")
              else:
              self.exp -= 100
              setattr(self, target, getattr(self, target) + 1)
              self.save()

              def attack(self, defender, damage_amount):
              # You get damage boost, depending on attacker strength level and
              # defender defence level.
              damage_amount_boost = (self.strength * damage_amount /
              (self.strength + defender.defence)) + damage_amount
              if damage_amount_boost > defender.health:
              overkill = abs(self.health - damage_amount_boost)
              defender.health = 0
              if overkill > 0:
              print(" takes fatal damage from , with overkill!".format(
              defender, self, overkill))
              else:
              print(" takes fatal damage from !".format(defender, self))
              else:
              defender.health -= damage_amount_boost
              print(" takes damage from !".format(
              defender, damage_amount_boost, self))

              def heal(self, heal_amount):
              if (heal_amount + self.health > 100):
              self.health = 100
              print(" heals back to full health!".format(self))
              else:
              self.health += heal_amount
              print(" heals for !".format(self, heal_amount))

              def get_selection(self):
              print 'Avalaible moves: 1. Mild Attack, 2. Hard Attack, 3. Heal'
              while True:
              try:
              choice = int(input("Select a move: "))
              if not 1 <= choice <= 3:
              continue
              return choice
              except ValueError:
              print("The input was invalid. Please try again.")

              def make_move(self, player2):
              choice = self.get_selection()
              if choice == 1:
              # mild attack
              damage = random.randint(*self.mild_attack)
              self.attack(player2, damage)
              elif choice == 2:
              # mild attack
              damage = random.randint(*self.hard_attack)
              self.attack(player2, damage)
              elif choice == 3:
              # mild attack
              heal = random.randint(*self.heal_amount)
              self.heal(heal)

              def win(self):
              self.wins += 1
              self.exp += 25
              self.gold += 100
              self.save()

              def loose(self):
              self.losses += 1
              self.save()


              class Computer(Character):

              def get_selection(self):
              print("Computer thinking...")
              time.sleep(random.randrange(2, 5))

              if self.health <= 35:
              # Have the computer heal ~50% of its turns when <= 35
              if random.random() >= 0.5:
              return 3
              return random.randint(1, 2)
              elif self.health == 100:
              return random.randint(1, 2)
              return random.randint(1, 3)

              def win(self):
              self.wins += 1

              def loose(self):
              self.losses += 1


              def play_round(player1, player2):
              player1.health = player2.health = 100
              while True:
              print("n has health remaining and has health remaining.".format(
              player1, player1.health, player2, player2.health))
              for _ in range(2):
              player1.make_move(player2)
              if player2.health <= 0:
              print(" looses!".format(player2))
              player1.win()
              player2.loose()
              return
              # swap the players
              player1, player2 = player2, player1


              # Play vs Ai, which you select your difficulty.
              def play_vs_ai(human, computer):
              while True:
              print "Current Score:"
              print "You - ".format(human.wins)
              print "Computer - ".format(computer.wins)
              play_round(computer, human)
              print
              if raw_input("Play another round?(Y/N)").lower() == "n":
              break


              def play_1_vs_1(player1, player2): # Play a local 1v1 game.
              while True:
              print "Current Score:"
              print "Player1 - ".format(player1.wins)
              print "Player2 - ".format(player2.wins)
              play_round(player1, player1)
              print
              if raw_input("Play another 1v1? (y/n)").lower() != "y":
              break


              def main_menu(): # Main menu
              name = raw_input("Username to load or create?")
              try:
              player1 = Character.load(name)
              except CharacterDoesNotExist:
              player1 = Character(name)
              player1.save()
              while True:
              print("What do you want to do?")
              move = raw_input(
              "1. Battle AI | 2. List stats | 3. Play 1v1 | 4. Upgrade str/def")
              if move == "1":
              target = raw_input("Easy, med or hard?")
              if target.lower() == "easy":
              computer = Computer("Computer_Easy")
              elif target.lower() == "med": # Set stats however you like
              computer = Computer("Computer_Med", strength=2, defence=3)
              elif target.lower() == "hard":
              computer = Computer("Computer_Hard", strength=5, defence=4)
              play_vs_ai(player1, computer)
              elif move == "2":
              print player1.__dict__
              elif move == "3":
              target = raw_input("Who do you want to fight?")
              try:
              player2 = Character.load(target)
              except CharacterDoesNotExist:
              player2 = Character(target)
              player2.save()
              play_1_vs_1(player1, player2)
              elif move == "4":
              while True:
              player = raw_input("Which player: or ")
              if player == player1.name:
              player1.upgrade_stat()
              break
              # elif player == player2.name:
              # player2.upgrade_stat()
              # break
              else:
              print("Exiting..")
              return
              if __name__ == "__main__":
              main_menu()


              Some notable changes:



              • The Character class inherits from object, making it a new-style class.

              • This uses a Computer class that inherits from Character and overrides some methods to allow the computer to make its decisions and prevent it from saving its wins and losses.

              • It has a classmethod load that loads a character from a file and a save method to save it.

              • The __str__ magic method makes sure that when we print a character that we see their name

              • Instead of disallowing some stats (like wins) to be upgraded, explicitly allow only strength and defence to be upgraded (whitelist vs blacklist).

              • A Character can attack and heal. By how much is encoded as a class variable.

              • Some of the attributes can be reached like for a dict, to ease the upgrading of a stat.

              • There is a make_move function that performs a characters move, given a choice of moves.

              • The play_round function is generic enough that it does not care if both players are humans or even both are computers.

              • The only thing that does not currently work is upgrading the stats of player 2, if they are human.

              • You don't need to specify the position in str.format strings, if you use them in the order you pass it in. In other words "0 1".format(1, 2) and " ".format(1, 2) are equivalent.

              • It uses a if __name__ == "__main__": guard to allow importing from this module.

              • A new character is automatically created if the loading fails.

              • The AI players have default values now. Whether or not they make sense, I don't know (I managed to consistently beat the easy AI...).

              • Consistently use print as a statement, as it was in Python 2.

              Some things which you should still change:



              • Make all those comments above your functions into docstrings.

              • Port this to Python 3, as Python 2 will be EOL soon.






              share|improve this answer















              share|improve this answer



              share|improve this answer








              edited Jul 12 at 9:06


























              answered Jul 11 at 16:29









              Graipher

              20.4k42981




              20.4k42981







              • 2




                Instead of printing a __dict__ prefer using vars. Also, if defining __getitem__ and __setitem__ is only useful for self[target] += 1 in upgrade_stat you shoul favor getattr and/or hasattr instead and handle a failure the same as a restricted attribute. Besides, you may want to check for the XP amount before asking what to upgrade.
                – Mathias Ettinger
                Jul 12 at 7:12










              • @MathiasEttinger: Agree, when I was writing it I thought I might need to set and get more attributes. Removed those methods entirely and replaced them with a call to setattr and getattr. Btw, I am checking that the user has enough exp.
                – Graipher
                Jul 12 at 8:57






              • 1




                But the check comes after asking the question ;)
                – Mathias Ettinger
                Jul 12 at 9:00












              • 2




                Instead of printing a __dict__ prefer using vars. Also, if defining __getitem__ and __setitem__ is only useful for self[target] += 1 in upgrade_stat you shoul favor getattr and/or hasattr instead and handle a failure the same as a restricted attribute. Besides, you may want to check for the XP amount before asking what to upgrade.
                – Mathias Ettinger
                Jul 12 at 7:12










              • @MathiasEttinger: Agree, when I was writing it I thought I might need to set and get more attributes. Removed those methods entirely and replaced them with a call to setattr and getattr. Btw, I am checking that the user has enough exp.
                – Graipher
                Jul 12 at 8:57






              • 1




                But the check comes after asking the question ;)
                – Mathias Ettinger
                Jul 12 at 9:00







              2




              2




              Instead of printing a __dict__ prefer using vars. Also, if defining __getitem__ and __setitem__ is only useful for self[target] += 1 in upgrade_stat you shoul favor getattr and/or hasattr instead and handle a failure the same as a restricted attribute. Besides, you may want to check for the XP amount before asking what to upgrade.
              – Mathias Ettinger
              Jul 12 at 7:12




              Instead of printing a __dict__ prefer using vars. Also, if defining __getitem__ and __setitem__ is only useful for self[target] += 1 in upgrade_stat you shoul favor getattr and/or hasattr instead and handle a failure the same as a restricted attribute. Besides, you may want to check for the XP amount before asking what to upgrade.
              – Mathias Ettinger
              Jul 12 at 7:12












              @MathiasEttinger: Agree, when I was writing it I thought I might need to set and get more attributes. Removed those methods entirely and replaced them with a call to setattr and getattr. Btw, I am checking that the user has enough exp.
              – Graipher
              Jul 12 at 8:57




              @MathiasEttinger: Agree, when I was writing it I thought I might need to set and get more attributes. Removed those methods entirely and replaced them with a call to setattr and getattr. Btw, I am checking that the user has enough exp.
              – Graipher
              Jul 12 at 8:57




              1




              1




              But the check comes after asking the question ;)
              – Mathias Ettinger
              Jul 12 at 9:00




              But the check comes after asking the question ;)
              – Mathias Ettinger
              Jul 12 at 9:00












              up vote
              4
              down vote














              1. parse_int() has no reason to be a function, as it doesn't simplify anything. get_selection() could look like this:



                def get_selection():
                valid_input = False
                while (valid_input is False):
                print()
                choice = input("Select an attack: ")
                try:
                return int(choice)
                except ValueError:
                print("The input was invalid. Please try again.")


              2. For comparing object identity (i.e. current_player == player2 or current_player == computer) use is. this checks if the objects are the same, rather than if they have the same values. In your case, because you did not override == they should currently act the same.


              3. You can abstract out a single human or computer turn as a function, so that the different combinations of human computer play are all the same code. This will also make it easier to do AI vs. AI duels.


              4. Try to separate the game code from the output code. What if you or someone else wanted to make a different user interface for your game? First try to remove printing from the Character class, then try to make a quiet turn function that handles dueling using arguments and return values.


              5. Instead of r = random you can do import random as r. In my opinion however, it is not a good idea to change the name of a module as it makes it harder for readers to figure out which module you are using.






              share|improve this answer



























                up vote
                4
                down vote














                1. parse_int() has no reason to be a function, as it doesn't simplify anything. get_selection() could look like this:



                  def get_selection():
                  valid_input = False
                  while (valid_input is False):
                  print()
                  choice = input("Select an attack: ")
                  try:
                  return int(choice)
                  except ValueError:
                  print("The input was invalid. Please try again.")


                2. For comparing object identity (i.e. current_player == player2 or current_player == computer) use is. this checks if the objects are the same, rather than if they have the same values. In your case, because you did not override == they should currently act the same.


                3. You can abstract out a single human or computer turn as a function, so that the different combinations of human computer play are all the same code. This will also make it easier to do AI vs. AI duels.


                4. Try to separate the game code from the output code. What if you or someone else wanted to make a different user interface for your game? First try to remove printing from the Character class, then try to make a quiet turn function that handles dueling using arguments and return values.


                5. Instead of r = random you can do import random as r. In my opinion however, it is not a good idea to change the name of a module as it makes it harder for readers to figure out which module you are using.






                share|improve this answer

























                  up vote
                  4
                  down vote










                  up vote
                  4
                  down vote










                  1. parse_int() has no reason to be a function, as it doesn't simplify anything. get_selection() could look like this:



                    def get_selection():
                    valid_input = False
                    while (valid_input is False):
                    print()
                    choice = input("Select an attack: ")
                    try:
                    return int(choice)
                    except ValueError:
                    print("The input was invalid. Please try again.")


                  2. For comparing object identity (i.e. current_player == player2 or current_player == computer) use is. this checks if the objects are the same, rather than if they have the same values. In your case, because you did not override == they should currently act the same.


                  3. You can abstract out a single human or computer turn as a function, so that the different combinations of human computer play are all the same code. This will also make it easier to do AI vs. AI duels.


                  4. Try to separate the game code from the output code. What if you or someone else wanted to make a different user interface for your game? First try to remove printing from the Character class, then try to make a quiet turn function that handles dueling using arguments and return values.


                  5. Instead of r = random you can do import random as r. In my opinion however, it is not a good idea to change the name of a module as it makes it harder for readers to figure out which module you are using.






                  share|improve this answer
















                  1. parse_int() has no reason to be a function, as it doesn't simplify anything. get_selection() could look like this:



                    def get_selection():
                    valid_input = False
                    while (valid_input is False):
                    print()
                    choice = input("Select an attack: ")
                    try:
                    return int(choice)
                    except ValueError:
                    print("The input was invalid. Please try again.")


                  2. For comparing object identity (i.e. current_player == player2 or current_player == computer) use is. this checks if the objects are the same, rather than if they have the same values. In your case, because you did not override == they should currently act the same.


                  3. You can abstract out a single human or computer turn as a function, so that the different combinations of human computer play are all the same code. This will also make it easier to do AI vs. AI duels.


                  4. Try to separate the game code from the output code. What if you or someone else wanted to make a different user interface for your game? First try to remove printing from the Character class, then try to make a quiet turn function that handles dueling using arguments and return values.


                  5. Instead of r = random you can do import random as r. In my opinion however, it is not a good idea to change the name of a module as it makes it harder for readers to figure out which module you are using.







                  share|improve this answer















                  share|improve this answer



                  share|improve this answer








                  edited Jul 11 at 16:40









                  Daniel

                  4,1032835




                  4,1032835











                  answered Jul 11 at 16:14









                  Peter

                  59410




                  59410




















                      up vote
                      2
                      down vote













                      Try to eliminate repetitions. For example, you have a lot of “generate filename, open, read/write” statements. Instead, create a separate class which could use along the lines of



                      storage = FileStorage(name) # reads "accounts/name.json" into storage.data
                      storage.data["something"] = whatever
                      storage.save()


                      Where else are you repeating yourself a lot? You have



                      if (current_player == human):
                      computer.calculate_damage(damage, human.name, computer.name)
                      else:
                      human.calculate_damage(damage, computer.name, human.name)


                      But you can simplify this to



                      active_player, non_active_player = human, computer

                      ...

                      active_player.calculate_damage(damage, active_player.name, non_active_player.name)

                      ...

                      # and when the turn ends:
                      active_player, non_active_player = non_active_player, active_player


                      And so on.



                      Repetition is bad because whenever you want to make a change you have to do it in multiple places, and you risk failing to update all the places or updating some of them differently from others.






                      share|improve this answer

























                        up vote
                        2
                        down vote













                        Try to eliminate repetitions. For example, you have a lot of “generate filename, open, read/write” statements. Instead, create a separate class which could use along the lines of



                        storage = FileStorage(name) # reads "accounts/name.json" into storage.data
                        storage.data["something"] = whatever
                        storage.save()


                        Where else are you repeating yourself a lot? You have



                        if (current_player == human):
                        computer.calculate_damage(damage, human.name, computer.name)
                        else:
                        human.calculate_damage(damage, computer.name, human.name)


                        But you can simplify this to



                        active_player, non_active_player = human, computer

                        ...

                        active_player.calculate_damage(damage, active_player.name, non_active_player.name)

                        ...

                        # and when the turn ends:
                        active_player, non_active_player = non_active_player, active_player


                        And so on.



                        Repetition is bad because whenever you want to make a change you have to do it in multiple places, and you risk failing to update all the places or updating some of them differently from others.






                        share|improve this answer























                          up vote
                          2
                          down vote










                          up vote
                          2
                          down vote









                          Try to eliminate repetitions. For example, you have a lot of “generate filename, open, read/write” statements. Instead, create a separate class which could use along the lines of



                          storage = FileStorage(name) # reads "accounts/name.json" into storage.data
                          storage.data["something"] = whatever
                          storage.save()


                          Where else are you repeating yourself a lot? You have



                          if (current_player == human):
                          computer.calculate_damage(damage, human.name, computer.name)
                          else:
                          human.calculate_damage(damage, computer.name, human.name)


                          But you can simplify this to



                          active_player, non_active_player = human, computer

                          ...

                          active_player.calculate_damage(damage, active_player.name, non_active_player.name)

                          ...

                          # and when the turn ends:
                          active_player, non_active_player = non_active_player, active_player


                          And so on.



                          Repetition is bad because whenever you want to make a change you have to do it in multiple places, and you risk failing to update all the places or updating some of them differently from others.






                          share|improve this answer













                          Try to eliminate repetitions. For example, you have a lot of “generate filename, open, read/write” statements. Instead, create a separate class which could use along the lines of



                          storage = FileStorage(name) # reads "accounts/name.json" into storage.data
                          storage.data["something"] = whatever
                          storage.save()


                          Where else are you repeating yourself a lot? You have



                          if (current_player == human):
                          computer.calculate_damage(damage, human.name, computer.name)
                          else:
                          human.calculate_damage(damage, computer.name, human.name)


                          But you can simplify this to



                          active_player, non_active_player = human, computer

                          ...

                          active_player.calculate_damage(damage, active_player.name, non_active_player.name)

                          ...

                          # and when the turn ends:
                          active_player, non_active_player = non_active_player, active_player


                          And so on.



                          Repetition is bad because whenever you want to make a change you have to do it in multiple places, and you risk failing to update all the places or updating some of them differently from others.







                          share|improve this answer













                          share|improve this answer



                          share|improve this answer











                          answered Jul 11 at 19:04









                          Roman Odaisky

                          2712




                          2712






















                               

                              draft saved


                              draft discarded


























                               


                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function ()
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f198293%2ftext-turn-based-dueling-game%23new-answer', 'question_page');

                              );

                              Post as a guest













































































                              Popular posts from this blog

                              Chat program with C++ and SFML

                              Function to Return a JSON Like Objects Using VBA Collections and Arrays

                              Will my employers contract hold up in court?