- Make reasonable assumptions for anything not specified in the video or the writeup! Your app does not have to be pixel-perfect match to ours. You may find it useful to write your own list of requirements while watching the video, at whatever level of detail you prefer.
- Watch the video, read the hints, etc
As with our hw5 app, be sure to watch the video carefully, then
read all these hints carefully, and so on. Also, work on one
feature at a time, to help manage the complexity. Basically,
all the suggestions we made earlier still apply here.
- Use indexes (and not pixels) as much as possible!
This is important! You do not want to store pieces by their pixel location.
You do not want your core logic to use (x,y) points, or pixels.
Instead, you want to represent the pieces in a list (see next hint),
and then your logic should be based on indexes into that list.
So think of a piece as an index, not a (cx, cy, r) tuple. Now, you do
have to deal with pixels, both to draw and also to handle mouse presses.
Even so, as much possible, deal with indexes and not pixels.
- How to store the board
This is a board game, like the standard Connect Four, only
here it is one-dimensional. Thus, we describe the line of pieces as
a board. We suggest you store the board
in app.board, as a 1d list of 0's and 1's, representing the
two players, though you may use other representations if you wish.
- How to store the selection
The 3 pieces that are highlighted are called the "selection".
We represented the selection by the index of the piece in
the middle of the selection.
We stored that in app.selectionCenterIndex. We
also used app.selectionIsLegal to track if the selection is legal or not.
- How to store the winning run
When there is a winner, the winning run is the sequence of 4 consecutive
same-colored pieces through which a line is drawn. Similar to the
selection, we stored this in an app variable. This time, we used
the left edge of the run, calling it app.winningRunStartIndex.
As usual, you can adapt (or ignore) this hint as you wish.
- getPieceCenterAndRadius(app, pieceIndex)
We found this to be an important helper function. It takes the app
and a pieceIndex, and returns (cx, cy, r), where that piece on the board
is centered at (cx, cy) with radius r. We called this function
in many places:
- when we draw the board (we called it once per piece here)
- when we draw the winning line (we called it twice here, once
for the leftmost piece in the winning run, and once for the rightmost
piece)
- when we draw the selection box (again, we called it twice, for the
two ends).
- in getPieceIndex() -- see next hint for details.
- getPieceIndex(app, x, y)
We found this to be another important helper function. It takes the app
and x and y, and returns the index of the piece on the board that contains
the point (x,y), or None if there is no such piece. While you do not
need to do so, we found it helpful to call
getPieceCenterAndRadius() here. In any case, this function was
very helpful in mousePressed.
- checkForWin(app)
Another helpful function, this takes the app and checks if there is
a win (four in a row of the same color). If so, it sets app.gameOver,
app.message, and app.winningRunStartIndex accordingly. Note that a player
might make a move that causes their opponent to accidentally win! In other
words, player 1 might win right after player 2 makes a move, if that move
causes player 1 to have four pieces in a row.
- moveSelection(app, moveToLeftEnd)
Yet another helpful function, this takes the app and boolean indicating
if we are moving to the left end (if False, then the right end).
This is called whenever a player selects a piece on the end. If the
selection is not legal, it sets the app message accordingly. Otherwise,
this is where we change the board by removing the selection and then
adding it back to the appropriate end. This function also calls
checkForWin().
- Debugging features: c and p
Be sure to understand why it is so helpful to have these features:
pressing c to set the color of selected block***, and
pressing p to change the current player. For example, these
let you fairly quickly make blocks of 4 so you can
verify that your app works properly when the game is over.
***This means
the three selected dots will change to the color of the current player.
See video for more details!
- Drawing helper functions
Here is our redrawAll:
def redrawAll(app, canvas):
drawTitle(app, canvas)
drawInstructions(app, canvas)
drawCurrentPlayerAndMessage(app, canvas)
drawBoard(app, canvas)
drawRules(app, canvas)
- drawPlayerPiece(app, canvas, player, cx, cy, r)
This is a drawing helper function. It draws the given
player's piece at (cx, cy) and with radius r. We used this to
draw the pieces on the board, and then also to draw that extra piece
that is drawn between the "Current Player" and the app.message.
- Use text anchors
We used anchor='e'
and also anchor='w'
in our calls to create_text in
our sample solution. Be sure you understand what these do so you
can use them as needed.
- Colors
These are the colors we used (but you may use other colors instead as long as they are reasonably easy to tell apart):
- 'lightBlue' with a 'blue' outline
- 'lightGreen' with a 'green' outline
- 'orange' and 'pink' for the selection box
- Message strings
These are the strings we assigned to app.message:
- 'Select your 3-piece block'
- 'End cannot be in block'
- 'Block must contain current player'
- 'Select end to move block to'
- 'Game Over!!!!!'
Use these (or similar strings) wherever/however you feel it makes the most sense.
- Instructions strings
Use this list in drawInstructions:
messages = ['See rules below.',
'Click interior piece to select center of 3-piece block.',
'Click end piece to move that block to that end.',
'Change board size (and then restart) with arrow keys.',
'For debugging, press c to set the color of selected block.',
'For debugging, press p to change the current player.',
'Press r to restart.',
]
- Rules strings
And use this list in drawRules (and the somewhat-odd
indenting is legal and avoids complaints by the linter):
messages = [
"The Rules of One-Dimensional Connect Four:",
"Arrange N (10 by default) pieces in a row of alternating colors.",
"Players take turns to move three pieces at a time, where:",
" The pieces must be in the interior (not on either end)",
" The pieces must be adjacent (next to each other).",
" At least one moved piece must be the player's color.",
"The three pieces must be moved in the same order to either end of the row.",
"The gap must be closed by sliding the remaining pieces together.",
"The first player to get four (or more) adjacent pieces of their color wins!",
]
- More Hints
- We allow magic numbers for graphics layout.
- Board sizes are always even, between 6 and 20, inclusive.
- When the game starts, the leftmost piece must be randomly chosen, and the
player with the leftmost piece goes first.
- When you restart, the board size stays the same and does not reset to 10.
- When the board size is changed, restart with that new board size.
- Treat a click on an end piece as a move and not a new selection.
- When the game is over, the 'Game Over' message is drawn in the color
of the winning player, next to the small piece of that player.
- If the winning run is longer than 4, draw the line through the leftmost 4 pieces.
- When the window is resized, the top text stays centered,
the bottom text stays put on the left,
and the board in the middle resizes -- the pieces get
a bit larger or smaller, and stay evenly spread out across the entire canvas.
- What we're looking for
Here is a helpful checklist of the most important features we're looking for!
- Have fun!
For many of you, this will be the second real app you
have ever made. Progress!!! Enjoy!!!