I'm new to coding and this is a text based adventure game with combat. Sleep and choice functions based on idea from https://codereview.stackexchange.com/a/52292/179642. Map idea from Codecademy battleship tutorial.

The actions in the fight function are not in a loop because attacks reduce the opponent's hp but healing affects your own hp.

Any comments on new ideas/features, better coding methods greatly appreciated.

import random, time, sys

#initial variables or settings, and map generation
hp = 100
rMap = [('G', 'G', 'G', 'C', 'W'), ('F', 'F', 'G', 'W', 'M'), ('B', 'W', 'W', 'G', 'M'), ('F', 'F', 'G', 'G', 'G'), ('F', 'F', 'F', 'G', 'V')]
pMap = []
for x in range(5):
pMap.append(['?'] * 5)
legend = {'X': 'You', '?': 'Unexplored', 'G': 'Grassland', 'V': 'Village', 'F': 'Forest', 'M': 'Mountain', 'B': 'Bridge', 'W': 'Water', 'C': 'Castle'}
enemy = {'G': ('Wolf', 30, 0, 33, 33, 50), 'F': ('Bandit', 30, 1, 50, 33, 50), 'M': ('Troll', 80, 0, 33, 50, 50), 'C': ('Dragon', 170, 2, 0, 0, 100), 'B': ('Ogre', 100, 0.5, 100, 100, 100)}
posR = 4
posC = 4
inv = {'Bow' : 1, 'Arrow' : 0, 'Potion' : 0}
action = {'Punch': (8, 12, 'p'), 'Kick': (6, 20, 'k')}

def wait(value):    #can be commented away for quicker testing
#time.sleep(value)
pass

def new_loc():  #whether there is an enemy when the player moves to a new location
for i in enemy:
if rMap[posR][posC] == i:
if random.randint(1, 100) <= enemy[i]:
fight(enemy[i], enemy[i], enemy[i])
loot(enemy[i], enemy[i])
if i == 'C':
print ('You win! Congratulations!')
sys.exit()
updatepos()
turn()

def turn():  #every turn or action by the player
global hp
print ('What do you want to do?')
wait(0.5)
print ('t to Travel, i to view Inventory, m to view Map')
c = choice(['t', 'i', 'm'])
if c == 't':
print ('Which direction do you want to move?')
d = []
if posR != 0:
if rMap[posR - 1][posC] != 'W':
print ('f to move forward')
d.append('f')
if posR != 4:
if rMap[posR + 1][posC] != 'W':
print ('b to move backward')
d.append('b')
if posC != 0:
if rMap[posR][posC - 1] != 'W':
print ('l to move left')
d.append('l')
if posC != 4:
if rMap[posR][posC + 1] != 'W':
print ('r to move right')
d.append('r')
sel_dir = choice(d)
if sel_dir == 'f':
move(-1, 0)
if sel_dir == 'b':
move(1, 0)
if sel_dir == 'l':
move(0, -1)
if sel_dir == 'r':
move(0, 1)
if c == 'i':
showInv()
turn()
if c == 'm':
updatepos()
turn()

def start():    #introduction to the game
print ('Your village has been burnt down by a dragon!')
wait(0.5)
print (' ')
print ('You have to find it and take revenge!')
print (' ')
updatepos()
turn()

def showAction():   #for debugging player actions in battle
for i in action:
print (i, action[i])

def updateAction():   #for updating actions linked to items
if inv['Potion'] > 0:
if 'Heal' not in action:
action['Heal'] = (40, 50, 'h')
if inv['Potion'] == 0:
if 'Heal' in action:
action.pop('Heal')
if inv['Arrow'] > 0:
if 'Shoot' not in action:
action['Shoot'] = (30, 40, 's')
if inv['Arrow'] == 0:
if 'Shoot' in action:
action.pop('Shoot')

def showInv():    #for viewing inventory
global hp
for i in inv:
if inv[i] > 0:
print (i + ':', inv[i])
if inv['Potion'] > 0:
updateAction()
print('Do you want to drink a Potion? y/n')
drink = choice(['y', 'n'])
if drink == 'y':
h = random.randint(action['Heal'], action['Heal'])
hp += h
print('You used a Potion')
wait(0.5)
print('You healed yourself for %d HP!' % h)
wait(0.5)
inv['Potion'] -= 1
print('You have %d Potions left' % (inv['Potion']))
turn()

def move(r, c):    #when the player moves
global posR
global posC
posR = posR + r
posC = posC + c
wait(0.5)
if r == -1:
print ('Moving Forward...')
if r == 1:
print ('Moving Backward...')
if c == 1:
print ('Moving Right...')
if c == -1:
print ('Moving Left...')
new_loc()

