mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-22 07:10:42 -08:00
Removed spaces from top-level directory names.
Spaces tend to cause annoyances in a Unix-style shell environment. This change fixes that.
This commit is contained in:
3
08_Batnum/python/README.md
Normal file
3
08_Batnum/python/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Conversion to [Python](https://www.python.org/about/)
|
||||
159
08_Batnum/python/batnum.py
Normal file
159
08_Batnum/python/batnum.py
Normal file
@@ -0,0 +1,159 @@
|
||||
from enum import Enum
|
||||
|
||||
class WinOptions(Enum):
|
||||
Undefined = 0
|
||||
TakeLast = 1
|
||||
AvoidLast = 2
|
||||
|
||||
class StartOptions(Enum):
|
||||
Undefined = 0
|
||||
ComputerFirst = 1
|
||||
PlayerFirst = 2
|
||||
|
||||
def PrintIntro():
|
||||
'''Prints out the introduction and rules for the game.'''
|
||||
print("BATNUM".rjust(33, ' '))
|
||||
print("CREATIVE COMPUTING MORRISSTOWN, NEW JERSEY".rjust(15, ' '))
|
||||
print()
|
||||
print()
|
||||
print()
|
||||
print("THIS PROGRAM IS A 'BATTLE OF NUMBERS' GAME, WHERE THE")
|
||||
print("COMPUTER IS YOUR OPPONENT.")
|
||||
print()
|
||||
print("THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU")
|
||||
print( "AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE.")
|
||||
print("WINNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR")
|
||||
print("NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINNING CONDITIONS.")
|
||||
print("DON'T USE ZERO, HOWEVER, IN PLAYING THE GAME.")
|
||||
print("ENTER A NEGATIVE NUMBER FOR NEW PILE SIZE TO STOP PLAYING.")
|
||||
print()
|
||||
return
|
||||
|
||||
def GetParams():
|
||||
'''This requests the necessary parameters to play the game.
|
||||
|
||||
Returns a set with the five game parameters:
|
||||
pileSize - the starting size of the object pile
|
||||
minSelect - minimum selection that can be made on each turn
|
||||
maxSelect - maximum selection that can be made on each turn
|
||||
startOption - 1 if the computer is first
|
||||
or 2 if the player is first
|
||||
winOption - 1 if the goal is to take the last object
|
||||
or 2 if the goal is to not take the last object
|
||||
'''
|
||||
pileSize = 0
|
||||
winOption = WinOptions.Undefined
|
||||
minSelect = 0
|
||||
maxSelect = 0
|
||||
startOption = StartOptions.Undefined
|
||||
|
||||
while pileSize < 1:
|
||||
pileSize = int(input("ENTER PILE SIZE "))
|
||||
while winOption == WinOptions.Undefined:
|
||||
winOption = int(input("ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST: "))
|
||||
while minSelect < 1 or maxSelect < 1 or minSelect > maxSelect:
|
||||
(minSelect, maxSelect) = [int(x) for x in input("ENTER MIN AND MAX ").split(' ')]
|
||||
while startOption == StartOptions.Undefined:
|
||||
startOption = int(input("ENTER START OPTION - 1 COMPUTER FIRST, 2 YOU FIRST "))
|
||||
return (pileSize, minSelect, maxSelect, startOption, winOption)
|
||||
|
||||
def PlayerMove(pileSize, minSelect, maxSelect, startOption, winOption):
|
||||
'''This handles the player's turn - asking the player how many objects
|
||||
to take and doing some basic validation around that input. Then it
|
||||
checks for any win conditions.
|
||||
|
||||
Returns a boolean indicating whether the game is over and the new pileSize.'''
|
||||
playerDone = False
|
||||
while not playerDone:
|
||||
playerMove = int(input("YOUR MOVE "))
|
||||
if playerMove == 0:
|
||||
print ("I TOLD YOU NOT TO USE ZERO! COMPUTER WINS BY FORFEIT.")
|
||||
return (True, pileSize)
|
||||
if playerMove > maxSelect or playerMove < minSelect:
|
||||
print("ILLEGAL MOVE, REENTER IT")
|
||||
continue
|
||||
pileSize = pileSize - playerMove
|
||||
playerDone = True
|
||||
if pileSize <= 0:
|
||||
if winOption == WinOptions.AvoidLast:
|
||||
print("TOUGH LUCK, YOU LOSE.")
|
||||
else:
|
||||
print("CONGRATULATIONS, YOU WIN.")
|
||||
return (True, pileSize)
|
||||
return (False, pileSize)
|
||||
|
||||
def ComputerPick(pileSize, minSelect, maxSelect, startOption, winOption):
|
||||
'''This handles the logic to determine how many objects the computer
|
||||
will select on its turn.
|
||||
'''
|
||||
q = pileSize - 1 if winOption == WinOptions.AvoidLast else pileSize
|
||||
c = minSelect + maxSelect
|
||||
computerPick = q - (c * int(q / c))
|
||||
if computerPick < minSelect:
|
||||
computerPick = minSelect
|
||||
if computerPick > maxSelect:
|
||||
computerPick = maxSelect
|
||||
return computerPick
|
||||
|
||||
def ComputerMove(pileSize, minSelect, maxSelect, startOption, winOption):
|
||||
'''This handles the computer's turn - first checking for the various
|
||||
win/lose conditions and then calculating how many objects
|
||||
the computer will take.
|
||||
|
||||
Returns a boolean indicating whether the game is over and the new pileSize.'''
|
||||
# First, check for win conditions on this move
|
||||
# In this case, we win by taking the last object and
|
||||
# the remaining pile is less than max select
|
||||
# so the computer can grab them all and win
|
||||
if winOption == WinOptions.TakeLast and pileSize <= maxSelect:
|
||||
print (f"COMPUTER TAKES {pileSize} AND WINS.")
|
||||
return (True, pileSize)
|
||||
# In this case, we lose by taking the last object and
|
||||
# the remaining pile is less than minsize and the computer
|
||||
# has to take all of them.
|
||||
if winOption == WinOptions.AvoidLast and pileSize <= minSelect:
|
||||
print (f"COMPUTER TAKES {minSelect} AND LOSES.")
|
||||
return (True, pileSize)
|
||||
|
||||
# Otherwise, we determine how many the computer selects
|
||||
currSel = ComputerPick(pileSize, minSelect, maxSelect, startOption, winOption)
|
||||
pileSize = pileSize - currSel
|
||||
print(f"COMPUTER TAKES {currSel} AND LEAVES {pileSize}")
|
||||
return (False, pileSize)
|
||||
|
||||
def PlayGame(pileSize, minSelect, maxSelect, startOption, winOption):
|
||||
'''This is the main game loop - repeating each turn until one
|
||||
of the win/lose conditions is met.
|
||||
'''
|
||||
gameOver = False
|
||||
# playersTurn is a boolean keeping track of whether it's the
|
||||
# player's or computer's turn
|
||||
playersTurn = startOption == StartOptions.PlayerFirst
|
||||
|
||||
while not gameOver:
|
||||
if playersTurn:
|
||||
(gameOver, pileSize) = PlayerMove(pileSize, minSelect, maxSelect, startOption, winOption)
|
||||
playersTurn = False
|
||||
if gameOver:
|
||||
return
|
||||
if not playersTurn:
|
||||
(gameOver, pileSize) = ComputerMove(pileSize, minSelect, maxSelect, startOption, winOption)
|
||||
playersTurn = True
|
||||
|
||||
return
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
pileSize = 0
|
||||
minSelect = 0
|
||||
maxSelect = 0
|
||||
# 1 = to take last, 2 = to avoid last
|
||||
winOption = 0
|
||||
# 1 = computer first, 2 = user first
|
||||
startOption = 0
|
||||
|
||||
while True:
|
||||
PrintIntro()
|
||||
(pileSize, minSelect, maxSelect, startOption, winOption) = GetParams()
|
||||
# Just keep playing the game until the user kills it with ctrl-C
|
||||
PlayGame(pileSize, minSelect, maxSelect, startOption, winOption)
|
||||
Reference in New Issue
Block a user