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