| CPSC 329 | Software Development | Fall 2026 |
In this individual project, you will build a working, playable console (text-based) version of the game Igel Ärgern (known as "Hedgehogs in a Hurry" in English). This project provides the foundation for the rest of the semester's projects as well as acting as a warmup — the goals are to practice building an object-oriented program from scratch, establish a sound individual git workflow, and develop the habit of incorporating testing from the start.
This is an individual project — the code and every deliverable should be entirely your own work. This includes no AI — review the course AI policy for details.
A 20-minute individual hand-in meeting is required after handin. These meetings will be scheduled prior to the project due date and will normally take place within a day or two of the due date. Be ready to walk through your own code and other deliverables and to explain specific aspects of your work as well as bigger-picture things like design decisions you made and other aspects of your process. This isn't a quiz about content but rather to confirm that your handin reflects your own understanding and effort.
Due Friday 9/25 at the start of class. Late handins are not accepted for projects, but an occasional 1-2 day extension is possible in case of a last-minute time crunch. (Plan ahead to avoid this!) See the late policy for details.
Hedgehogs in a Hurry is a racing game played on a rectangular board. Each player controls four pieces (the hedgehogs) that must travel across the board along one of six parallel tracks. A player wins by being the first to get three of their four pieces across the board. Click on the thumbnail image to the right for a larger view of the game board (with a game in progress).
There are many variants of this game; you will be implementing the standard version (with one modification to the game setup) as described below. (official rules)
The board is a grid with 6 rows (tracks) and 9 columns. The leftmost column is the start column and the rightmost column is the goal column.
One square per track is a black field. On the standard board, the black fields are in columns 4, 7, 5, 6, 3, and 8, respectively, for tracks 1-6 (as shown on the game board).
Multiple hedgehogs can occupy the same square, stacked on top of each other. Only the hedgehog on the top of a stack is free to move — hedgehogs underneath are blocked until those above them have moved away.
A black field acts as a barrier: a hedgehog sitting on a black field cannot move forward until all of the places behind them — on any track — are completely empty. For example, a hedgehog on the black field in track 1 (in column 4) cannot move until columns 1-3 are empty in all tracks.
The game is for 2-6 players. Prompt the user for the number of players on startup — don't hardcode a specific number.
Each player has four hedgehogs.
In the standard game, each player takes turns placing their hedgehogs in the start column. In this version, the hedgehogs will be placed automatically: place one hedgehog per player per round, in player order, until all of the hedgehogs have been placed. Each hedgehog goes into the shortest stack that doesn't already contain one of that player's own pieces, breaking stack-height ties by choosing the lowest-numbered track.
A turn has three parts, in order:
Roll. Roll a single 6-sided die.
Optional sidestep. The current player may move one of their own free (top of the stack) hedgehogs to an adjacent track (one track higher or lower) within the same column. This step is optional — the player doesn't have to sidestep — but must be done before the mandatory forward move if it is done.
Mandatory forward move. The current player must move one free hedgehog in the track corresponding to the value rolled one column forward (to the right, towards the goal column). If none of the eligible hedgehogs belong to the current player, the player must move one belonging to an opponent, otherwise they can move any free hedgehog in the track (their own or an opponent's).
Note that each move (forward or sideways) is only a single square, and no hedgehog ever moves backwards. Additionally:
Only hedgehogs on the top of a stack are free to move. Hedgehogs on a black field are only free to move if the columns behind them are also clear.
Sidesteps are only allowed for the player's own hedgehogs and can occur in any track. Forward moves can be any player's hedgehog but must be in the track corresponding to the die roll.
The forward step may be impossible — if there are no free hedgehogs in the required track, the forward move is skipped for that turn. It is allowed to do a sidestep that then makes a forward step impossible.
The first player to get three of their four hedgehogs into the goal column wins.
Support 2-6 players. Prompt for the number of players at the beginning.
Game play. Implement the game as described above (standard rules plus the automatic hedgehog setup modification).
Console (text-based) I/O only — no GUI. This is a throwaway component (a GUI is a later stage of the project) so the user interface doesn't need to be particularly polished or elegant, just functional enough to play the game. Some clunkiness is fine, but if it takes real effort for the player to figure out the current board state or to enter their move, it's not clunky — it's not functional.
Provide sufficient in-game instructions so that players familiar with how to play the game can use your program. For the most part, how to use the program will likely be self-evident and not require any additional explanation. Where it is not, fold the instructions into the prompt e.g. "enter a move as track,column:" instead of just "enter a move:". Instructions can also be printed at the beginning when the program starts up. Don't include game rules! The players know how Hedgehogs in a Hurry works, just not necessarily how to use your program.
Enforce the rules and address robustness. Reject illegal moves and bad input with a clear message and reprompt. Even though this is a throwawy UI, the program shouldn't crash if used incorrectly.
Report the winner at the end. They deserve some congratulations!
Use textual analysis and the CRC card approach to develop an initial class organization. Keep this low-overhead and where you can see the whole design at once: use actual 3x5 crds, divide several sheets of paper into quadrants and use one for each card, fill in the rows of a table in a Word document, etc.
Use incremental development and a test-early approach. Write a test plan for the methods in your design before you write any code in order to help nail down their contracts. (See the Deliverables section for details.) Implement bottom-up, starting with the building blocks and only moving on to game play functionality once the supporting classes are in place. Implement one chunk — a single method, a whole class, or a unit of functionality — at a time. For each chunk, implement tests before you write the code they cover, then write the relevant code and ensure all the tests pass before moving on to the next chunk.
Implement JUnit tests. Implement tests for the scenarios in your test plan as JUnit tests. Focus on worthwhile tests — you can skip testing low-risk methods where the code is simple, easy to reason about confidently, and called in many places so that if a bug does slip by, it is very likely to be caught when something that depends on it fails a test. You may defer more complex or less deterministic scenarios (such as an entire turn or things that depend on dice rolls) to manual play-testing instead of automating them. See the Deliverables section for details on documenting the rationale for any tests you skip or defer.
Utilize testing and debugging tools and strategies other than print statements — the Eclipse debugger, assertions, logging. Deliberately try out tools that are new to you — don't just fall back on the familiar (such as print statements) if something else would be appropriate. Document this with a debugging log (described in the Deliverables section).
Use version control. Incorporate git from the start and follow the standard individual workflow: initialize a repository and commit meaningfully and incrementally as you go — each commit should correspond to a distinct, meaningful step in development, not an arbitrary save point or only a single commit at the end covering the whole project. Set up your project's directory structure as done in lab 1. Name your project hedgehogs.
Hand in all of the following — each is an essential part of the assessment for this project.
Source code, JUnit test suite, and git commit history: copy your entire ~/cs329/dev/hedgehogs directory into your handin directory in /classes/cs329/handin. This should include your git repository (in ~/cs329/dev/hedgehogs/.git). If you did not name your project hedgehogs, rename the directory in the handin folder once you've copied it.
CRC cards: Hand in a hard copy of your CRC cards.
Test plan: For each method being tested, list the normal, edge, and error scenarios (as applicable) and describe the expected behavior. Resolve any ambiguities or questions that arise; flag them in the plan as documentation of the process. Also include brief rationales for any tests you don't implement in JUnit — why it is low-risk or why you deferred it to manual testing.
Hand in a hard copy of your test plan.
Debugging log: Include 2-3 short entries, each covering: what broke, what you observed, how you used the tools to find it, and what the fix was. If you have lots of bugs, pick more complex ones or ones that together illustrate using a variety of techniques. If you didn't have any bugs, or they were all trivial enough to spot immediately, you are very lucky! In that case, instead address 2-3 instances of how you did (or could) use assertions and logging to help detect and track down bugs.
Hand in a hard copy of your log.
Project reflection: (1-2 pages) Reflect on the process you used for this project. Address the following:
CRC cards: How did your design change as you moved from initial design into implementation — which classes or responsibilities were added, merged, split, or dropped and what prompted each change? Did you find working through CRC cards before writing code useful or was it something you moved past quickly??
Workflow: Did working this way — incremental development, testing early, and committing in distinct chunks — change how you approached implementation or how you thought about a piece of functionality before writing it? Did breaking work into small, separately-tested, separately-committed chunks feel like it caught problems earlier,or did it feel like unnecessary added structure? Were you able to stick with the process or did you find yourself sometimes slipping back into writing a larger chunk before testing or committing it — and if so, where?
JUnit: Did writing small, focused unit tests change anything about how you found or thought about bugs? Where did a unit test catch something that simply running the program might have missed, or that might have taken longer to notice? Were there any cases where it felt like unnecessary overhead and just running the program would have been as effective?
Debugging tools: What was new to you and how did that go — useful, or overkill for what you needed? Did your approach to debugging change at all over the course of the project?
Be honest and thoughtful in your reflection — whether you found something useful or not won't affect your grade. What matters is consdering what this experience taught you about the software development process itself.
Hand in a hard copy of your reflection.
The course projects together account for 50% of your final grade in this course. There are two distinct components to the project grade:
Program and deliverable quality (15%) Does the program correctly implement the specification and are the other deliverables complete and done properly (not just present)? This is graded against the stated program and process requirements — a program missing functionality or crashing on bad input or process steps that weren't followed fall short here.
Skills standards: (35%) Your work also provides evidence towards the following skills standards. These are assessed directly from your deliverables, and some may be followed up on briefly in the handin meeting, where you may be asked to explain a specific choice you made.
Reasonable decomposition into classes with sensible responsibilities. [CRC cards, code]
Basic version control. The repository is set up as discussed in class, and the commit history shows progress broken into distinct chunks. [git commit history]
Designing a test plan with reasonable coverage. [test plan]
Writing meaningful JUnit tests, including edge cases. This includes both what tests are implemented and well as which are not (and why). [JUnit test suite, test plan]
Test-early practice. Tests are written before or alongside the code they exercise, not after the code is nearly complete. [git commit history, JUnit test suite]
Effective use of debugging and testing tools: debugger, logging, and assertions. [debugging log]