-
Notifications
You must be signed in to change notification settings - Fork 13
Tutorial Part 1 Text Catan Game
In this tutorial, we are going to make a text interface for playing Catan with PyCatan
To start, download board_renderer.py from the examples folder. We'll eventually make our own, but for now let's just get the game up and running.
Now let's create a new file called text_game.py and add some skeleton comments:
from pycatan.game import Game
from board_renderer import BoardRenderer
if __name__ == "__main__":
# Starting phase
# Twice for each player
# Place a free settlement
# Place a free road connected to that settlement
# While the game is not won
# Roll the die
# Hand out appropriate resources
# Let this turn's player trade
# Let this turn's player build
# Announce winner
passRun python3 text_game.py to make sure the file runs. Now let's create a game of Catan.
if __name__ == "__main__":
# Create a new game of Catan
game = Game()Now let's make BoardRenderer use this game's board.
# Set up board to render
br = BoardRenderer(board=game.board, center=[50, 10])
# Draw the board
br.render()Now running python3 text_game.py should show the board, in ascii form. Let's add the starting phase, but first
let's quickly add a small helper method for reading integers from the user's input.
# Get an integer from standard input and return it
# If a non-integer value is entered, continue to prompt the user
def integer_input(str_prompt):
while True:
try:
return int(input(str_prompt))
except ValueError:
print("Please enter a valid integer")
continueNow let's add the starting phase of the game. Currently, we'll just add settlements.
# Starting phase
# Twice for each player
for p in game.players + list(reversed(game.players)):
# Render the board
br.render()
# Place a free settlement
with terminal.location(0, terminal.height - 1):
# Prompt the player for input
print("Player %s, it is your turn" % p.num)
while True:
# Get the row
row = integer_input("Enter the row you want to place the settlement: ")
# Get the index
index = integer_input("Enter the index you want to place your settlement: ")
# Try to build the settlement
res = game.add_settlement(player=p.num, r=row, i=index, is_starting=True)
# If invalid, just repeat
if res != Statuses.ALL_GOOD:
continueNow running the code should allow users to place their starting settlements. Let's add roads:
# If invalid, just repeat
if res != Statuses.ALL_GOOD:
continue
# Place a free road connected to that settlement
points = game.board.points[row][index].connected_points
# Render the board
br.render()
# Loop while road input is invalid
while True:
with terminal.location(0, terminal.height - 1):
print("Please choose from one of the following points to build your road to:")
# Go through valid points
for i in range(len(points)):
# Print each point as an option
print("%s. %s" % (i, points[i].position))
# Prompt user to chose a point
choice = integer_input("Which point do you want to build your road to? ")
# Ensure choice is valid
if choice < 0 or choice > len(points) - 1:
print("Please choose a valid option")
else:
# Add the road
res = game.add_road(player=p.num, start=[row, index], end=points[choice].position, is_starting=True)
# If successful, break the loop and go to the next player
if res == Statuses.ALL_GOOD:
break
# Break from outer loop, so that the next player is prompted:w
breakGreat, now players should be able to add their settlements and roads at the beginning of the game. However, if they enter an invalid position for a settlement, the game doesn't tell them why it's invalid. PyCatan will return several different Statuses for different reasons why a placement is invalid. Let's use these to tell the player why their settlement position is invalid:
# Try to build the settlement
res = game.add_settlement(player=p.num, r=row, i=index, is_starting=True)
# If invalid, tell the player why and allow them to re-enter a position
if res != Statuses.ALL_GOOD:
if res == Statuses.ERR_BLOCKED:
print("Another settlement is too close for you to build a settlement there!")
elif res == Statuses.ERR_BAD_POINT:
print("The point %s is not on the board!" % [row, index])
else:
# These are the only 2 errors that should run during the building phase, so something went terribly wrong
print("An internal error occured. res = %s." % res)
# Repeat the loop to allow the user to reenter the position
continue
# Code here will execute if the settlement position is correctGreat. Now let's add road building right after, assuming the player entered their settlement correctly
# Code here will execute if the settlement position is correct
# Place a free road connected to that settlement
points = game.board.points[row][index].connected_points
# Render the board
br.render()
# Loop while road input is invalid
while True:
with terminal.location(0, terminal.height - 1):
print("Please choose from one of the following points to build your road to:")
# Go through valid points
for i in range(len(points)):
# Print each point as an option
print("%s. %s" % (i, points[i].position))
# Prompt user to chose a point
choice = integer_input("Which point do you want to build your road to? ")
# Ensure choice is valid
if choice < 0 or choice > len(points) - 1:
print("Please choose a valid option")
else:
# Add the road
res = game.add_road(player=p.num, start=[row, index], end=points[choice].position, is_starting=True)
# If successful, break the loop and go to the next player
if res == Statuses.ALL_GOOD:
break
# Break from outer loop, so that the next player is prompted
break