mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-22 23:26:40 -08:00
Port Batnum to Python and VB
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,5 @@
|
|||||||
*/.vs
|
*/.vs
|
||||||
|
*.suo
|
||||||
|
|
||||||
bin/
|
bin/
|
||||||
obj/
|
obj/
|
||||||
|
|||||||
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)
|
||||||
199
08 Batnum/vbnet/Program.vb
Normal file
199
08 Batnum/vbnet/Program.vb
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
Imports System
|
||||||
|
|
||||||
|
Module BatNum
|
||||||
|
Enum WinOptions
|
||||||
|
Undefined = 0
|
||||||
|
TakeLast = 1
|
||||||
|
AvoidLast = 2
|
||||||
|
End Enum
|
||||||
|
|
||||||
|
Enum StartOptions
|
||||||
|
Undefined = 0
|
||||||
|
ComputerFirst = 1
|
||||||
|
PlayerFirst = 2
|
||||||
|
End Enum
|
||||||
|
|
||||||
|
Dim pileSize As Integer = 0
|
||||||
|
Dim minSelect As Integer = 0
|
||||||
|
Dim maxSelect As Integer = 0
|
||||||
|
Dim startOption As StartOptions = StartOptions.Undefined
|
||||||
|
Dim winOption As WinOptions = WinOptions.Undefined
|
||||||
|
|
||||||
|
' <summary>
|
||||||
|
' Prints the intro and rules of the game.
|
||||||
|
' </summary>
|
||||||
|
Private Sub PrintIntro()
|
||||||
|
Console.WriteLine("BATNUM".PadLeft(33, " "))
|
||||||
|
Console.WriteLine("CREATIVE COMPUTING MORRISSTOWN, NEW JERSEY".PadLeft(15, " "))
|
||||||
|
Console.WriteLine()
|
||||||
|
Console.WriteLine()
|
||||||
|
Console.WriteLine()
|
||||||
|
Console.WriteLine("THIS PROGRAM IS A 'BATTLE OF NUMBERS' GAME, WHERE THE")
|
||||||
|
Console.WriteLine("COMPUTER IS YOUR OPPONENT.")
|
||||||
|
Console.WriteLine()
|
||||||
|
Console.WriteLine("THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU")
|
||||||
|
Console.WriteLine("AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE.")
|
||||||
|
Console.WriteLine("WINNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR")
|
||||||
|
Console.WriteLine("NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINNING CONDITIONS.")
|
||||||
|
Console.WriteLine("DON'T USE ZERO, HOWEVER, IN PLAYING THE GAME.")
|
||||||
|
Console.WriteLine("ENTER A NEGATIVE NUMBER FOR NEW PILE SIZE TO STOP PLAYING.")
|
||||||
|
Console.WriteLine()
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
' <summary>
|
||||||
|
' Asks the user for the various parameters necessary
|
||||||
|
' to play the game.
|
||||||
|
' </summary>
|
||||||
|
Private Sub GetParams()
|
||||||
|
' Reset the game parameters
|
||||||
|
pileSize = 0
|
||||||
|
minSelect = 0
|
||||||
|
maxSelect = 0
|
||||||
|
startOption = StartOptions.Undefined
|
||||||
|
winOption = WinOptions.Undefined
|
||||||
|
|
||||||
|
While pileSize < 1
|
||||||
|
Console.Write("ENTER PILE SIZE ")
|
||||||
|
pileSize = Convert.ToInt32(Console.ReadLine())
|
||||||
|
End While
|
||||||
|
While winOption = WinOptions.Undefined
|
||||||
|
Console.Write("ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST: ")
|
||||||
|
winOption = Convert.ToInt32(Console.ReadLine())
|
||||||
|
End While
|
||||||
|
While minSelect < 1 Or maxSelect < 1 Or minSelect > maxSelect
|
||||||
|
Console.Write("ENTER MIN AND MAX ")
|
||||||
|
Dim vals = Console.ReadLine().ToString().Split(" ").[Select](Function(n) Integer.Parse(n)).ToList()
|
||||||
|
If vals.Count() <> 2 Then
|
||||||
|
Continue While
|
||||||
|
End If
|
||||||
|
minSelect = vals(0)
|
||||||
|
maxSelect = vals(1)
|
||||||
|
End While
|
||||||
|
While startOption = StartOptions.Undefined
|
||||||
|
Console.Write("ENTER START OPTION - 1 COMPUTER FIRST, 2 YOU FIRST ")
|
||||||
|
startOption = Convert.ToInt32(Console.ReadLine())
|
||||||
|
End While
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
'<summary>
|
||||||
|
'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.
|
||||||
|
'</summary>
|
||||||
|
'<returns>Returns a Boolean indicating whether the game Is over And the New pileSize.</returns>'
|
||||||
|
Private Function PlayerMove() As Boolean
|
||||||
|
Dim playerDone As Boolean = False
|
||||||
|
|
||||||
|
While Not playerDone
|
||||||
|
Console.WriteLine("YOUR MOVE ")
|
||||||
|
Dim playerNum As Integer = Convert.ToInt32(Console.ReadLine())
|
||||||
|
If playerNum = 0 Then
|
||||||
|
Console.WriteLine("I TOLD YOU NOT TO USE ZERO! COMPUTER WINS BY FORFEIT.")
|
||||||
|
Return True
|
||||||
|
End If
|
||||||
|
If playerNum > maxSelect Or playerNum < minSelect Then
|
||||||
|
Console.WriteLine("ILLEGAL MOVE, REENTER IT")
|
||||||
|
Continue While
|
||||||
|
End If
|
||||||
|
|
||||||
|
pileSize = pileSize - playerNum
|
||||||
|
playerDone = True
|
||||||
|
If pileSize <= 0 Then
|
||||||
|
If winOption = WinOptions.AvoidLast Then
|
||||||
|
Console.WriteLine("TOUGH LUCK, YOU LOSE.")
|
||||||
|
Else
|
||||||
|
Console.WriteLine("CONGRATULATIONS, YOU WIN.")
|
||||||
|
End If
|
||||||
|
Return True
|
||||||
|
End If
|
||||||
|
End While
|
||||||
|
|
||||||
|
Return False
|
||||||
|
End Function
|
||||||
|
|
||||||
|
'<summary>
|
||||||
|
'This handles the logic to determine how many objects the computer
|
||||||
|
'will select on its turn.
|
||||||
|
'</summary>
|
||||||
|
Private Function ComputerPick() As Integer
|
||||||
|
Dim q As Integer = IIf(winOption = WinOptions.AvoidLast, pileSize - 1, pileSize)
|
||||||
|
Dim c As Integer = minSelect + maxSelect
|
||||||
|
Dim computerNum As Integer = q - (c * Int(q / c))
|
||||||
|
If computerNum < minSelect Then
|
||||||
|
computerNum = minSelect
|
||||||
|
End If
|
||||||
|
If computerNum > maxSelect Then
|
||||||
|
ComputerPick = maxSelect
|
||||||
|
End If
|
||||||
|
|
||||||
|
Return computerNum
|
||||||
|
End Function
|
||||||
|
|
||||||
|
'<summary>
|
||||||
|
'This handles the computer's turn - first checking for the various
|
||||||
|
'win/lose conditions And then calculating how many objects
|
||||||
|
'the computer will take.
|
||||||
|
'</summary>
|
||||||
|
'<returns>Returns a boolean indicating whether the game is over.</returns>'
|
||||||
|
Private Function ComputerMove() As Boolean
|
||||||
|
' 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 Then
|
||||||
|
Console.WriteLine($"COMPUTER TAKES {pileSize} AND WINS.")
|
||||||
|
Return True
|
||||||
|
End If
|
||||||
|
' 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 Then
|
||||||
|
Console.WriteLine($"COMPUTER TAKES {minSelect} AND LOSES.")
|
||||||
|
Return True
|
||||||
|
End If
|
||||||
|
|
||||||
|
' Otherwise, we determine how many the computer selects
|
||||||
|
Dim currSel As Integer = ComputerPick()
|
||||||
|
pileSize = pileSize - currSel
|
||||||
|
Console.WriteLine($"COMPUTER TAKES {currSel} AND LEAVES {pileSize}")
|
||||||
|
Return False
|
||||||
|
End Function
|
||||||
|
|
||||||
|
'<summary>
|
||||||
|
'This is the main game loop - repeating each turn until one
|
||||||
|
'of the win/lose conditions Is met.
|
||||||
|
'</summary>
|
||||||
|
Private Sub PlayGame()
|
||||||
|
Dim gameOver As Boolean = False
|
||||||
|
' playersTurn Is a Boolean keeping track Of whether it's the
|
||||||
|
' player's or computer's turn
|
||||||
|
Dim playersTurn As Boolean = (startOption = StartOptions.PlayerFirst)
|
||||||
|
|
||||||
|
While Not gameOver
|
||||||
|
If playersTurn Then
|
||||||
|
gameOver = PlayerMove()
|
||||||
|
playersTurn = False
|
||||||
|
If gameOver Then Return
|
||||||
|
End If
|
||||||
|
|
||||||
|
If Not playersTurn Then
|
||||||
|
gameOver = ComputerMove()
|
||||||
|
playersTurn = True
|
||||||
|
End If
|
||||||
|
End While
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Public Sub Play()
|
||||||
|
While True
|
||||||
|
PrintIntro()
|
||||||
|
GetParams()
|
||||||
|
PlayGame()
|
||||||
|
End While
|
||||||
|
End Sub
|
||||||
|
End Module
|
||||||
|
|
||||||
|
Module Program
|
||||||
|
Sub Main(args As String())
|
||||||
|
BatNum.Play()
|
||||||
|
End Sub
|
||||||
|
End Module
|
||||||
25
08 Batnum/vbnet/batnum.sln
Normal file
25
08 Batnum/vbnet/batnum.sln
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 16
|
||||||
|
VisualStudioVersion = 16.0.31321.278
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "batnum", "batnum.vbproj", "{D577E429-F84D-4E84-86E7-E6526CFD5FD9}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{D577E429-F84D-4E84-86E7-E6526CFD5FD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{D577E429-F84D-4E84-86E7-E6526CFD5FD9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{D577E429-F84D-4E84-86E7-E6526CFD5FD9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{D577E429-F84D-4E84-86E7-E6526CFD5FD9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {426DF7FE-66E7-4319-9AD8-7A2DD3964A2F}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
9
08 Batnum/vbnet/batnum.vbproj
Normal file
9
08 Batnum/vbnet/batnum.vbproj
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<RootNamespace>batnum</RootNamespace>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
Reference in New Issue
Block a user