mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-22 15:16:33 -08:00
Adds comments
This commit is contained in:
@@ -1,37 +1,25 @@
|
||||
"""
|
||||
BUG
|
||||
|
||||
Ported by Peter Sharp
|
||||
"""
|
||||
|
||||
from random import randint
|
||||
from collections import namedtuple
|
||||
|
||||
PAGE_WIDTH = 64
|
||||
|
||||
def main():
|
||||
states = {
|
||||
'start': (print_start, control_start, update_state),
|
||||
'instructions': (print_instructions, goto_game, update_state),
|
||||
'game': (print_game, control_game, update_game),
|
||||
'pictures': (print_pictures, goto_game, update_state),
|
||||
'won': (print_winner, exit_game, update_state)
|
||||
}
|
||||
|
||||
partTypes = (
|
||||
Bodypart(name="BODY", count=1 , depends=None),
|
||||
Bodypart(name="NECK", count=1 , depends=0),
|
||||
Bodypart(name="HEAD", count=1 , depends=1),
|
||||
Bodypart(name="FEELERS", count=2 , depends=2),
|
||||
Bodypart(name="TAIL", count=1 , depends=0),
|
||||
Bodypart(name="LEGS", count=6 , depends=0)
|
||||
)
|
||||
|
||||
data = {
|
||||
'state': 'start',
|
||||
'partNo': None,
|
||||
'players': {
|
||||
'YOU': [0] * len(partTypes),
|
||||
'I': [0] * len(partTypes)
|
||||
},
|
||||
'partTypes': partTypes,
|
||||
'finished': [],
|
||||
'logs': []
|
||||
}
|
||||
def main(states, data):
|
||||
"""
|
||||
Starts the game loop using given states and data
|
||||
|
||||
Uses a modified version of the MVC (Model View Controller) pattern that uses functions instead of objects
|
||||
|
||||
each state in the game has one of each of the following:
|
||||
View, displays data
|
||||
Control, converts raw command from user into something the model understands
|
||||
Model, updates game data based on action received from controller
|
||||
"""
|
||||
|
||||
while True:
|
||||
if 'exit' == data['state']: break
|
||||
@@ -43,6 +31,9 @@ def main():
|
||||
Bodypart = namedtuple('Bodypart', ['name', 'count', 'depends'])
|
||||
|
||||
def print_start(_):
|
||||
"""
|
||||
Prints start message
|
||||
"""
|
||||
print_centered("BUG")
|
||||
print_centered("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY")
|
||||
print()
|
||||
@@ -54,6 +45,9 @@ def print_start(_):
|
||||
return input("DO YOU WANT INSTRUCTIONS? ")
|
||||
|
||||
def control_start(cmd):
|
||||
"""
|
||||
Controls the start state
|
||||
"""
|
||||
if cmd.lower() in ('y', 'yes'):
|
||||
action = 'instructions'
|
||||
else:
|
||||
@@ -61,6 +55,9 @@ def control_start(cmd):
|
||||
return action
|
||||
|
||||
def print_instructions(data):
|
||||
"""
|
||||
Prints game instructions
|
||||
"""
|
||||
print("THE OBJECT OF BUG IS TO FINISH YOUR BUG BEFORE I FINISH")
|
||||
print("MINE. EACH NUMBER STANDS FOR A PART OF THE BUG BODY.")
|
||||
print("I WILL ROLL THE DIE FOR YOU, TELL YOU WHAT I ROLLED FOR YOU")
|
||||
@@ -80,12 +77,22 @@ def print_instructions(data):
|
||||
return ''
|
||||
|
||||
def goto_game(_):
|
||||
"""
|
||||
Returns game
|
||||
"""
|
||||
return 'game'
|
||||
|
||||
def update_state(data, action):
|
||||
"""
|
||||
sets game state to given player value
|
||||
"""
|
||||
return {**data, 'state': action}
|
||||
|
||||
def update_game(data, action):
|
||||
"""
|
||||
Updates game data for player turns until one player successfully gets a body part
|
||||
"""
|
||||
# stores logs of what happened during a particular round
|
||||
logs = []
|
||||
|
||||
if 'pictures' == action:
|
||||
@@ -94,16 +101,24 @@ def update_game(data, action):
|
||||
partAdded = False
|
||||
while partAdded == False:
|
||||
for player, parts in data['players'].items():
|
||||
# rolls the dice for a part
|
||||
newPartIdx = randint(1,6) - 1
|
||||
|
||||
# gets information about the picked part
|
||||
partType = data['partTypes'][newPartIdx]
|
||||
|
||||
# gets the number of existing parts of that type the player has
|
||||
partCount = parts[newPartIdx]
|
||||
|
||||
logs.append(('rolled', newPartIdx, player))
|
||||
|
||||
# a new part can only be added if the player has the parts
|
||||
# the new part depends on and doesn't have enough of the part already
|
||||
overMaxParts = partType.count < partCount + 1
|
||||
missingPartDep = partType.depends != None and parts[partType.depends] == 0
|
||||
|
||||
if not overMaxParts and not missingPartDep:
|
||||
# adds a new part
|
||||
partCount += 1
|
||||
logs.append(('added', newPartIdx, player))
|
||||
partAdded = True
|
||||
@@ -115,13 +130,18 @@ def update_game(data, action):
|
||||
data['players'][player][newPartIdx] = partCount
|
||||
data['logs'] = logs
|
||||
|
||||
# checks if any players have finished their bug
|
||||
finished = get_finished(data)
|
||||
if len(finished) > 0:
|
||||
# and sets the state to 'won' if that's the case
|
||||
data['finished'] = finished
|
||||
data['state'] = 'won'
|
||||
return data
|
||||
|
||||
def get_finished(data):
|
||||
"""
|
||||
Gets players who have finished their bugs
|
||||
"""
|
||||
totalParts = sum([partType.count for partType in data['partTypes']])
|
||||
finished = []
|
||||
for player, parts in data['players'].items():
|
||||
@@ -129,6 +149,9 @@ def get_finished(data):
|
||||
return finished
|
||||
|
||||
def print_game(data):
|
||||
"""
|
||||
Displays the results of the game turn
|
||||
"""
|
||||
for log in data['logs']:
|
||||
code, partIdx, player, *logdata = log
|
||||
partType = data['partTypes'][partIdx]
|
||||
@@ -170,6 +193,9 @@ def print_game(data):
|
||||
return input("DO YOU WANT THE PICTURES? ") if len(data['logs']) else 'n'
|
||||
|
||||
def print_pictures(data):
|
||||
"""
|
||||
Displays what the bugs look like for each player
|
||||
"""
|
||||
typeIxs = { partType.name: idx for idx, partType in enumerate(data['partTypes']) }
|
||||
PIC_WIDTH = 22
|
||||
for player, parts in data['players'].items():
|
||||
@@ -205,6 +231,9 @@ def print_pictures(data):
|
||||
print()
|
||||
|
||||
def control_game(cmd):
|
||||
"""
|
||||
returns state based on command
|
||||
"""
|
||||
if cmd.lower() in ('y', 'yes'):
|
||||
action = 'pictures'
|
||||
else:
|
||||
@@ -212,14 +241,23 @@ def control_game(cmd):
|
||||
return action
|
||||
|
||||
def print_winner(data):
|
||||
"""
|
||||
Displays the winning message
|
||||
"""
|
||||
for player in data['finished']:
|
||||
print(f"{'YOUR' if 'YOU' == player else 'MY'} BUG IS FINISHED.")
|
||||
print("I HOPE YOU ENJOYED THE GAME, PLAY IT AGAIN SOON!!")
|
||||
|
||||
def exit_game(_):
|
||||
"""
|
||||
Exists the game regardless of input
|
||||
"""
|
||||
return 'exit'
|
||||
|
||||
def print_centered(msg, width=PAGE_WIDTH):
|
||||
"""
|
||||
Prints given message centered to given width
|
||||
"""
|
||||
spaces = " " * ((width - len(msg)) // 2)
|
||||
print(spaces + msg)
|
||||
|
||||
@@ -228,4 +266,45 @@ def print_table(rows):
|
||||
print(*row, sep="\t")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
# The main states in the game
|
||||
states = {
|
||||
# Initial state of the game
|
||||
'start': (print_start, control_start, update_state),
|
||||
|
||||
# displays game instructions
|
||||
'instructions': (print_instructions, goto_game, update_state),
|
||||
|
||||
# the main game state
|
||||
'game': (print_game, control_game, update_game),
|
||||
|
||||
# displays pictures before returning to game
|
||||
'pictures': (print_pictures, goto_game, update_state),
|
||||
|
||||
# Displays the winning players and message
|
||||
'won': (print_winner, exit_game, update_state)
|
||||
}
|
||||
|
||||
# body part types used by the game to work out whether a player's body part can be added
|
||||
partTypes = (
|
||||
Bodypart(name="BODY", count=1 , depends=None),
|
||||
Bodypart(name="NECK", count=1 , depends=0),
|
||||
Bodypart(name="HEAD", count=1 , depends=1),
|
||||
Bodypart(name="FEELERS", count=2 , depends=2),
|
||||
Bodypart(name="TAIL", count=1 , depends=0),
|
||||
Bodypart(name="LEGS", count=6 , depends=0)
|
||||
)
|
||||
|
||||
# all the data used by the game
|
||||
data = {
|
||||
'state': 'start',
|
||||
'partNo': None,
|
||||
'players': {
|
||||
'YOU': [0] * len(partTypes),
|
||||
'I': [0] * len(partTypes)
|
||||
},
|
||||
'partTypes': partTypes,
|
||||
'finished': [],
|
||||
'logs': []
|
||||
}
|
||||
main(states, data)
|
||||
Reference in New Issue
Block a user