Networking courses often focus on theory. You learn about protocols, layers, and packet structures. But reading about serial communication differs from actually sending bytes through a wire. The concepts stay abstract until you build something that depends on them.
My Computer Networks I course required a practical project. Most students chose web-based chat applications. I wanted something different. Something that would force me to understand low-level communication. Truco, a traditional Venezuelan card game, became the vehicle for that exploration.
The constraint was unusual: use RS232 serial ports to connect players across a local network. No TCP/IP. No HTTP. Just raw serial data flowing between machines.
What It Does
Truco is a four-player card game popular in Venezuela and other Latin American countries. Players form two teams. Each round, players take turns playing cards from their hand. The highest card wins the round. Win two rounds and your team scores points.
The game uses a Spanish deck with 40 cards across four suits: gold, cups, swords, and clubs. Card values follow a non-linear ranking. The ace of swords beats everything. The ace of clubs comes second. These special rankings add strategy beyond simple number comparison.
A “vira” card drawn at the start changes the game. Cards matching the next number in the vira’s suit become the most powerful. This wildcard mechanic keeps each match unpredictable.
Players can call “truco” to raise the stakes. The opposing team must accept or forfeit. Accepting means the round is worth more points. Declining hands victory to the challenger. This bluffing element adds psychological depth.
The game runs on four separate machines. One acts as the server, dealing cards and broadcasting game state. The others connect through serial ports. Each player sees their own hand and the cards played by others. A graphical interface built with Java’s AWT renders the playing field.
Technical Deep-Dive
The Three-Layer Architecture
The codebase splits into three Maven modules. The Common module holds shared models: cards, decks, players, and game rooms. The Logic Layer contains commands that manipulate game state. The UI Layer handles rendering and serial communication.
This separation keeps responsibilities clear. Models know nothing about how they display. The logic layer knows nothing about serial ports. Each layer depends only on the one below it.
Serial Communication Protocol
RS232 is an old standard for serial communication. It predates modern networking. Data flows as raw bytes at fixed speeds, measured in baud. I configured the connection at 1200 baud with 8 data bits, no parity, and one stop bit.
Every message follows a custom frame format. Frames start with a double dollar sign and end with double percent signs. Between the delimiters, fields encode the sender, receiver, and payload.
A card distribution message looks like this: the sender identifier, the receiver identifier, then three cards encoded as two-digit numbers followed by suit codes. Gold is “O”, cups is “C”, swords is “E”, and clubs is “B”.
When a player plays a card, the frame includes the player identifier and the card code. The receiver parses the frame, extracts the card, and updates the local game state. Other messages handle truco calls, responses, and handshakes.
The Handshake Problem
Synchronizing four players over serial ports presented challenges. Unlike TCP, RS232 has no built-in connection management. You cannot know if the other end received your message.
I implemented a handshake protocol. The server broadcasts a handshake request. Each client retransmits the message when received. When the server sees its own message return, it knows the ring is complete. Only then does it deal cards.
This relay pattern ensures all players are connected before the game begins. Without it, some players might miss the initial card distribution.
Message Parsing
Incoming data arrives as a stream of characters. Messages might arrive fragmented across multiple events. The receiver buffers characters until it sees the end delimiter.
Once a complete frame arrives, a filter determines the message type. Different prefixes indicate different actions: card distribution, card play, truco request, or truco response. The filter dispatches to the appropriate handler.
The parser maps suit codes back to internal representations. It extracts player identifiers and converts them to array indices. Error handling is minimal, assuming messages arrive correctly. In a production system, checksums would validate integrity.
Card Ranking System
Card values follow complex rules. Each card has a strategy object that returns its point value. The ace of swords is worth 14 points. The ace of clubs is worth 13. The seven of swords and seven of gold rank high. Face cards and other numbers follow a different scale.
When the vira card appears, certain cards gain bonus points. If the vira is a 5 of gold, then all 6s become powerful. This dynamic ranking uses a visitor pattern. Each card checks if it matches the special condition and adjusts its value.
The round winner is whoever played the highest-value card. Ties between teammates favor that team. Ties between opponents result in a draw, and the next round decides.
Graphics Rendering
The UI uses Java’s Abstract Window Toolkit. A main frame contains the game canvas. Cards render as image components loaded from resource files. Each suit has 10 card images stored as JPEGs.
Graphic card objects know their position, dimensions, and whether they show face up or face down. Click detection uses bounding box checks. Hover effects enlarge the card slightly.
Player hands display as rows of cards. The current player sees their cards face up. Opponent cards render face down until played. The center area shows played cards for the current round.
Turn Management
The game manager tracks whose turn it is. A counter cycles through players 0 through 3. When a player plays a card, the turn advances. After all four cards are played, the winner is calculated.
The winning player starts the next round. After three rounds, scores update based on who won more rounds. If one team wins two rounds, they take the points. The vira card and dealt cards reset for a new hand.
Truco calls interrupt normal flow. When a player calls truco, the next opponent must respond. Accepting increases the stake. Declining ends the hand immediately with points going to the caller.
What I Learned
Building a multiplayer game over serial ports taught me why protocols exist. Every decision about frame format, delimiters, and message types solved a real problem. Abstract concepts like synchronization became concrete when messages arrived out of order.
The project also showed the value of layered architecture. Changes to the rendering never touched the game logic. Fixing a serial parsing bug did not require understanding card rankings. Clean boundaries made debugging manageable.
Working with teammates on shared code required coordination. We split responsibilities by layer. I handled the communication protocol while my partner focused on game logic. The interfaces between modules served as contracts.
RS232 is obsolete for new projects. But understanding low-level serial communication helps when working with embedded systems, hardware interfaces, and legacy equipment. The principles transfer even when the technology does not.


