Learning Pygame with Catan (Part 1)
An Intro to Catan
Who else here used to play Settlers of Catan as a kid? The first memory I have with the game is happily placing roads down, not realizing I was supposed to pay for them with resources. It went on for way too long before my friends yelled at me for cheating! But I was just a noob. Nowadays, I love playing Catan Universe on Steam whenever I can.
If you haven't played, or need a bit of a refresher, let's go over the game real fast.
This is a board game dictated by each playing taking turns rolling a pair of dice. The board is a hexagonal grid, with each hex representing one of five resources:
Wood, Brick, Wool, Wheat, Ore.
There's also one desert tile. On each hex is a number tile, with numbers between 2 and 12. Here's an example:
Each player has certain pieces they can place on the intersections of the hexes:
Settlements, roads, cities.
Each player takes turns placing a settlement and a road on the hexes, with each player placing a total of two settlements and two roads before the game starts.
When the player rolls the dice, we add up the results, and any players with a settlement on a hex with that number tile will get one of those resources. If you have a city on that hex, you get 2 of that resource! Placing settlements, roads, and cities costs resources, so we get a cycle of gaining and using resources. With the board above as an example, if the player rolls a 2 and 3, then that's a 5 and red would get 1 brick and 1 wheat, and yellow would get 1 wheat.
How does the game end? Each settlement placed gives the player one point and each city placed gives the player two points. The first player to 13 points wins - it's that easy!
The final thing we need to address are the harbors. During the game, we can trade resources with other players or with the bank at a 4:1 ratio. There is one harbor for each resource and four ? harbors. If you build a settlement/city on a resource harbor, you can trade that resource 2:1 instead of 4:1. And if you build on a ? harbor, then you can trade any resource 3:1.
Our motivation to program
As you play Catan more and more, you realize that the choice you make for the first two settlements REALLY matters when it comes to the outcome of the game. There are a lot of things to consider:
How much of each resource can I expect to get?
How often can I expect to get any resource?
Are there "nice" clusters of numbers and resources?
Are there any harbor spots that mesh well with the resource tiles?
Instead of analyzing each board as they come, let's try to write a program that takes a board as input and outputs all the information we want to know. This will help inform our choice of placement...and also will be a fun excuse to learn some Python!
Specifically, we'll use the Pygame library in Python, which will set us up with lots of tools to make a game! To even get started, we first need to open up our text editor and compiler. I will use the editor that you get when you download python called IDLE. Once you open this, you'll see the shell, and you can go to File -> New File to create a new text file which will contain all our python code.
Now you'll see a blank document, where we can set up our code before we begin writing anything specific to our program. We first need to import pygame and initiate it:
import pygame pygame.init()
We then set a screen size and a caption for our screen using pygame.display:
screen_w = 800 screen_h = 800 screen = pygame.display.set_mode((screen_w,screen_h)) pygame.display.set_caption("Catan Analyzer")
To run our code, you can go to Run -> Run Module or just do the keyboard shortcut fn + f5. It will prompt you to save the file first - I called mine CatanAnalyzer! Once you do that, you'll see a black screen with your chosen caption:
To actually display anything, we need to set up our main loop. This will keep the computer constantly checking user input and updating what we see. To get a loop that goes until we explicitly tell it to stop, we set a variable to always be true and then set a loop to go while that variable is true.
run = True while run: #write program code
Obviously we need to fill in the important bit, but notice that I started "write program code" with a #. This indicates to the computer that everything that comes after it will be a comment by the writer to other human readers, and should be ignored by the computer.
One of the first things you'll notice is that if you click on the "x", nothing happens! This is because we need to explicitly tell the computer how to react.
THIS IS THE KEY TO EVERYTHING WE DO!
Every aspect of our game will be controlled by us looking at the computer events and telling the computer how to respond to those events. A fun way to get familiar with the type of events (other than looking at the pygame.event documentation) is by printing out the events and then clicking on the screen, pressing keys, etc.
run = True while run: for event in pygame.event.get(): print(event)
The shell is where all the computer output will be sent, which will be helpful in figuring out what the computer is doing. Pretty much, for every part of our program, we can inject a "print(blah)" to get a view of what the computer sees at that point.
Here is an example. You see some initial events are the computer setting up the screen, and it also registers an event for each mouse movement, button click, key click.
In particular, CLICKING THE "X" BUTTON IS AN EVENT! So let's tell the computer to close our program if that event is triggered.
run = True while run: for event in pygame.event.get(): if event.type == pygame.QUIT: run = False pygame.quit()
So we set run = True, and let the loop run while run is True. So if the event type is "pygame.QUIT", meaning the user clicked the "x", we change run to False, which will stop the loop. Once the loop stops, the computer moves on and executes the pygame.quit() command. Then the screen is closed!
We'll get heavier into the code next time, but let's at least change what we see a little bit. Outside of the event loop, we can choose to fill the screen with a particular color (written as its RGB values), and draw a circle. Outside of the main loop, we'll add a color definition
brown = pygame.Color(193,154,107)
And then fill the screen with this color by adding
inside of the main loop but outside of the event loop, since we want the background to be wood brown regardless of the event.
If you run this code, you'll still see a black screen! This is because we, again, need to explicitly tell the computer to update the display. We do this by adding pygame.display.flip() at the end of our main loop.
For a bit of flair, we can draw a circle with
pygame.draw.circle(surface, color, center, radius)
The surface we're drawing on is screen, and maybe we'll define two new colors red = pygame.Color(255,0,0) and blue = pygame.Color(0,0,255) and draw TWO circles! We'll center them at the middle of the screen, and have one of radius 20, and the other radius 50. The final code and output is:
Thank you for reading!