Topics Covered: Tic-tac-toe
This exercise is actually more of a mini-project: we're going to work through building a simple tic-tac-toe application from scratch. Pick a partner who you haven't worked with before, create tictactoe.rb
in d4
and let's get started.
As usual, we're going to plan out our approach before we start coding away. Read the following carefully—your program must do the following:
The player input will be an integer from 0-8 and the squares will be numbered top-left to bottom-right (0 is the top-left square, 2 is the top-right square, 4 is the middle square, and 8 is the bottom-right square).
In tictactoe.rb
, answer the following questions:
# tictactoe.rb
# How will you keep track of whose turn it is?
# What data structure will you use to keep track of the board? You only
# know two (Array, Hash), but remember they can be nested (meaning an
# array can contain another array—it can even contain a hash that contains
# another hash, though unclear if that will be useful :P)
# When a player makes a move, what should happen?
# How do you keep track of which squares have Xs and which have Os?
# How do you detect a winner?
# When does the program stop? Is there a loop? If so, what kind?
Pseudo-code is an informal, high-level description of your program's operation. Pseudo-code is written in english and outlines your program's behavior using step by step instructions. An example for tic-tac-toe:
# Every turn:
# Update whose turn it is
# Get user input
# Update board
# Check for winner
Of course, that's pretty easy to write. However, it may be less obvious how you would translate pseudo-code into good ol' Ruby. What exactly is a turn? How does one update the board? These are questions you've started thinking about in Step 1. For Step 2, expand your thinking, and the above pseudo-code, to make a more detailed outline. That is, your writing may contain words like "Array" and "Hash", but probably doesn't contain any "[" or "{" glyphs. As you write, consider these questions, and be ready to answer them:
It may be starting to become clear that coding is much more about thinking than anything else. While there isn't necessarily a best solution, there are solutions that are much more intuitive and easier to understand than others. Remember that code is meant to be read by humans, and when two pieces of code do the same thing with the same efficiency, the one that's simpler is always better.
Check in with a TA before continuing!
Now that you have your pseudo-code, it should be a simple matter to turn it into real code. Take a crack at it, and see if it works!
$ ruby tictactoe.rb
Player 1:
0
Player 2:
1
Player 1:
kittens
Error: Invalid input
Player 1:
10
Error: Invalid input
Player 1:
3
Player 2:
2
Player 1:
2
Error: Square already taken
Player 1:
6
Congrats, player 1 won!
If you've gotten this far, you actually know quite a bit about coding, and the coding process. This was actually a Google coding interview problem (though keep that fact hush hush!). When you interview at companies—or try to code anything, really—this workflow is a good one to keep in mind: first talk through your solution and think about what data structures you'll use. Then write pseudo-code and try to foresee as many problems as you can. Only when you're confident in your thinking should you start coding.
To be honest, while your program is pretty awesome, it's not very user friendly. Since humans aren't very good at remembering what the board looks like, add a method to print out the board after each step. We've picked a design below, but feel free to make it look like however you want.
$ ruby tictactoe.rb
Player 1:
4
| |
———+———+———
| X |
———+———+———
| |
Player 2:
0
O | |
———+———+———
| X |
———+———+———
| |
Player 1:
2
O | | X
———+———+———
| X |
———+———+———
| |
Player 2:
6
O | | X
———+———+———
| X |
———+———+———
O | |
Player 1:
3
O | | X
———+———+———
X | X |
———+———+———
O | |
Player 2:
5
O | | X
———+———+———
X | X | O
———+———+———
O | |
Player 1:
1
O | X | X
———+———+———
X | X | O
———+———+———
O | |
Player 2:
7
O | X | X
———+———+———
X | X | O
———+———+———
O | O |
Player 1:
8
O | X | X
———+———+———
X | X | O
———+———+———
O | O | X
Cats game!
Now that you've mastered the basics of tic-tac-toe, it's time to move on to bigger and better things. Choose one of the following extension projects:
Change your game into EXTREME tic-tac-toe, AKA 4x4 tic-tac-toe (Guru difficulty)
Think about what kind of changes you will need to make to your program by following the steps you used for making the first game. Plan, pseudo-code, code, repeat!
Create Connect Four (Chosen One difficulty)
Recreate the (awesome) two-player sensation from the 70s. Think about the different rules that you will need for this game as opposed to regular tic-tac-toe, e.g. can a player put a disc wherever they want?
While playing against a person is fun, us loners need something to do. Write a program that plays tic tac toe against you. Your implementation should give your opponenent artificial intelligence (AI)! While this may seem too difficult, it's not too hard if you split it into steps! Try giving the computer these abilities in order:
The first three items are quite manageable, and are a great start to making your opponent smart! The last two items will require some time studying Tic-Tac-Toe strategy, but are a fun way to practice the translation of human strategy to computer code!
$ ruby computer_tictactoe.rb
Would you like to be Player 1 or Player 2?
1
Player 1:
4
Computer: 0
O | |
———+———+———
| X |
———+———+———
| |
Player 1:
2
Computer: 6
6
O | | X
———+———+———
| X |
———+———+———
O | |
Player 1
5
Computer: 8
3
O | | X
———+———+———
O | X | X
———+———+———
O | |
The computer wins!
As you can see, it's pretty tough to get a computer to even be smart about something as simple as tic-tac-toe—the human brain is really amazing. Now consider how much code and intelligence is required to make a program that plays chess, or gives directions to some place depending on traffic and road closings... it's actually quite humbling.
Onward the plot to bring consumerism to Cape Town. We have the Goods and the Vehicle, all we need is the Villan.
Create a Shopper
class. It should:
first_name
last_name
(optional) and the third one should be money
(the amount of money the shopper starts with).money
is not provided in the options
hash, then it should default to 100.first_name
, last_name
and money
, and a full_name
methodcart
property that is set to an empty Cart
in the constructor.add_to_cart
and remove_from_cart
methods.checkout
method that empties the cart and subtracts the total price of its items from money
proprety, only if the shopper has enough money. If not, the method does nothing.Now create a SuperShopper
class. It should:
Shopper
checkout
method, only 90% of the total price of the cart is subtracted from money
.get_money
method that takes an optional integer parameter and adds the input to the money
property. If no input is specified, add 100.As with before, download the test script from here. Save it into your shopping_cart
directory, run it, and make all the tests pass!