WordGuess Game: Building a Classic Word Game from Scratch
Here’s the thing about learning object-oriented programming: you can read about classes and interfaces all day long, but until you build something that actually uses them in a meaningful way, it won’t click. That’s where the WordGuess project comes in.
You’re going to build a word-guessing game (think Hangman, but we don’t call it that anymore). A player tries to guess letters in a hidden word, one at a time. Get it right, and the letters reveal themselves. Get it wrong too many times, and you lose. Simple concept, but trust me—there’s a ton of learning packed into this project.
Why This Project Matters
This isn’t just another toy assignment. Here’s what you’re really learning:
Object-Oriented Design: You’ll work with interfaces, implement classes that fulfill contracts, and manage relationships between objects. This is how real software gets built.
State Management: Games are all about state—what’s been guessed, what’s left, who’s winning. Learning to track and update state cleanly is a skill you’ll use in every application you ever build.
Incremental Development: We’re going to teach you to build this in phases, starting with the absolute minimum and adding features one by one. This is how professionals work. You don’t build everything at once and hope it works.
Test-Driven Development: The project comes with tests. You’ll learn to run them, understand what they’re checking, and use them to guide your implementation. Six months from now, when you’re on your first job, you’ll be writing code that passes tests every single day.
The Game Mechanics
Let’s be clear about what you’re building:
- Hidden Word: The game picks a word (or you provide one) that the player needs to guess
- Letter Guessing: Player guesses one letter at a time
- Progress Display: Show the word with blanks for unguessed letters
(like
_ _ _ L E _) - Limited Attempts: Player has a fixed number of wrong guesses before losing
- Win/Lose Detection: Game ends when the word is complete or attempts run out
Think of it as a state machine. Every guess changes the state of the game, and you need to track all of that carefully.
Project Structure
The repository gives you starter code in both Java and Python. Pick your language and stick with it for this project.
What You’re Given:
- Interface definitions (contracts your code must fulfill)
- A Person class to implement (manages player data and scoring)
- A Hangman/WordGuess game class to complete (the core game logic)
- Test files to verify your implementation
What You Need to Build:
- Complete the Person class implementation
- Build the game class with all the mechanics
- Make the tests pass
- Optionally add enhancements (difficulty levels, categories, scoring)
The Five-Phase Development Approach
Here’s where we teach you to think like a professional developer. You don’t build the entire game in one shot. You build it in phases, testing as you go.
Phase 1: The Minimal Game Loop
Start with the absolute simplest thing that could possibly work:
1# Phase 1: Just get input and echo it back
2def play_game():
3 print("Welcome to Word Guess!")
4 while True:
5 guess = input("Guess a letter: ")
6 print(f"You guessed: {guess}")
7 # That's it for Phase 1This does almost nothing, but it runs. That’s the point. Get something working, then build on it.
What you’re learning: How to set up a basic game loop, handle user input, and keep the program running.
Phase 2: Core Game State
Now add the actual state tracking:
1# Phase 2: Track the word and guessed letters
2class Hangman:
3 def __init__(self, word):
4 self.word = word.upper()
5 self.guessed_letters = set()
6 self.max_attempts = 6
7 self.wrong_guesses = 0
8
9 def display_word(self):
10 """Show the word with blanks for unguessed letters"""
11 display = ""
12 for letter in self.word:
13 if letter in self.guessed_letters:
14 display += letter + " "
15 else:
16 display += "_ "
17 return display.strip()Now you have a word, you can track guesses, and you can display progress. Still no win/lose logic, but you’re building the foundation.
What you’re learning: Object state management, data structures (sets are perfect for tracking unique letters), and separating display logic from game logic.
Phase 3: Letter-Guessing Mechanics
Add the ability to actually process guesses:
1def make_guess(self, letter):
2 """Process a single letter guess"""
3 letter = letter.upper()
4
5 # Validation
6 if len(letter) != 1 or not letter.isalpha():
7 return "Please guess a single letter"
8
9 if letter in self.guessed_letters:
10 return "You already guessed that letter"
11
12 # Track the guess
13 self.guessed_letters.add(letter)
14
15 # Check if it's correct
16 if letter in self.word:
17 return f"Good guess! {letter} is in the word"
18 else:
19 self.wrong_guesses += 1
20 return f"Sorry, {letter} is not in the word"Notice the validation. You can’t just trust user input. They might type “AB” or “3” or hit Enter without typing anything. Handle it gracefully.
What you’re learning: Input validation, state updates, and providing feedback to users.
Phase 4: Win/Lose Detection
Now add the logic to actually end the game:
1def is_won(self):
2 """Check if all letters have been guessed"""
3 return all(letter in self.guessed_letters for letter in self.word)
4
5def is_lost(self):
6 """Check if player is out of attempts"""
7 return self.wrong_guesses >= self.max_attempts
8
9def is_game_over(self):
10 """Check if game should end"""
11 return self.is_won() or self.is_lost()These are simple methods, but they’re crucial. Separating the conditions into their own methods makes your code readable and testable.
What you’re learning: Boolean logic, method decomposition, and game state evaluation.
Phase 5: Polish and Enhancement
Now that the core works, add the nice-to-haves:
- Show how many attempts are left
- Display previously guessed letters
- Add a scoring system
- Let players play multiple rounds
- Track high scores
1def get_game_status(self):
2 """Return a formatted status string"""
3 status = f"Word: {self.display_word()}\n"
4 status += f"Guessed: {', '.join(sorted(self.guessed_letters))}\n"
5 status += f"Attempts remaining: {self.max_attempts - self.wrong_guesses}"
6 return statusWhat you’re learning: User experience, information display, and feature integration.
The Person Class: Managing Player Data
Part of this project is implementing a Person class that tracks player information. Here’s the kind of thing you need to handle:
1class Person:
2 def __init__(self, name):
3 self.name = name
4 self.score = 0
5 self.games_played = 0
6 self.games_won = 0
7
8 def update_score(self, points):
9 """Add points to player's score"""
10 self.score += points
11
12 def record_game(self, won):
13 """Track game statistics"""
14 self.games_played += 1
15 if won:
16 self.games_won += 1
17
18 def get_win_rate(self):
19 """Calculate winning percentage"""
20 if self.games_played == 0:
21 return 0.0
22 return (self.games_won / self.games_played) * 100This is object-oriented programming in action. The Person object knows how to manage its own data. You don’t pass around a bunch of separate variables—you pass around a Person object that contains everything.
Working with Interfaces
The project provides interfaces (or abstract base classes in Python) that define contracts your classes must fulfill. Here’s what that means:
1# Interface definition (provided to you)
2class PersonInterface:
3 def get_name(self):
4 """Return the person's name"""
5 raise NotImplementedError
6
7 def get_score(self):
8 """Return the person's current score"""
9 raise NotImplementedErrorYour Person class must implement these methods. The interface is a contract: “If you claim to be a Person, you must provide these methods.”
Why this matters: In professional development, teams use interfaces to define contracts between different parts of the system. You might not write the code that uses your Person class, but as long as you fulfill the interface contract, everything will work together.
Testing: Your Safety Net
The repository comes with tests. Here’s how to use them:
Java:
1cd java
2mvn testPython:
1pip install -r requirements.txt
2pytestTests will fail at first. That’s expected. As you implement each piece, more tests will pass. This is test-driven development: let the tests guide your implementation.
When a test fails, read the error message carefully. It’s telling you what’s broken. Maybe you forgot to handle an edge case, or your method returns the wrong type, or you didn’t implement a required method from the interface.
Common Pitfalls to Avoid
1. Not Handling Case Sensitivity
Players might type “a” or “A”. Your code should treat them the same:
1# Always normalize input
2letter = letter.upper()2. Forgetting to Check for Already-Guessed Letters
If a player guesses ‘E’ twice, don’t count it as a wrong guess the second time. Track what’s been guessed:
1if letter in self.guessed_letters:
2 return "Already guessed"3. Not Validating Input
What if the player types “hello” or “123” or just hits Enter? Handle it:
1if not letter.isalpha() or len(letter) != 1:
2 return "Invalid input"4. Tight Coupling Between Display and Logic
Separate the game logic from the display logic. Don’t mix print() statements into your game state methods. Return data, and let the caller decide how to display it:
1# Good: Returns data
2def get_word_progress(self):
3 return self.display_word()
4
5# Bad: Prints directly
6def show_word_progress(self):
7 print(self.display_word()) # Makes testing harderOptional Enhancements
Once the basic game works, here are some ways to level it up:
Difficulty Levels:
- Easy: More attempts, shorter words
- Hard: Fewer attempts, longer words
Word Categories:
- Let players choose categories (animals, countries, programming terms)
- Store word lists in files or data structures
Scoring System:
- Award points for correct guesses
- Bonus points for winning quickly
- Penalties for wrong guesses
Persistence:
- Save high scores to a file
- Load player statistics between sessions
- Track all-time leaderboards
Hint System:
- Reveal one letter after several wrong guesses
- Show the category or word length
- Cost points to use hints
The Professional Mindset
Here’s what this project is really teaching you:
Incremental Development: Start small, build up, test constantly. This is how real software gets built. You don’t write 500 lines of code and then try to run it for the first time.
Interface-Driven Design: Define contracts between components. This makes code modular, testable, and maintainable.
State Management: Track what’s happening in your program. Games are state machines, and so are most applications you’ll build.
User Input Validation: Never trust user input. Always validate, always handle errors gracefully.
Separation of Concerns: Keep display logic separate from business logic. It makes testing easier and code more reusable.
Getting Started
Here’s your action plan:
- Clone the repository from https://github.com/ZipCodeCore/WordGuess
- Choose your language (Java or Python) and navigate to that directory
- Run the tests to see what’s failing
- Start with Phase 1: Get a basic game loop running
- Implement Phase 2: Add state tracking
- Work through Phases 3-5: Add features incrementally
- Make the tests pass: Use them to guide your implementation
- Add your own enhancements: Make it yours
The Long Game
Six months from now, you’ll be working on a real codebase at your first developer job. You’ll be implementing features incrementally, writing tests, fulfilling interface contracts, and managing state in complex applications.
This little word-guessing game? It’s teaching you all of that. The game itself doesn’t matter—it’s the process of building it that matters.
So don’t rush. Build it in phases. Make the tests pass. Understand why the code is structured the way it is. That’s the real learning.
And trust me, when you’re in a job interview six months from now and they ask you about object-oriented programming, state management, or test-driven development, you’ll be able to talk about this project with confidence. You’ll know what you’re talking about because you built it.
Now go build your game. Start small. Test often. And most importantly—have fun with it. This is programming. It’s supposed to be satisfying when it works.