# How the ddpoker Table Design System Handles Seating Arrangements

> Discover how the ddpoker table design system manages seating arrangements. Learn about the separation of concerns between TableDesign and PokerTable for efficient seat logic and display.

- Repository: [Doug Donohoe/ddpoker](https://github.com/dougdonohoe/ddpoker)
- Tags: how-to-guide
- Published: 2026-02-28

---

**The ddpoker table design system splits concerns between visual styling managed by `TableDesign` and seat logic handled by `PokerTable`, which uses a fixed 10-seat array with offset calculations to center the local player at display seat five.**

The open-source ddpoker project implements a robust architecture that separates aesthetic table configuration from player positioning mechanics. While the `TableDesign` class manages gradient backgrounds and persisted color profiles, the `PokerTable` class orchestrates seating arrangements through array-based storage and mathematical seat translation. This design ensures consistent visual theming while supporting dynamic player assignment and dealer button rotation across the 10-seat layout.

## Architectural Separation of Concerns

The system divides table design into two distinct domains that operate independently. Understanding this separation is critical for modifying either the visual presentation or seating logic without affecting the other.

**Visual Appearance** is handled by `TableDesign`, a `BaseProfile` subclass that stores top and bottom gradient colors as `java.awt.Color` fields (`colorTop_` and `colorBottom_`). These profiles serialize to HTML color strings (`#RRGGBBAA`) and persist in the `tables/` directory, loaded at runtime via `TableDesignManager`.

**Seat Management** is implemented in `PokerTable`, the core model that maintains a fixed array of `PokerPlayer` objects, tracks the dealer button position, and provides utilities to map logical table seats to display positions in the UI.

## Visual Profile Management

The `TableDesign` class focuses exclusively on aesthetic configuration, leaving seat allocation to other components.

Color values are serialized through `read()` and `write()` methods that convert between Java `Color` objects and HTML hex strings. The `TableDesignManager.getDefaultProfile()` method retrieves the most recently used profile or falls back to a built-in "Green" theme, supplying it to the UI layer at `PokerGameboard` lines 149-151.

Source: [`code/poker/src/main/java/com/donohoedigital/games/poker/TableDesign.java`](https://github.com/dougdonohoe/ddpoker/blob/main/code/poker/src/main/java/com/donohoedigital/games/poker/TableDesign.java) — color handling at lines 69-73 and profile I/O at lines 61-71.

## Seat Storage and Assignment

The `PokerTable` class in [`code/poker/src/main/java/com/donohoedigital/games/poker/PokerTable.java`](https://github.com/dougdonohoe/ddpoker/blob/main/code/poker/src/main/java/com/donohoedigital/games/poker/PokerTable.java) implements the seating arrangement logic using a fixed-size array structure.

### Fixed Array Structure

Player positions are stored in a 10-element array defined by `PokerConstants.SEATS`, where empty positions contain `null`:

```java
PokerPlayer players_[] = new PokerPlayer[PokerConstants.SEATS];   // PokerTable.java L69-70

```

### Adding Players

**Random assignment** uses `addPlayer(PokerPlayer p)`, which locates a random empty slot and delegates to `setPlayer()`:

```java
public void addPlayer(PokerPlayer p) { … setPlayer(p, i); }   // PokerTable.java L75-86

```

**Targeted assignment** uses `setPlayer(p, nSeat)`, which validates seat availability, updates the array, and fires a `TYPE_PLAYER_ADDED` event:

```java
public void setPlayer(PokerPlayer p, int nSeat) { … }   // PokerTable.java L32-53

```

Occupancy queries support UI decision-making through `getNumOccupiedSeats()` (lines 112-119) and `getNumOpenSeats()` (lines 100-107), allowing interfaces to determine available actions like rebuys or add-ons.

## Dealer Button Management

The dealer position (`nButton_`) is stored as a seat index within the `PokerTable` state. Helper methods manage button rotation around occupied seats:

- `moveButton()` advances to the next occupied seat
- `setButtonRandom()` places the button randomly
- `setButtonHighCard()` assigns based on high card logic

The `setButton(int n)` method updates the internal index and fires `TYPE_BUTTON_MOVED` events:

```java
public void setButton(int n) { … firePokerTableEvent(...); }   // PokerTable.java L33-42

```

## Display Seat Translation

To ensure the local human player always appears at seat 5 (index 4) in the UI, `PokerTable` implements offset calculations that rotate the logical seat numbers without altering the underlying array.

### Offset Calculation

The `getSeatOffset()` method computes the rotation needed to center the local player:

```java
public int getSeatOffset() { … return 4 - nSeat; }   // PokerTable.java L62-80

```

### Seat Mapping Methods

Two complementary methods handle the translation between internal logic and display:

- `getDisplaySeat(int nSeat)` adds the offset and wraps using modulo arithmetic (lines 85-96)
- `getTableSeat(int nDisplaySeat)` subtracts the offset to convert display positions back to logical indices (lines 99-110)

This allows the UI to call `table.getDisplaySeat(logicalSeat)` for each player, ensuring consistent positioning regardless of which seat the local player occupies.

## Practical Implementation

### Creating a Table and Seating Players

```java
// Create a new table (number 1) attached to a game instance
PokerTable table = new PokerTable(myGame, 1);

// Create two PokerPlayer instances (could be human or AI)
PokerPlayer alice = new PokerPlayer(...);
PokerPlayer bob   = new PokerPlayer(...);

// Seat them in random open seats
table.addPlayer(alice);
table.addPlayer(bob);

// Query occupied seats – should be 2
int occupied = table.getNumOccupiedSeats();   // returns 2

```

*Relevant source*: `PokerTable` constructor L73-78, `addPlayer` L75-86, `getNumOccupiedSeats` L112-119.

### Mapping Logical Seats to UI Positions

```java
int logicalSeat = 0;                     // first seat in the array
int uiSeat = table.getDisplaySeat(logicalSeat);
// uiSeat will be 4 (seat 5) if the local human is at seat 0,
// otherwise it will be rotated so the human stays centered.

```

*Relevant source*: `getSeatOffset()` L62-80, `getDisplaySeat()` L85-96.

### Rotating the Dealer Button

```java
int next = table.getNextSeatAfterButton();  // finds next occupied seat after current button
table.setButton(next);                      // updates nButton_ and fires TYPE_BUTTON_MOVED

```

*Relevant source*: `getNextSeatAfterButton()` L124-126, `setButton()` L33-42.

## Summary

- **Separation of concerns**: `TableDesign` handles visual styling (colors/gradients) while `PokerTable` manages seating arrangements and player positioning.
- **Fixed array storage**: Seats are stored in a 10-element `PokerPlayer` array with `null` indicating empty positions.
- **Flexible assignment**: The system supports both random seating via `addPlayer()` and specific seat targeting via `setPlayer()`.
- **Dealer rotation**: The dealer button tracks as a seat index with methods to advance randomly or to the next occupied seat.
- **UI centering**: Offset calculations in `getDisplaySeat()` ensure the local player always renders at position 5 regardless of logical seat assignment.

## Frequently Asked Questions

### Where is the seat data stored in ddpoker?

Seat occupancy data is stored in the `players_` array within [`PokerTable.java`](https://github.com/dougdonohoe/ddpoker/blob/main/PokerTable.java) (lines 69-70), defined as `new PokerPlayer[PokerConstants.SEATS]` with a fixed length of 10. Empty seats contain `null` values, and the array index directly corresponds to the logical seat number (0-9).

### How does ddpoker ensure the local player always appears in the center?

The `getSeatOffset()` method calculates a rotation value (`4 - nSeat`) that shifts all display positions so the local human player occupies index 4 (display seat 5). When the UI renders players, it calls `getDisplaySeat()` to translate internal array indices to rotated display positions, maintaining visual consistency across different seating positions.

### Can players choose specific seats or are they randomly assigned?

The system supports both approaches. `addPlayer()` assigns players to random empty seats, while `setPlayer(PokerPlayer p, int nSeat)` allows direct seat selection by specifying the target index. The latter validates that the seat is empty before assignment and fires appropriate events for UI updates.

### What is the relationship between TableDesign and PokerTable?

`TableDesign` and `PokerTable` operate independently. `TableDesign` (managed by `TableDesignManager`) only affects visual appearance through color profiles stored in the `tables/` directory, while `PokerTable` contains all seating arrangement logic, player positioning, and dealer button management. The UI (`PokerGameboard`) consumes both: it applies the visual profile for rendering aesthetics and queries `PokerTable` for player positions.