Writing a chess game in python [Day 1]
Tags: python, codenewbie
Published: 2020-10-06 07:25:45

We're in lockdown due to COVID-19, and it's a holiday (no school, not even zoom). So I decided to take a week off work and wind down, spend some time with the kids. And really, what better use of my time than to implement a small code project with my son? He's studying python at school, but they haven't gotten many classes in (remember COVID-19?) and aren't much past `print`, this could be an excellent opportunity for him to up his game and I get to write a cool blog-post series!!! Total win-win situation.

He's been into chess lately, so I asked if he wanted to implement a textual chess game and he seemed genuinely excited (pretty sure he was _not_ faking it). 

In this series I'll be going through how we implemented the game day by day. Remember that this is a 12 year old and I'm trying to use this as a teaching opportunity, I _promise_ you by the end we'll have everything implemented with well structured and nicely optimized code, but I chose to start with a naive approach, arriving at conclusions on how to do things better together instead of me applying everything I already know upfront. I'm pretty cerntain we _will_ end up with an undo/redo/replay game using command pattern, I know it even if he doesn't yet. Anyway, seeing the process is _totally_ part of the fun.

I hope you enjoy this series, now let's dive in!

---

The first thing I did was to ask him what the basic building blocks of a chess game would be. He said that we should probably start with the board. As I mentioned, he'd learned `print` so we tried to "brute force" the board by printing lines and columns:
```
print("-------------------------")
print("|  |  |  |  |  |  |  |  |  |")
```
Not too bad:
```
-------------------------
|  |  |  |  |  |  |  |  |  |
```
Apparently he already new about string duplication with `*`, _and_ about using the `end` parameter so we changed it to:
```
print("-"*25)
print("|  "*8, end="|\n")
```
The code was prettier, but the output was still only one row! We needed 8. He already knew about loops, but didn't have experience with python syntax so I helped him out there and we came up with:
```
for x in range(8):
  print("-"*25)
  print("|  "*8, end="|\n")
```
We noticed we were missing the closing row so we added:
```
print("-"*25)
```
after the loop.
Look! We have a board.
```
-------------------------
|  |  |  |  |  |  |  |  |
-------------------------
|  |  |  |  |  |  |  |  |
-------------------------
|  |  |  |  |  |  |  |  |
-------------------------
|  |  |  |  |  |  |  |  |
-------------------------
|  |  |  |  |  |  |  |  |
-------------------------
|  |  |  |  |  |  |  |  |
-------------------------
|  |  |  |  |  |  |  |  |
-------------------------
|  |  |  |  |  |  |  |  |
-------------------------
```
OK, this is nice - but if we want to be able to actually play, we need some kind of data structure to store information about the board status.

12yo knows about arrays, but reasoning about a two dimensional array was a bit of a jump, so I described it as a _list of lists_ and that worked. So here's the code we started writing:

```
board = []
for i in range(8):
  row = []
  for j in range(8):
    row.append(None)
  board.append(row)
```

At this point I wasn't sure if this would be the best teaching approach - but I just _couldn't_ leave those awful nested for loops as they were, so I taught him this shorthand list comprehension:
```
board = [[None]*8]*8
```
I started explaining what I was doing here, but turns out since he was already familiar with this type of syntax from strings - he just understood what was going on (lucky me!).
Now we had to change the way we print the board to... actually print the board instead of hard-coded strings.
We defined the following method:
```
def print_board(board):
  for row in board:
    print("-"*25)
    for column in row:
       print("|{}".format(column), end="")
    print("|")
  print("-"*25)

board = [[None]*8]*8

print_board(board)
```
Output:
```
-------------------------
|None|None|None|None|None|None|None|None|
-------------------------
|None|None|None|None|None|None|None|None|
-------------------------
|None|None|None|None|None|None|None|None|
-------------------------
|None|None|None|None|None|None|None|None|
-------------------------
|None|None|None|None|None|None|None|None|
-------------------------
|None|None|None|None|None|None|None|None|
-------------------------
|None|None|None|None|None|None|None|None|
-------------------------
|None|None|None|None|None|None|None|None|
-------------------------
```
OK... let's add the pieces onto the board.
We decided to use the standard one letter for each piece, and add the color `W` or `B` as a prefix.
We added:
```
board[0] = ["BR","BN","BB","BQ","BK","BB","BN","BR"]
board[1] = ["BP","BP","BP","BP","BP","BP","BP","BP"]
board[6] = ["BP","BP","BP","BP","BP","BP","BP","BP"]
board[7] = ["BR","BN","BB","BQ","BK","BB","BN","BR"]
```
Output now is totally out of balance:
```
-------------------------
|BR|BN|BB|BQ|BK|BB|BN|BR|
-------------------------
|BP|BP|BP|BP|BP|BP|BP|BP|
-------------------------
|None|None|None|None|None|None|None|None|
-------------------------
|None|None|None|None|None|None|None|None|
-------------------------
|None|None|None|None|None|None|None|None|
-------------------------
|None|None|None|None|None|None|None|None|
-------------------------
|BP|BP|BP|BP|BP|BP|BP|BP|
-------------------------
|BR|BN|BB|BQ|BK|BB|BN|BR|
-------------------------
```
12yo pointed out we should have row numbers and column letters, so we added those and changed the `None` value to   two whitespaces so it would line up nicely. After a few tweaks we landed on:
```
def print_board(board):
    row_number = 8
    print("  ", end="")
    print(" ----"*8)
    for row in board:
        print(row_number, end=" ")
        row_number -= 1
        for cell in row:
            print("| {} ".format(cell), end="")
        print("|")
        print("  ", end="")
        print(" ----"*8)
    print("  ", end="")
    for letter in ['a','b','c','d','e','f','g','h']:
        print("  {}  ".format(letter), end="")
    print("")

board = [["  "]*8]*8
board[0] = ["BR","BN","BB","BQ","BK","BB","BN","BR"]
board[1] = ["BP","BP","BP","BP","BP","BP","BP","BP"]
board[6] = ["BP","BP","BP","BP","BP","BP","BP","BP"]
board[7] = ["BR","BN","BB","BQ","BK","BB","BN","BR"]

print_board(board)
```
Output:
```
   ---- ---- ---- ---- ---- ---- ---- ----
8 | BR | BN | BB | BQ | BK | BB | BN | BR |
   ---- ---- ---- ---- ---- ---- ---- ----
7 | BP | BP | BP | BP | BP | BP | BP | BP |
   ---- ---- ---- ---- ---- ---- ---- ----
6 |    |    |    |    |    |    |    |    |
   ---- ---- ---- ---- ---- ---- ---- ----
5 |    |    |    |    |    |    |    |    |
   ---- ---- ---- ---- ---- ---- ---- ----
4 |    |    |    |    |    |    |    |    |
   ---- ---- ---- ---- ---- ---- ---- ----
3 |    |    |    |    |    |    |    |    |
   ---- ---- ---- ---- ---- ---- ---- ----
2 | BP | BP | BP | BP | BP | BP | BP | BP |
   ---- ---- ---- ---- ---- ---- ---- ----
1 | BR | BN | BB | BQ | BK | BB | BN | BR |
   ---- ---- ---- ---- ---- ---- ---- ----
    a    b    c    d    e    f    g    h  
```
And that was it for the day.

---

Tune in next time to see how we're doing!