CoinStrip Game Implementation

Overview
The CoinStrip Game simulates a two-player board game where players take turns moving coins leftward under specific rules. The game is implemented in Java using the structure5.Vector<E>
class and follows the TwoPlayerGame
interface.
Code Review and Analysis
1. Game Initialization
Code Section:
public CoinStrip(int numTiles, int numCoins) {
numberOfTiles = numTiles;
currentPlayer = 1;
tiles = new Vector<>(numberOfTiles);
for (int m = 0; m < numberOfTiles; m++) {
tiles.add(-1);
}
generateBoard();
while (coinCount() < 3) {
generateBoard();
}
}
Strengths:
- The constructor ensures the board is initialized with the required number of tiles.
- The
generateBoard()
method randomly places coins, ensuring variation across games. - The while loop ensures at least 3 coins are present, satisfying game rules.
Opportunities for Improvement:
Optimization: The generateBoard()
method might run multiple times before reaching a valid state. Instead, generate coins while creating the board to avoid redundant iterations.
Code Comments: Add comments to explain the initialization logic for better readability.
2. Board Representation
Code Section:
tiles = new Vector<>(numberOfTiles);
for (int m = 0; m < numberOfTiles; m++) {
tiles.add(-1);
}
Strengths:
- The use of
Vector<Integer>
from thestructure5
library allows dynamic resizing and easy manipulation of the board. - The
-1
placeholder makes it clear that a tile is unoccupied.
Considerations for Engineers:
- This design prioritizes simplicity but requires frequent iterations (e.g., checking occupied tiles). A sparse representation (e.g.,
Map<Integer, Integer>
where key = position, value = coin) might be more efficient.
3. Move Validation
Code Section:
public boolean isValidMove(int resource, int updatedValue) {
if (!tiles.contains(resource)) {
System.out.println("\nThere is no such coin as [" + resource + "]. Try again!");
return false;
}
if (updatedValue < 1 || updatedValue > numberOfTiles) {
System.out.println("\nYou can't move this coin [" + updatedValue + "] steps. Try again!");
return false;
}
for (int i = 1; i <= updatedValue; i++) {
if (tiles.get(getResource(resource) - i) > -1) {
System.out.println("\nYou can't move this coin. Try again!");
return false;
}
}
return true;
}
Strengths:
- Thorough validation of moves, including checks for out-of-bounds and illegal placements.
- Prevents moves that violate the game's rules, such as jumping over other coins or occupying the same tile.
Opportunities for Improvement:
Error Messages: Consolidate error messages for better clarity. Currently, multiple checks may confuse the user.
Code Efficiency: The loop for checking tiles (for (int i = 1; i <= updatedValue; i++)
) could be replaced with a single range check.
Example Optimization:
if (tiles.subList(getResource(resource) - updatedValue, getResource(resource)).contains(resource)) {
return false;
}
4. Displaying the Board
public void displayBoard() {
for (int i = 0; i < numberOfTiles; i++) {
if (tiles.get(i) > 0) {
System.out.print(tiles.get(i) + " ");
} else {
System.out.print("- ");
}
}
}
Strengths:
- Clear and minimalistic visualization of the board.
- Helps players easily identify coin positions and empty tiles.
Suggestions:
Add column indices for better player guidance, especially on larger boards.
Use a newline at the end to avoid cluttered output.
Enhanced Example:
public void displayBoard() {
System.out.print("Index: ");
for (int i = 0; i < numberOfTiles; i++) {
System.out.print(i + " ");
}
System.out.println();
System.out.print("Tiles: ");
for (int i = 0; i < numberOfTiles; i++) {
System.out.print((tiles.get(i) > 0 ? tiles.get(i) : "-") + " ");
}
System.out.println("\n");
}
5. Turn Management
public void takeATurn() {
Scanner sc = new Scanner(System.in);
System.out.print("\nPlayer: [" + getPlayer() + "]\n");
displayBoard();
System.out.print("\n[1] Select the coin and [2] How many tiles you want to move: ");
try {
userCoinNumber = sc.nextInt();
userTileNumber = sc.nextInt();
} catch (Exception e) {
System.out.println("\nInvalid input. Please put an integer number.\n");
takeATurn();
}
if (isValidMove(userCoinNumber, userTileNumber)) {
setResource(userCoinNumber, userTileNumber);
if (isGameOver()) {
displayBoard();
System.out.println("\nPlayer " + getPlayer() + " is the winner!");
} else {
setPlayer(getPlayer());
takeATurn();
}
} else {
takeATurn();
}
}
Strengths:
- Recursive turn handling is clean and avoids unnecessary loops.
- Input validation ensures the game flow remains smooth.
Opportunities for Improvement:
Avoid Infinite Recursion: Recursive calls in takeATurn()
could lead to stack overflow on invalid inputs. Replace with a loop.
Error Handling: Catch input exceptions more gracefully and prompt users again without repeating the entire method.
Improved Code:
public void takeATurn() {
Scanner sc = new Scanner(System.in);
while (true) {
System.out.print("\nPlayer: [" + getPlayer() + "]\n");
displayBoard();
System.out.print("\n[1] Select the coin and [2] How many tiles you want to move: ");
try {
userCoinNumber = sc.nextInt();
userTileNumber = sc.nextInt();
} catch (Exception e) {
System.out.println("\nInvalid input. Please enter integers only.");
sc.nextLine(); // Clear the scanner buffer
continue;
}
if (isValidMove(userCoinNumber, userTileNumber)) {
setResource(userCoinNumber, userTileNumber);
break;
}
}
if (isGameOver()) {
displayBoard();
System.out.println("\nPlayer " + getPlayer() + " is the winner!");
} else {
setPlayer(getPlayer());
takeATurn();
}
}
Engineering Principles I tried to follow
Modularity: Implements the TwoPlayerGame
interface, promoting clean, reusable code.
Dynamic Representation: The use of Vector<E>
ensures flexibility in board design and coin placement.
Game Logic: Comprehensive validation prevents illegal moves and ensures a fair game.
Opportunities for Scalability: The current design can be easily extended with additional features (e.g., AI opponent).
Reflection and Recommendations
- Strengths: The implementation demonstrates clean game logic and proper use of Java's data structures. Recursive methods simplify logic but may need optimization for edge cases.
- Improvements:
- Replace recursion in
takeATurn()
with loops for better scalability. - Add comments to explain critical logic blocks for readability.
- Optimize board generation to avoid redundant iterations.
- Replace recursion in
- Potential Enhancements: Add an AI player with heuristic-based moves or a graphical interface for a more interactive experience.