A LAN-based two-player game implemented in Java with a retro-style UI. Players make strategic decisions to either STEAL or SHARE, affecting their balance based on their opponent's choice.
-
Basic Gameplay
- Two players compete over multiple rounds
- Each round, players simultaneously choose to either STEAL or SHARE
- Points are awarded based on both players' choices
-
Scoring System
- Both SHARE: Each player gets 3 coins (Draw)
- Both STEAL: Each player gets 1 coin (Draw)
- One STEAL, one SHARE:
- STEAL player gets 5 coins (Hit)
- SHARE player gets 0 coins (Miss)
-
Game Statistics
- Hit Rate: Percentage of successful steals (when opponent shared)
- Miss Rate: Percentage of times got stolen from (when you shared)
- None Rate: Percentage of draws (both STEAL or both SHARE)
- Final coins comparison determines the winner (WIN/LOSE/DRAW)
-
Round Selection
- Players can choose between 15 or 200 rounds at the start
- Selection is made via a dropdown menu in the main dashboard
- If players choose different numbers, the game uses the smaller number
- Round selection must be made before clicking "READY"
-
Ready System
- Each player must indicate readiness by clicking the "READY" button
- Once ready, players cannot change their round selection
- Players can see when their opponent is ready via status updates
- Game starts automatically when both players are ready
-
Algorithm Play
- Click "PLAY WITH ALGORITHM" before making any manual moves
- Once selected, manual play is disabled for the entire game
- Algorithm timing:
- Regular games (15 rounds): 3-second delay
- Long games (200 rounds): 0.2-second delay
-
Available Algorithms
- Tit for Tat: Starts with SHARE, then copies opponent's last move
- Random: Randomly chooses between STEAL and SHARE
- Systematic: Alternates between SHARE and STEAL
- Friedman: Starts with SHARE, then always STEAL after opponent STEALS
- Joss: Like Tit for Tat, but 10% chance to STEAL
- Graaskamp: Like Tit for Tat, but STEALS after round 50
- Tit for Two Tats: Only STEALS after two consecutive STEALS
- Tester: Tests opponent with initial STEAL
- Rakshitha: First 10 moves random, then adapts based on success
-
End Game Statistics At the end of each game, players receive:
- Final coin totals for both players
- Game result (WIN/LOSE/DRAW)
- Hit Rate: Successful steals percentage
- Miss Rate: Times got stolen from percentage
- None Rate: Draw percentage (both STEAL or both SHARE)
The game uses a text-based protocol with the following message formats:
-
Game Setup
ROUND_SELECTION:<number> # Client -> Server: Selected rounds (15 or 200) READY_STATE:<boolean> # Client -> Server: Player ready status OPPONENT_READY:<boolean> # Server -> Client: Opponent ready status GAME_CONFIG:<number> # Server -> Client: Final round configuration -
Game Flow
GAME_START # Server -> Client: Game initialization ROUND:<number> # Server -> Client: Round announcement STEAL or SHARE # Client -> Server: Player move RESULT:<move1>:<move2>:<coins1>:<coins2>[:<TIMEOUT>] # Server -> Client: Round results GAME_OVER # Server -> Client: Game termination FINAL_SUMMARY:<myCoins>:<oppCoins>:<hits>:<misses>:<hitRate>:<missRate>:<noneRate>:<result> # Server -> Client: Final statistics
-
Disconnection
- Disconnected player's moves default to SHARE
- Game ends after current round
- Connected player receives final results
-
Invalid Moves
- Invalid move formats default to SHARE
- Timeout moves default to SHARE
- Players are notified of timeouts in results
-
Round Selection
- Invalid round numbers default to 15
- Different selections use smaller number
- Selection locked after clicking READY
- Retro 1990s style UI using Java Swing
- LAN-based multiplayer (2 players)
- 30-second timeout per move (defaults to SHARE)
- Real-time coin updates
- Configurable initial money and number of rounds
- Sound effects for different game outcomes
- Retro-styled interface with game log
- Automatic play using predefined algorithms
- Java 11 or higher
- Maven 3.x
- Network connectivity for LAN play
stealnshare/
├── src/ # Source code directory
│ ├── main/
│ │ ├── java/ # Java source files
│ │ │ └── com/stealnshare/
│ │ │ ├── client/ # Client-side code
│ │ │ │ └── GameClient.java # Client UI and network logic
│ │ │ ├── server/ # Server-side code
│ │ │ │ └── GameServer.java # Game server and logic
│ │ │ └── common/ # Shared code
│ │ │ └── GameConfig.java # Common constants and configs
│ │ └── resources/ # Resource files
│ │ └── sounds/ # Game sound effects
│ │ ├── steal.wav # Sound for steal action
│ │ ├── share.wav # Sound for share action
│ │ ├── lose.wav # Sound for losing
│ │ ├── both_steal.wav # Sound for both stealing
│ │ └── generate_sounds.py # Script to generate sound files
│ └── test/ # Test directory
│ └── java/ # Test source files
├── run-server.sh # Script to start the server
├── run-client.sh # Script to start a client
└── pom.xml # Maven project configuration
- Manages game state and player connections
- Handles game logic and move validation
- Processes player moves with timeout mechanism
- Updates player coin counts based on game rules
- Broadcasts game state to connected clients
- Detects player disconnections and ends the game appropriately
- Defaults to SHARE for players who disconnect or time out
- Provides retro-styled GUI interface
- Manages network connection to server
- Handles user input and move submission
- Displays game state and coin updates
- Plays sound effects based on game events
- Supports automatic play with three algorithm choices:
- Tit for Tat: Starts with SHARE, then copies opponent's last move
- Random: Randomly chooses between STEAL and SHARE
- Systematic: Alternates between SHARE and STEAL (starting with SHARE)
- Defines shared constants
- Network protocol messages
- Game configuration parameters
- Port and connection settings
- Clone the repository:
git clone https://github.com/cropsgg/StealnShare.git
cd StealnShare- Build with Maven:
mvn clean package- Start the server:
./run-server.sh- Start two client instances (in separate terminals):
./run-client.sh- Start the server:
java -cp target/steal-and-share-1.0-SNAPSHOT.jar com.stealnshare.server.GameServer- Start two client instances:
java -cp target/steal-and-share-1.0-SNAPSHOT.jar com.stealnshare.client.GameClient- Start the server:
mvn exec:java -Dexec.mainClass="com.stealnshare.server.GameServer"- Start two client instances (in separate terminals):
mvn exec:java -Dexec.mainClass="com.stealnshare.client.GameClient"-
Server Setup:
- Start the server first
- Server will wait for two players to connect
- Manages game state and player interactions
-
Client Setup (for each player):
- Launch the client application
- Enter initial money amount when prompted
- Enter desired number of rounds
- Wait for opponent to connect
-
Gameplay:
- Each round lasts 30 seconds
- Choose STEAL or SHARE using the buttons, or let an algorithm play for you
- Algorithms take 3 seconds to "think" before making a move
- If no choice is made, defaults to SHARE
- If a player disconnects during a round, their move defaults to SHARE and the game ends after that round
- View results and coin updates in real-time
- Sound effects play based on game outcomes
- Default port: 8080
- Default host: localhost
- For LAN play:
- Server: Ensure port 8080 is accessible
- Clients: Modify server address in GameClient.java to server's IP
- Configure firewalls to allow connections
The game includes custom-generated sound effects:
- steal.wav: Plays when successfully stealing
- share.wav: Plays when both players share
- lose.wav: Plays when opponent steals
- both_steal.wav: Plays when both players steal
Sound files can be regenerated using the provided Python script:
cd src/main/resources/sounds
python generate_sounds.py-
Connection Issues:
- Verify server is running
- Check port availability
- Confirm firewall settings
- Verify network connectivity
-
Build Issues:
- Ensure Java 11+ is installed
- Verify Maven installation
- Check for missing dependencies
-
Runtime Issues:
- Verify sound files exist
- Check file permissions
- Monitor server logs
- Fork the repository
- Create a feature branch
- Commit changes
- Push to the branch
- Create a Pull Request
This project is open source and available under the MIT License.
The game has been designed to gracefully handle player disconnections:
-
Detection:
- The server detects disconnections via socket read timeouts
- If a player doesn't respond within the time limit, they're considered disconnected
-
Response:
- For the current round: The disconnected player's move defaults to SHARE
- The round is completed and coins are awarded accordingly
- Game state is sent to the remaining connected player
- The game ends after the current round instead of continuing
-
Reconnection:
- Players must restart the client application to reconnect
- A new game session will begin when two players connect
The game supports automatic play using predefined algorithms:
-
Algorithm Types:
- Tit for Tat: Always starts with SHARE, then copies what the opponent did in the previous round
- Random: Randomly chooses between STEAL and SHARE with equal probability
- Systematic: Alternates between SHARE and STEAL (always starts with SHARE)
-
Usage:
- Click the "PLAY WITH ALGORITHM" button in the first round before making any manual move
- Select your desired algorithm from the dialog
- Once an algorithm is selected, manual play is disabled for the entire game
- The algorithm will wait 3 seconds before making each move
-
Limitations:
- Algorithms can only be selected in the first round before making any manual move
- Algorithm selection cannot be changed mid-game
- Each new game requires a new algorithm selection
-
Round Selection
- Players can choose between 15 or 200 rounds at the start of the game
- Selection is made via a dropdown menu in the main dashboard
- If players choose different numbers of rounds, the game will use the smaller number
- Round selection must be made before clicking the "READY" button
-
Ready System
- Each player must indicate readiness by clicking the "READY" button
- Once ready, players cannot change their round selection
- Players can see when their opponent is ready via status updates in the game log
- Game starts automatically when both players are ready
-
Game Flow
- Select number of rounds (15 or 200)
- Choose whether to play manually or with an algorithm
- Click "READY" when prepared to start
- Wait for opponent to be ready
- Game begins automatically when both players are ready
- Make moves each round (STEAL or SHARE) or let algorithm play
-
Algorithm Types
- Tit for Tat: Always starts with SHARE, then copies what the opponent did in the previous round
- Random: Randomly chooses between STEAL and SHARE with equal probability
- Systematic: Alternates between SHARE and STEAL (always starts with SHARE)
- Friedman: Starts with SHARE, then always STEAL after opponent STEALS
- Joss: Like Tit for Tat, but 10% chance to STEAL
- Graaskamp: Like Tit for Tat, but STEALS after round 50
- Tit for Two Tats: Only STEALS after two consecutive STEALS
- Tester: Tests opponent with initial STEAL
- Rakshitha: First 10 moves random, then adapts based on success
-
Algorithm Usage
- Click the "PLAY WITH ALGORITHM" button before making any manual moves
- Select your desired algorithm from the dialog
- Once an algorithm is selected, manual play is disabled for the entire game
- Algorithm timing varies:
- Regular games (15 rounds): 3-second delay between moves
- Long games (200 rounds): 0.5-second delay between moves
The game uses a text-based protocol with the following message formats:
-
Round Selection and Ready State
ROUND_SELECTION:<number> # Client -> Server: Selected number of rounds (15 or 200) READY_STATE:<boolean> # Client -> Server: Player ready status OPPONENT_READY:<boolean> # Server -> Client: Opponent ready status GAME_CONFIG:<number> # Server -> Client: Final round configuration -
Game Flow Messages
GAME_START # Server -> Client: Game initialization ROUND:<number> # Server -> Client: Round announcement STEAL or SHARE # Client -> Server: Player move RESULT:<move1>:<move2>:<coins1>:<coins2>[:<TIMEOUT>] # Server -> Client: Round results GAME_OVER # Server -> Client: Game termination FINAL_SUMMARY:<myCoins>:<oppCoins>:<hits>:<misses>:<hitRate>:<missRate>:<noneRate>:<result> # Server -> Client: Final statistics
- Both SHARE: Each player gets 3 coins
- Both STEAL: Each player gets 1 coin
- One STEAL, one SHARE:
- STEAL player gets 5 coins
- SHARE player gets 0 coins
-
Disconnection
- If a player disconnects, their moves default to SHARE
- Game ends after the current round
- Connected player receives final results
-
Invalid Moves
- Invalid move formats default to SHARE
- Timeout moves default to SHARE
- Players are notified of timeouts in results
-
Round Selection
- Invalid round numbers default to 15 rounds
- Different selections use the smaller number
- Selection is locked after clicking READY
The Steal and Share game implements a classic client-server architecture using Java's socket programming capabilities:
-
Transport Layer
- Protocol: TCP (Transmission Control Protocol)
- Port: 8080 (configurable in GameConfig.java)
- Benefits: Reliable, ordered, and error-checked delivery of game messages
- Connection Management: Full-duplex communication with persistent connections
-
Application Layer Protocol
- Format: Text-based with colon-separated fields
- Encoding: UTF-8 text
- Message Types:
GAME_START # Server -> Client: Game initialization ROUND:<number> # Server -> Client: Round announcement STEAL or SHARE # Client -> Server: Player move RESULT:<move1>:<move2>:<coins1>:<coins2>[:<TIMEOUT>] # Server -> Client: Round results GAME_OVER # Server -> Client: Game termination FINAL_SUMMARY:<myCoins>:<oppCoins>:<hits>:<misses>:<hitRate>:<missRate>:<noneRate>:<result> # Server -> Client: Final statistics
-
Protocol Flow:
1. Server starts and binds to port 8080 2. Two clients connect to server 3. Server sends GAME_START to both clients 4. For each round: a. Server sends ROUND:<number> to both clients b. Clients send STEAL or SHARE to server (or timeout) c. Server processes moves and sends RESULT:... to both clients 5. After all rounds or on disconnect, server sends GAME_OVER 6. Server closes connections
-
Server-Side Socket Management:
// Server socket initialization serverSocket = new ServerSocket(GameConfig.PORT); // Accepting client connections (blocking) Socket clientSocket = serverSocket.accept(); // Creating I/O streams for client communication BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
-
Client-Side Socket Management:
// Connecting to server socket = new Socket("localhost", GameConfig.PORT); // Creating I/O streams for server communication in = new BufferedReader(new InputStreamReader(socket.getInputStream())); out = new PrintWriter(socket.getOutputStream(), true); // Asynchronous message listening new Thread(this::listenForMessages).start();
-
Concurrency Model:
- Server: Multi-threaded with one thread per client plus main game thread
- Client: Main UI thread + dedicated network listener thread
- Synchronization: Server coordinates player moves and ensures game consistency
-
Timeout Implementation:
// Server-side timeout handling using ExecutorService and Futures ExecutorService executor = Executors.newFixedThreadPool(2); Future<String> moveFuture = executor.submit(() -> { return in.readLine(); // Read player move }); // Try to get move with timeout try { String move = moveFuture.get(GameConfig.MOVE_TIMEOUT_SECONDS, TimeUnit.SECONDS); // Process valid move } catch (TimeoutException e) { // Handle timeout - default to SHARE }
-
Buffering and Flushing:
- Server and client both use
PrintWriterwith auto-flush enabled - Critical messages use explicit
flush()to ensure immediate transmission - Buffered readers improve network efficiency
- Server and client both use
-
Connection Loss Detection:
- IOException during socket read/write indicates connection loss
- Server detects client disconnection through socket read timeouts
- Socket exceptions caught and handled to prevent application crashes
-
Error Recovery:
- If a move is invalid or connection drops, server defaults to SHARE
- Game continues with defaulted move for current round
- Game ends after the round if player disconnected
-
Bandwidth Usage:
- Extremely lightweight protocol (few bytes per message)
- Text-based messages typically under 100 bytes each
- Total bandwidth per game session typically under 10KB
-
Latency Handling:
- 30-second move timeout accommodates even high-latency connections
- Blocking reads on client ensure proper synchronization
- No real-time action requirements makes the game tolerant of network delays
-
Current Implementation:
- No encryption of network traffic
- No authentication mechanism
- Designed for trusted LAN environments only
-
Security Recommendations for Production:
- Implement SSL/TLS for encrypted communication
- Add user authentication system
- Validate all incoming messages to prevent injection attacks
- Implement rate limiting to prevent denial of service
-
Debugging Techniques:
- Extensive logging of network messages with timestamps
- Console output of all sent/received messages
- Error capture and display for network operations
-
Network Testing Tools:
- Wireshark for packet capture and protocol analysis
- Netcat for manual connection testing
- Network emulators for simulating poor network conditions
-
Port Already in Use
- Issue: Cannot start server because port 8080 is already in use
- Solution: Change the port in GameConfig.java or close the application using port 8080
-
Firewall Blocking
- Issue: Clients cannot connect to server
- Solution: Configure firewall to allow traffic on port 8080 (TCP)
-
Connection Timeouts
- Issue: Clients unable to reach server
- Solution: Verify server IP address, ensure server is running, check network connectivity
-
NAT Traversal
- Issue: Cannot connect from external networks
- Solution: Configure port forwarding on router, or use server with public IP address