def updatepos():    #updating the map position
pMap[posR][posC] = 'X'
if posR != 4:
pMap[posR + 1][posC] = rMap[posR + 1][posC]
if posR != 0:
pMap[posR - 1][posC] = rMap[posR - 1][posC]
if posC != 4:
pMap[posR][posC + 1] = rMap[posR][posC + 1]
if posC != 0:
pMap[posR][posC - 1] = rMap[posR][posC - 1]
showMap()
wait(0.5)
print ('You are now in %s' % legend[rMap[posR][posC]])

def showMap():  #prints the map and legend (for revealed areas)
print ('Map:')
for row in pMap:
for i in row:
print (i, end = ' ')
print()
print (' ')
legList = []
for row in pMap:
for i in row:
legList.append(i)
for i in legend:
if i in legList:
print (i, legend[i])
print (' ')

def choice(list):   #get a valid choice from the user
while True:
userChoice = input('Choose an action:')
userChoice = userChoice.lower()
if userChoice in list:
return userChoice
else:
print ('Invalid choice. Try again.')

def fight(enemy, eHP, level):   #fighting an enemy
print ('%s appeared!' % enemy)
wait(0.5)
global hp
enemyHP = eHP
while True:
if hp <= 0:
print ("You died :(. Game over")
sys.exit()
wait(1)
print ('Your hp: %d, %s hp: %d' % (hp, enemy, enemyHP))
wait(1)
updateAction()
act = []
for i in action:
print (i + ': ' + str(action[i]) + ' - ' + str(action[i]))
act.append(action[i])
act_str = ', '.join(str(x) for x in act)
print ('Choices: ' + act_str)
pmove = choice(act)
wait(0.7)
if pmove == 'p':
d = random.randint(action['Punch'], action['Punch'])
enemyHP -= d
print ('You punch %s for %d damage!' % (enemy, d))
elif pmove == 'k':
d = random.randint(action['Kick'], action['Kick'])
enemyHP -= d
print ('You kick %s for %d damage!' % (enemy, d))
elif pmove == 'h':
h = random.randint(action['Heal'], action['Heal'])
print ('You used a Potion')
print ('You heal yourself for %d HP!' % h)
inv['Potion'] -= 1
print ('You have %d Potions left' % (inv['Potion']))
updateAction()
hp += h
elif pmove == 's':
d = random.randint(action['Shoot'], action['Shoot'])
print ('You used an Arrow')
print ('You shoot %s for %d damage!' % (enemy, d))
inv['Arrow'] -= 1
print('You have %d Arrows left' % (inv['Arrow']))
updateAction()
enemyHP -= d

if enemyHP <= 0:
print("You defeated %s!" % enemy)
return

wait(1)
emove = random.randint (1, 3)
if emove == 1:
dam = random.randint(1, 5) + 10 * level
print ('%s scratches you for %d damage!' % (enemy, dam))
hp -= dam
elif emove == 2:
dam = random.randint(6, 10) + 0.5 * level
print ('%s bites you for %d damage!' % (enemy, dam))
hp -= dam
else:
heal = random.randint(9, 15) + 1 * level
print ('%s healed for %d HP!' % (enemy, heal))
enemyHP += heal

def loot(a, p): #probability of getting loot from enemy
wait(1)
pArrow = random.randint(1, 100)
pPotion = random.randint(1, 100)
if pArrow <= a:
inv['Arrow'] += 1
print ('You found an Arrow!')
wait(0.5)
print('You now have %d Arrows' % inv['Arrow'])
wait(0.7)

if pPotion <= p:
inv['Potion'] += 1
print ('You found a Potion!')
wait(0.5)
print('You now have %d Potions' % inv['Potion'])
wait(0.7)

start()
• I'm not very good at Python so I don't have any criticism other than to say, I've briefly played your game, got into a fight with a wolf, defeated the wolf and thoroughly enjoyed it. :) Sep 14 '18 at 22:58
• One thing you might consider is putting another new line after Choose an action: to give a little separation between each turn. Sep 15 '18 at 4:33
• @I0_ol Glad you enjoyed it! I'll implement a turn counter along with the other updates so the user knows which turn they are on.
– Ben
Sep 15 '18 at 5:54

Nice work!

Here are some things you can improve:

• Style: PEP8 - you can check it with http://pep8online.com/ and there are many editors / editor-plugins that autocorrect or at least complain.
• #can be commented away for quicker testing is useless
• Variable names:
• inv: inventory would be better
• What is an rMap, what a pMap?
• Documentation: Adding docstrings is usually a good idea.

Object Orientation

You could create a couple of objects and assign attributes / functions to them:

• Game: Command line interactions, contains the other objects.
• Has the map(s) as a property
• Player: Has an intentory, a position, hp, ...
• Thanks for the feedback!. Forgot to remove the # in wait. rMap is the real map, but is not shown to the player so there is some element of exploration. pMap is the map shown to the player, and is updated to reveal the adjacent areas whenever the player moves to a new location. I'll update their names to reflect that. Right, realised that I used an object oriented language but did not use any objects... Silly me! Creating a class would also be a better way to manage the enemies' stats instead of a list within a dictionary.
– Ben
Sep 15 '18 at 5:46