Repository: CataniaUnited/catania-united-server
Pull request #67: 8 placing the second village and road in reverse order
Author: login: w0lphi
Created: 2025-05-07T14:59:10Z | Merged: 2025-05-07T21:18:47Z



Diff:
diff --git a/src/main/java/com/example/cataniaunited/api/GameWebSocket.java b/src/main/java/com/example/cataniaunited/api/GameWebSocket.java
index bbf35aab..a82cda0d 100644
--- a/src/main/java/com/example/cataniaunited/api/GameWebSocket.java
+++ b/src/main/java/com/example/cataniaunited/api/GameWebSocket.java
@@ -63,11 +63,13 @@ public Uni<MessageDTO> onTextMessage(MessageDTO message, WebSocketConnection con
                 case CREATE_LOBBY -> createLobby(message);
                 case JOIN_LOBBY -> joinLobby(message, connection);
                 case SET_USERNAME -> setUsername(message, connection);
-                case CREATE_GAME_BOARD -> createGameBoard(message, connection); // TODO: Remove after regular game start is implemented
+                case CREATE_GAME_BOARD ->
+                        createGameBoard(message, connection); // TODO: Remove after regular game start is implemented
+                case SET_ACTIVE_PLAYER -> setActivePlayer(message);
                 case PLACE_SETTLEMENT -> placeSettlement(message, connection);
                 case PLACE_ROAD -> placeRoad(message, connection);
-                case ERROR, CONNECTION_SUCCESSFUL, CLIENT_DISCONNECTED, LOBBY_CREATED, LOBBY_UPDATED, PLAYER_JOINED, GAME_BOARD_JSON  ->
-                        throw new GameException("Invalid client command");
+                case ERROR, CONNECTION_SUCCESSFUL, CLIENT_DISCONNECTED, LOBBY_CREATED, LOBBY_UPDATED, PLAYER_JOINED,
+                     GAME_BOARD_JSON -> throw new GameException("Invalid client command");
             };
         } catch (GameException ge) {
             logger.errorf("Unexpected Error occurred: message = %s, error = %s", message, ge.getMessage());
@@ -89,7 +91,8 @@ Uni<MessageDTO> placeRoad(MessageDTO message, WebSocketConnection connection) th
         } catch (NumberFormatException e) {
             throw new GameException("Invalid road id: id = %s", roadId.toString());
         }
-        MessageDTO update = new MessageDTO(MessageType.PLACE_ROAD, message.getPlayer(), message.getLobbyId());
+        GameBoard updatedGameboard = gameService.getGameboardByLobbyId(message.getLobbyId());
+        MessageDTO update = new MessageDTO(MessageType.PLACE_ROAD, message.getPlayer(), message.getLobbyId(), updatedGameboard.getJson());
         return connection.broadcast().sendText(update).chain(i -> Uni.createFrom().item(update));
     }
 
@@ -98,10 +101,11 @@ Uni<MessageDTO> placeSettlement(MessageDTO message, WebSocketConnection connecti
         try {
             int position = Integer.parseInt(settlementPosition.toString());
             gameService.placeSettlement(message.getLobbyId(), message.getPlayer(), position);
-        } catch (NumberFormatException | GameException e) {
+        } catch (NumberFormatException e) {
             throw new GameException("Invalid settlement position id: id = %s", settlementPosition.toString());
         }
-        MessageDTO update = new MessageDTO(MessageType.PLACE_SETTLEMENT, message.getPlayer(), message.getLobbyId());
+        GameBoard updatedGameboard = gameService.getGameboardByLobbyId(message.getLobbyId());
+        MessageDTO update = new MessageDTO(MessageType.PLACE_SETTLEMENT, message.getPlayer(), message.getLobbyId(), updatedGameboard.getJson());
         return connection.broadcast().sendText(update).chain(i -> Uni.createFrom().item(update));
     }
 
@@ -133,6 +137,13 @@ Uni<MessageDTO> setUsername(MessageDTO message, WebSocketConnection connection)
         throw new GameException("No player session");
     }
 
+    //TODO: Remove after implementation of player order
+    Uni<MessageDTO> setActivePlayer(MessageDTO message) throws GameException {
+        lobbyService.getLobbyById(message.getLobbyId()).setActivePlayer(message.getPlayer());
+        return Uni.createFrom().item(new MessageDTO(MessageType.SET_ACTIVE_PLAYER, message.getPlayer(), message.getLobbyId()));
+    }
+
+
     MessageDTO createErrorMessage(String errorMessage) {
         ObjectNode errorNode = JsonNodeFactory.instance.objectNode();
         errorNode.put("error", errorMessage);
@@ -141,7 +152,7 @@ MessageDTO createErrorMessage(String errorMessage) {
 
     Uni<MessageDTO> createGameBoard(MessageDTO message, WebSocketConnection connection) throws GameException {
         GameBoard board = gameService.createGameboard(message.getLobbyId());
-        MessageDTO updateJson =  new MessageDTO(MessageType.GAME_BOARD_JSON, null, message.getLobbyId(), board.getJson());
+        MessageDTO updateJson = new MessageDTO(MessageType.GAME_BOARD_JSON, null, message.getLobbyId(), board.getJson());
         return connection.broadcast().sendText(updateJson).chain(i -> Uni.createFrom().item(updateJson));
 
     }
diff --git a/src/main/java/com/example/cataniaunited/dto/MessageType.java b/src/main/java/com/example/cataniaunited/dto/MessageType.java
index 3ad61333..9f5c3986 100644
--- a/src/main/java/com/example/cataniaunited/dto/MessageType.java
+++ b/src/main/java/com/example/cataniaunited/dto/MessageType.java
@@ -15,7 +15,8 @@ public enum MessageType {
     CREATE_LOBBY,
     JOIN_LOBBY,
     SET_USERNAME,
+    SET_ACTIVE_PLAYER, //-> TODO: Remove after implementation of player order
     PLACE_SETTLEMENT,
     PLACE_ROAD,
-    CREATE_GAME_BOARD
+    CREATE_GAME_BOARD,
 }
\ No newline at end of file
diff --git a/src/main/java/com/example/cataniaunited/game/GameService.java b/src/main/java/com/example/cataniaunited/game/GameService.java
index ab17094a..5a79a480 100644
--- a/src/main/java/com/example/cataniaunited/game/GameService.java
+++ b/src/main/java/com/example/cataniaunited/game/GameService.java
@@ -4,6 +4,7 @@
 import com.example.cataniaunited.game.board.GameBoard;
 import com.example.cataniaunited.lobby.Lobby;
 import com.example.cataniaunited.lobby.LobbyService;
+import com.example.cataniaunited.player.PlayerColor;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import jakarta.enterprise.context.ApplicationScoped;
 import jakarta.inject.Inject;
@@ -28,16 +29,20 @@ public GameBoard createGameboard(String lobbyId) throws GameException {
     }
 
     public void placeSettlement(String lobbyId, String playerId, int settlementPositionId) throws GameException {
+        checkPlayerTurn(lobbyId, playerId);
         GameBoard gameboard = getGameboardByLobbyId(lobbyId);
-        gameboard.placeSettlement(playerId, settlementPositionId);
+        PlayerColor color = lobbyService.getPlayerColor(lobbyId, playerId);
+        gameboard.placeSettlement(playerId, color, settlementPositionId);
     }
 
     public void placeRoad(String lobbyId, String playerId, int roadId) throws GameException {
+        checkPlayerTurn(lobbyId, playerId);
         GameBoard gameboard = getGameboardByLobbyId(lobbyId);
-        gameboard.placeRoad(playerId, roadId);
+        PlayerColor color = lobbyService.getPlayerColor(lobbyId, playerId);
+        gameboard.placeRoad(playerId, color, roadId);
     }
 
-    public ObjectNode getGameboardJsonByLobbyId(String lobbyId) throws GameException{
+    public ObjectNode getGameboardJsonByLobbyId(String lobbyId) throws GameException {
         GameBoard gameBoard = getGameboardByLobbyId(lobbyId);
         return gameBoard.getJson();
     }
@@ -51,6 +56,12 @@ public GameBoard getGameboardByLobbyId(String lobbyId) throws GameException {
         return gameboard;
     }
 
+    private void checkPlayerTurn(String lobbyId, String playerId) throws GameException {
+        if (!lobbyService.isPlayerTurn(lobbyId, playerId)) {
+            throw new GameException("It is not the players turn: playerId=%s, lobbyId=%s", playerId, lobbyId);
+        }
+    }
+
     void addGameboardToList(String lobbyId, GameBoard gameboard) {
         lobbyToGameboardMap.put(lobbyId, gameboard);
     }
diff --git a/src/main/java/com/example/cataniaunited/game/board/GameBoard.java b/src/main/java/com/example/cataniaunited/game/board/GameBoard.java
index a07c2666..7007ccb9 100644
--- a/src/main/java/com/example/cataniaunited/game/board/GameBoard.java
+++ b/src/main/java/com/example/cataniaunited/game/board/GameBoard.java
@@ -6,6 +6,7 @@
 import com.example.cataniaunited.game.board.tile_list_builder.TileListBuilder;
 import com.example.cataniaunited.game.board.tile_list_builder.TileListDirector;
 import com.example.cataniaunited.game.buildings.Settlement;
+import com.example.cataniaunited.player.PlayerColor;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
@@ -72,19 +73,20 @@ void generateBoard() {
         roadList = graphBuilder.getRoadList();
     }
 
-    public void placeSettlement(String playerId, int positionId) throws GameException {
+    public void placeSettlement(String playerId, PlayerColor color, int positionId) throws GameException {
         try {
             SettlementPosition settlementPosition = settlementPositionGraph.get(positionId - 1);
-            settlementPosition.setBuilding(new Settlement(playerId));
+            settlementPosition.setBuilding(new Settlement(playerId, color));
         } catch (IndexOutOfBoundsException e) {
             throw new GameException("Settlement position not found: id = %s", positionId);
         }
     }
 
-    public void placeRoad(String playerId, int roadId) throws GameException {
+    public void placeRoad(String playerId, PlayerColor color, int roadId) throws GameException {
         try {
             Road road = roadList.get(roadId - 1);
             road.setOwnerPlayerId(playerId);
+            road.setColor(color);
         } catch (IndexOutOfBoundsException e) {
             throw new GameException("Road not found: id = %s", roadId);
         }
diff --git a/src/main/java/com/example/cataniaunited/game/board/Road.java b/src/main/java/com/example/cataniaunited/game/board/Road.java
index 0dfba536..442d0ada 100644
--- a/src/main/java/com/example/cataniaunited/game/board/Road.java
+++ b/src/main/java/com/example/cataniaunited/game/board/Road.java
@@ -1,6 +1,7 @@
 package com.example.cataniaunited.game.board;
 
 import com.example.cataniaunited.exception.GameException;
+import com.example.cataniaunited.player.PlayerColor;
 import com.example.cataniaunited.util.Util;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ArrayNode;
@@ -10,6 +11,7 @@
 
 public class Road implements Placable {
     String ownerPlayerId;
+    PlayerColor color;
     final SettlementPosition positionA;
     final SettlementPosition positionB;
     final int id;
@@ -94,6 +96,17 @@ public String getOwnerPlayerId() {
         return ownerPlayerId;
     }
 
+    public PlayerColor getColor() {
+        return color;
+    }
+
+    public void setColor(PlayerColor color) throws GameException {
+        if (this.color != null) {
+            throw new GameException("Color of road cannot be changed twice: roadId = %s, color = %s", id, color.getHexCode());
+        }
+        this.color = color;
+    }
+
     @Override
     public String toString() {
         return "Road:{owner: %s; (%s, %s); position: (%s); angle: %f}"
@@ -104,7 +117,6 @@ public String toString() {
     public ObjectNode toJson() {
         ObjectMapper mapper = new ObjectMapper();
         ObjectNode roadNode = mapper.createObjectNode();
-
         roadNode.put("id", this.id);
 
         if (this.ownerPlayerId != null) {
@@ -113,14 +125,17 @@ public ObjectNode toJson() {
             roadNode.putNull("owner");
         }
 
+        if (this.color != null) {
+            roadNode.put("color", this.color.getHexCode());
+        } else {
+            roadNode.putNull("color");
+        }
 
         ArrayNode coordsNode = mapper.createArrayNode();
         coordsNode.add(this.coordinates[0]); // Add x
         coordsNode.add(this.coordinates[1]); // Add y
         roadNode.set("coordinates", coordsNode);
-
         roadNode.put("rotationAngle", this.rotationAngle);
-
         return roadNode;
     }
 
diff --git a/src/main/java/com/example/cataniaunited/game/board/SettlementPosition.java b/src/main/java/com/example/cataniaunited/game/board/SettlementPosition.java
index 43ec3805..7cd2ee39 100644
--- a/src/main/java/com/example/cataniaunited/game/board/SettlementPosition.java
+++ b/src/main/java/com/example/cataniaunited/game/board/SettlementPosition.java
@@ -3,6 +3,7 @@
 import com.example.cataniaunited.exception.GameException;
 import com.example.cataniaunited.game.board.tile_list_builder.Tile;
 import com.example.cataniaunited.game.buildings.Building;
+import com.example.cataniaunited.util.Util;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
@@ -83,6 +84,21 @@ public void setBuilding(Building building) throws GameException {
         if (this.building != null && !this.building.getOwnerPlayerId().equals(building.getOwnerPlayerId())) {
             throw new GameException("Player mismatch when placing building: positionId = %s, playerId = %s", id, building.getOwnerPlayerId());
         }
+
+        /*
+            The three intersections surrounding this settlement position MUST NOT have buildings on it,
+            and there may only be one road adjacent to this settlement position
+         */
+        boolean hasNoNeighbouringBuildings = getNeighbours().stream().allMatch(sp -> sp.getBuildingOwner() == null);
+        if (!hasNoNeighbouringBuildings) {
+            throw new GameException("Placement of building is not allowed -> spacing rule violated: positionId = %s, playerId = %s", id, building.getOwnerPlayerId());
+        }
+
+        boolean atLeastOneOwnedRoad = getRoads().stream().anyMatch(road -> !Util.isEmpty(road.getOwnerPlayerId()) && road.getOwnerPlayerId().equals(building.getOwnerPlayerId()));
+        if (!atLeastOneOwnedRoad) {
+            throw new GameException("Placement of building is not allowed -> no owned road adjacent: positionId = %s, playerId = %s", id, building.getOwnerPlayerId());
+        }
+
         this.building = building;
     }
 
@@ -101,16 +117,17 @@ public ObjectNode toJson() {
 
         settlementPositionNode.put("id", this.id);
 
-
-        settlementPositionNode.put("building", String.valueOf(this.building)); // type of Building
-
+        if (this.building != null) {
+            settlementPositionNode.set("building", this.building.toJson()); // type of Building
+        } else {
+            settlementPositionNode.putNull("building");
+        }
 
         ArrayNode coordsNode = mapper.createArrayNode();
         coordsNode.add(this.coordinates[0]); // Add x
         coordsNode.add(this.coordinates[1]); // Add y
         settlementPositionNode.set("coordinates", coordsNode);
 
-
         return settlementPositionNode;
     }
 
diff --git a/src/main/java/com/example/cataniaunited/game/buildings/Building.java b/src/main/java/com/example/cataniaunited/game/buildings/Building.java
index 2f60a47f..67096726 100644
--- a/src/main/java/com/example/cataniaunited/game/buildings/Building.java
+++ b/src/main/java/com/example/cataniaunited/game/buildings/Building.java
@@ -1,19 +1,37 @@
 package com.example.cataniaunited.game.buildings;
 
 import com.example.cataniaunited.exception.GameException;
+import com.example.cataniaunited.player.PlayerColor;
 import com.example.cataniaunited.util.Util;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
 
 public abstract class Building {
     protected final String ownerPlayerId;
+    protected final PlayerColor color;
 
-    protected Building(String playerId) throws GameException {
-        if(Util.isEmpty(playerId)) {
+    protected Building(String playerId, PlayerColor color) throws GameException {
+        if (Util.isEmpty(playerId)) {
             throw new GameException("Owner Id of building must not be empty");
         }
+
+        if (color == null) {
+            throw new GameException("Color of building must not be null");
+        }
+
         this.ownerPlayerId = playerId;
+        this.color = color;
     }
 
     public String getOwnerPlayerId() {
         return ownerPlayerId;
     }
+
+    public ObjectNode toJson() {
+        ObjectNode result = JsonNodeFactory.instance.objectNode();
+        result.put("owner", this.ownerPlayerId);
+        result.put("color", this.color.getHexCode());
+        result.put("type", this.getClass().getSimpleName());
+        return result;
+    }
 }
diff --git a/src/main/java/com/example/cataniaunited/game/buildings/Settlement.java b/src/main/java/com/example/cataniaunited/game/buildings/Settlement.java
index 2bd57b64..f22098eb 100644
--- a/src/main/java/com/example/cataniaunited/game/buildings/Settlement.java
+++ b/src/main/java/com/example/cataniaunited/game/buildings/Settlement.java
@@ -1,9 +1,11 @@
 package com.example.cataniaunited.game.buildings;
 
 import com.example.cataniaunited.exception.GameException;
+import com.example.cataniaunited.player.PlayerColor;
 
 public class Settlement extends Building {
-    public Settlement(String playerId) throws GameException {
-        super(playerId);
+
+    public Settlement(String playerId, PlayerColor color) throws GameException {
+        super(playerId, color);
     }
 }
diff --git a/src/main/java/com/example/cataniaunited/lobby/Lobby.java b/src/main/java/com/example/cataniaunited/lobby/Lobby.java
index 3c0ce686..122d43f4 100644
--- a/src/main/java/com/example/cataniaunited/lobby/Lobby.java
+++ b/src/main/java/com/example/cataniaunited/lobby/Lobby.java
@@ -1,16 +1,21 @@
 package com.example.cataniaunited.lobby;
 
-import java.util.*;
-import java.util.concurrent.CopyOnWriteArraySet;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.ConcurrentHashMap;
 import com.example.cataniaunited.player.PlayerColor;
 
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CopyOnWriteArraySet;
+
 public class Lobby {
     private final String lobbyId;
     private final Set<String> players = new CopyOnWriteArraySet<>();
     private final Map<String, PlayerColor> playerColors = new ConcurrentHashMap<>();
     private final List<PlayerColor> availableColors = new CopyOnWriteArrayList<>();
+    private volatile String activePlayer;
 
     public Lobby(String lobbyId, String hostPlayer) {
         this.lobbyId = lobbyId;
@@ -26,38 +31,51 @@ public Set<String> getPlayers() {
         return players;
     }
 
-    public void addPlayer(String player){
-       players.add(player);
+    public void addPlayer(String player) {
+        players.add(player);
     }
 
-    public boolean removePlayer(String player){
+    public boolean removePlayer(String player) {
         return players.remove(player);
     }
 
-    public List<PlayerColor> getAvailableColors(){
+    public String getActivePlayer() {
+        return activePlayer;
+    }
+
+    //TODO: Remove after implementation of player turn order
+    public void setActivePlayer(String activePlayer) {
+        this.activePlayer = activePlayer;
+    }
+
+    public boolean isPlayerTurn(String player) {
+        return player != null && player.equals(activePlayer);
+    }
+
+    public List<PlayerColor> getAvailableColors() {
         return availableColors;
     }
 
-    public void setPlayerColor(String player, PlayerColor color){
+    public void setPlayerColor(String player, PlayerColor color) {
         playerColors.put(player, color);
     }
 
-    public PlayerColor getPlayerColor (String player){
+    public PlayerColor getPlayerColor(String player) {
         return playerColors.get(player);
     }
 
-    public void removePlayerColor(String player){
+    public void removePlayerColor(String player) {
         playerColors.remove(player);
     }
 
-    public PlayerColor assignAvailableColor(){
-        if(availableColors.isEmpty()) return null;
+    public PlayerColor assignAvailableColor() {
+        if (availableColors.isEmpty()) return null;
         Collections.shuffle(availableColors);
         return availableColors.remove(0);
     }
 
-    public void restoreColor(PlayerColor color){
-        if(color != null && !availableColors.contains(color)){
+    public void restoreColor(PlayerColor color) {
+        if (color != null && !availableColors.contains(color)) {
             availableColors.add(color);
         }
     }
diff --git a/src/main/java/com/example/cataniaunited/lobby/LobbyService.java b/src/main/java/com/example/cataniaunited/lobby/LobbyService.java
index 2f7f6b5e..acce8c84 100644
--- a/src/main/java/com/example/cataniaunited/lobby/LobbyService.java
+++ b/src/main/java/com/example/cataniaunited/lobby/LobbyService.java
@@ -1,15 +1,26 @@
 package com.example.cataniaunited.lobby;
 
 import com.example.cataniaunited.exception.GameException;
+import com.example.cataniaunited.player.PlayerColor;
 
 import java.util.List;
 
 public interface LobbyService {
     String createLobby(String hostPlayer);
+
     String generateLobbyId();
+
     List<String> getOpenLobbies();
+
     boolean joinLobbyByCode(String lobbyId, String player);
+
     void removePlayerFromLobby(String lobbyId, String player);
+
     Lobby getLobbyById(String lobbyId) throws GameException;
+
     void clearLobbies();
+
+    boolean isPlayerTurn(String lobbyId, String playerId) throws GameException;
+
+    PlayerColor getPlayerColor(String lobbyId, String playerId) throws GameException;
 }
\ No newline at end of file
diff --git a/src/main/java/com/example/cataniaunited/lobby/LobbyServiceImpl.java b/src/main/java/com/example/cataniaunited/lobby/LobbyServiceImpl.java
index eadec9aa..870afb70 100644
--- a/src/main/java/com/example/cataniaunited/lobby/LobbyServiceImpl.java
+++ b/src/main/java/com/example/cataniaunited/lobby/LobbyServiceImpl.java
@@ -6,7 +6,9 @@
 import org.jboss.logging.Logger;
 
 import java.security.SecureRandom;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
 @ApplicationScoped
@@ -24,9 +26,9 @@ public String createLobby(String hostPlayer) {
         do {
             lobbyId = generateLobbyId();
         } while (lobbies.containsKey(lobbyId));
-
-        lobbies.put(lobbyId, new Lobby(lobbyId, hostPlayer));
-
+        Lobby lobby = new Lobby(lobbyId, hostPlayer);
+        setPlayerColor(lobby, hostPlayer);
+        lobbies.put(lobbyId, lobby);
         logger.infof("Lobby created: ID=%s, Host=%s", lobbyId, hostPlayer);
 
         return lobbyId;
@@ -53,24 +55,19 @@ private String getRandomCharacters(String characters, int length) {
     @Override
     public List<String> getOpenLobbies() {
         List<String> openLobbies = new ArrayList<>(lobbies.keySet());
-
         logger.infof("Current open lobbies: %s", openLobbies);
-
         return openLobbies;
     }
 
     @Override
     public boolean joinLobbyByCode(String lobbyId, String player) {
         Lobby lobby = lobbies.get(lobbyId);
-        if(lobby != null){
-            PlayerColor assignedColor = lobby.assignAvailableColor();
+        if (lobby != null) {
+            PlayerColor assignedColor = setPlayerColor(lobby, player);
             if(assignedColor == null){
-                logger.warnf("No colors available for new players in lobby %s.", lobbyId);
                 return false;
             }
             lobby.addPlayer(player);
-            lobby.setPlayerColor(player, assignedColor);
-
             logger.infof("Player %s joined lobby %s with color %s", player, lobbyId, assignedColor);
             return true;
         }
@@ -79,12 +76,22 @@ public boolean joinLobbyByCode(String lobbyId, String player) {
         return false;
     }
 
-    public void removePlayerFromLobby(String lobbyId, String player){
+    protected PlayerColor setPlayerColor(Lobby lobby, String player) {
+        PlayerColor assignedColor = lobby.assignAvailableColor();
+        if (assignedColor == null) {
+            logger.warnf("No colors available for new players in lobby %s.", lobby.getLobbyId());
+            return null;
+        }
+        lobby.setPlayerColor(player, assignedColor);
+        return assignedColor;
+    }
+
+    public void removePlayerFromLobby(String lobbyId, String player) {
         Lobby lobby = lobbies.get(lobbyId);
-        if(lobby != null){
+        if (lobby != null) {
             PlayerColor color = lobby.getPlayerColor(player);
 
-            if(color != null){
+            if (color != null) {
                 lobby.restoreColor(color);
                 logger.infof("Color %s returned to pool from player %s", color, player);
             }
@@ -107,6 +114,22 @@ public Lobby getLobbyById(String lobbyId) throws GameException {
         return lobby;
     }
 
+    @Override
+    public boolean isPlayerTurn(String lobbyId, String playerId) throws GameException {
+        Lobby lobby = getLobbyById(lobbyId);
+        return lobby.isPlayerTurn(playerId);
+    }
+
+    @Override
+    public PlayerColor getPlayerColor(String lobbyId, String playerId) throws GameException {
+        Lobby lobby = getLobbyById(lobbyId);
+        PlayerColor playerColor = lobby.getPlayerColor(playerId);
+        if (playerColor == null) {
+            throw new GameException("No color for player found: playerId=%s, lobbyId=%s", playerId, lobbyId);
+        }
+        return playerColor;
+    }
+
     @Override
     public void clearLobbies() {
         lobbies.clear();
diff --git a/src/main/java/com/example/cataniaunited/player/PlayerColor.java b/src/main/java/com/example/cataniaunited/player/PlayerColor.java
index ccfa6a40..749b3979 100644
--- a/src/main/java/com/example/cataniaunited/player/PlayerColor.java
+++ b/src/main/java/com/example/cataniaunited/player/PlayerColor.java
@@ -2,17 +2,22 @@
 
 public enum PlayerColor {
     RED("#BD2828"),
-    LIGHT_RED("FF9999"),
+    LIGHT_RED("#FF9999"),
     PURPLE("#B62FB2"),
-    LAVENDER("CCCCFF"),
+    LAVENDER("#CCCCFF"),
     BLUE("#0080B3"),
-    LIGHT_BLUE("B1DAE7"),
+    DARK_BLUE("#002D72"),
     GREEN("#008000"),
-    LIGHT_GREEN("A7F1A7"),
-    ORANGE("#CF6D17"),
-    LIGHT_ORANGE("FFCC99"),
+    LIGHT_GREEN("#A7F1A7"),
+    ORANGE("#FF6A00"),
+    LIGHT_ORANGE("#FF944D"),
     YELLOW("#DB9224"),
-    GREY("#999999");
+    GREY("#999999"),
+    BRIGHT_YELLOW("#FFF200"),
+    CYAN("#00FFFF"),
+    MAGENTA("#FF00FF"),
+    TEAL("#008080"),
+    BROWN("#8B4513");
 
     private final String hexCode;
     PlayerColor(String hexCode) {
diff --git a/src/test/java/com/example/cataniaunited/api/GameWebSocketTest.java b/src/test/java/com/example/cataniaunited/api/GameWebSocketTest.java
index ec9ebf23..54e8b5f3 100644
--- a/src/test/java/com/example/cataniaunited/api/GameWebSocketTest.java
+++ b/src/test/java/com/example/cataniaunited/api/GameWebSocketTest.java
@@ -5,7 +5,10 @@
 import com.example.cataniaunited.exception.GameException;
 import com.example.cataniaunited.game.GameService;
 import com.example.cataniaunited.game.board.GameBoard;
+import com.example.cataniaunited.game.board.SettlementPosition;
+import com.example.cataniaunited.lobby.Lobby;
 import com.example.cataniaunited.lobby.LobbyService;
+import com.example.cataniaunited.player.PlayerColor;
 import com.example.cataniaunited.player.PlayerService;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -33,11 +36,20 @@
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Stream;
 
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 @QuarkusTest
 public class GameWebSocketTest {
@@ -286,7 +298,7 @@ void testPlayerJoinedLobbySuccess() throws JsonProcessingException, InterruptedE
 
         MessageDTO joinLobbyMessage = new MessageDTO(MessageType.JOIN_LOBBY, player, lobbyId);
 
-       List<String> receivedMessages = new CopyOnWriteArrayList<>();
+        List<String> receivedMessages = new CopyOnWriteArrayList<>();
         CountDownLatch messageLatch = new CountDownLatch(3);
 
         var webSocketClientConnection = BasicWebSocketConnector.create()
@@ -334,11 +346,16 @@ void testPlacementOfSettlement() throws GameException, JsonProcessingException,
         String player2 = "Player2";
         String lobbyId = lobbyService.createLobby(player1);
         lobbyService.joinLobbyByCode(lobbyId, player2);
+        PlayerColor expectedColor = lobbyService.getPlayerColor(lobbyId, player2);
+        Lobby lobby = lobbyService.getLobbyById(lobbyId);
+        lobby.setActivePlayer(player2);
         GameBoard gameBoard = gameService.createGameboard(lobbyId);
+        SettlementPosition settlementPosition = gameBoard.getSettlementPositionGraph().get(0);
+        settlementPosition.getRoads().get(0).setOwnerPlayerId(player2);
 
-        assertNull(gameBoard.getSettlementPositionGraph().get(0).getBuildingOwner());
+        assertNull(settlementPosition.getBuildingOwner());
         //Create message DTO
-        int positionId = gameBoard.getSettlementPositionGraph().get(0).getId();
+        int positionId = settlementPosition.getId();
         ObjectNode placeSettlementMessageNode = objectMapper.createObjectNode().put("settlementPositionId", positionId);
 
         var placeSettlementMessageDTO = new MessageDTO(MessageType.PLACE_SETTLEMENT, player2, lobbyId, placeSettlementMessageNode);
@@ -367,6 +384,8 @@ void testPlacementOfSettlement() throws GameException, JsonProcessingException,
 
         var actualSettlementPosition = gameService.getGameboardByLobbyId(lobbyId).getSettlementPositionGraph().get(0);
         assertEquals(player2, actualSettlementPosition.getBuildingOwner());
+        ObjectNode settlementNode = actualSettlementPosition.toJson();
+        assertEquals(expectedColor.getHexCode(), settlementNode.get("building").get("color").asText());
         verify(gameService).placeSettlement(lobbyId, player2, actualSettlementPosition.getId());
     }
 
@@ -414,6 +433,8 @@ void testPlacementOfRoad() throws GameException, JsonProcessingException, Interr
         String player2 = "Player2";
         String lobbyId = lobbyService.createLobby(player1);
         lobbyService.joinLobbyByCode(lobbyId, player2);
+        Lobby lobby = lobbyService.getLobbyById(lobbyId);
+        lobby.setActivePlayer(player2);
         GameBoard gameBoard = gameService.createGameboard(lobbyId);
 
         assertNull(gameBoard.getRoadList().get(0).getOwnerPlayerId());
diff --git a/src/test/java/com/example/cataniaunited/game/GameServiceTest.java b/src/test/java/com/example/cataniaunited/game/GameServiceTest.java
index 9e0b2e52..60cd6310 100644
--- a/src/test/java/com/example/cataniaunited/game/GameServiceTest.java
+++ b/src/test/java/com/example/cataniaunited/game/GameServiceTest.java
@@ -4,6 +4,7 @@
 import com.example.cataniaunited.game.board.GameBoard;
 import com.example.cataniaunited.lobby.Lobby;
 import com.example.cataniaunited.lobby.LobbyService;
+import com.example.cataniaunited.player.PlayerColor;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import io.quarkus.test.junit.QuarkusTest;
@@ -13,9 +14,17 @@
 
 import java.util.Set;
 
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 @QuarkusTest
 class GameServiceTest {
@@ -77,16 +86,38 @@ void getGameBoardShouldReturnCorrectGameBoard() throws GameException {
     void placeSettlementShouldThrowGameExceptionForNonExistingLobby() throws GameException {
         String invalidLobbyId = "invalidLobbyId";
         GameException ge = assertThrows(GameException.class, () -> gameService.placeSettlement(invalidLobbyId, "1", 1));
-        assertEquals("Gameboard for Lobby not found: id = %s".formatted(invalidLobbyId), ge.getMessage());
-        verify(gameService).getGameboardByLobbyId(invalidLobbyId);
+        assertEquals("Lobby with id %s not found".formatted(invalidLobbyId), ge.getMessage());
+        verify(gameService, never()).getGameboardByLobbyId(invalidLobbyId);
     }
 
     @Test
     void placeRoadShouldThrowGameExceptionForNonExistingLobby() throws GameException {
         String invalidLobbyId = "invalidLobbyId";
         GameException ge = assertThrows(GameException.class, () -> gameService.placeRoad(invalidLobbyId, "1", 1));
-        assertEquals("Gameboard for Lobby not found: id = %s".formatted(invalidLobbyId), ge.getMessage());
-        verify(gameService).getGameboardByLobbyId(invalidLobbyId);
+        assertEquals("Lobby with id %s not found".formatted(invalidLobbyId), ge.getMessage());
+        verify(gameService, never()).getGameboardByLobbyId(invalidLobbyId);
+    }
+
+    @Test
+    void placeSettlementShouldThrowGameExceptionForNotPlayerTurn() throws GameException {
+        String playerId = "playerId1";
+        String lobbyId = lobbyMock.getLobbyId();
+        doReturn(lobbyMock).when(lobbyService).getLobbyById(lobbyId);
+        doReturn(false).when(lobbyMock).isPlayerTurn(playerId);
+        GameException ge = assertThrows(GameException.class, () -> gameService.placeSettlement(lobbyId, playerId, 1));
+        assertEquals("It is not the players turn: playerId=%s, lobbyId=%s".formatted(playerId, lobbyId), ge.getMessage());
+        verify(gameService, never()).getGameboardByLobbyId(lobbyId);
+    }
+
+    @Test
+    void placeRoadShouldThrowGameExceptionForNotPlayerTurn() throws GameException {
+        String playerId = "playerId1";
+        String lobbyId = lobbyMock.getLobbyId();
+        doReturn(lobbyMock).when(lobbyService).getLobbyById(lobbyId);
+        doReturn(false).when(lobbyMock).isPlayerTurn(playerId);
+        GameException ge = assertThrows(GameException.class, () -> gameService.placeRoad(lobbyId, playerId, 1));
+        assertEquals("It is not the players turn: playerId=%s, lobbyId=%s".formatted(playerId, lobbyId), ge.getMessage());
+        verify(gameService, never()).getGameboardByLobbyId(lobbyId);
     }
 
     @Test
@@ -94,9 +125,12 @@ void setSettlementShouldCallPlaceSettlementOnGameboard() throws GameException {
         String playerId = "playerId1";
         int settlementPositionId = 15;
         String lobbyId = lobbyMock.getLobbyId();
+        doReturn(lobbyMock).when(lobbyService).getLobbyById(lobbyId);
+        doReturn(true).when(lobbyMock).isPlayerTurn(playerId);
+        doReturn(PlayerColor.BLUE).when(lobbyMock).getPlayerColor(playerId);
         doReturn(gameboardMock).when(gameService).getGameboardByLobbyId(lobbyId);
         gameService.placeSettlement(lobbyId, playerId, settlementPositionId);
-        verify(gameboardMock).placeSettlement(playerId, settlementPositionId);
+        verify(gameboardMock).placeSettlement(playerId, PlayerColor.BLUE, settlementPositionId);
     }
 
     @Test
@@ -104,9 +138,12 @@ void setRoadShouldCallPlaceRoadOnGameboard() throws GameException {
         String playerId = "playerId1";
         int settlementPositionId = 15;
         String lobbyId = lobbyMock.getLobbyId();
+        doReturn(lobbyMock).when(lobbyService).getLobbyById(lobbyId);
+        doReturn(true).when(lobbyMock).isPlayerTurn(playerId);
+        doReturn(PlayerColor.BLUE).when(lobbyMock).getPlayerColor(playerId);
         doReturn(gameboardMock).when(gameService).getGameboardByLobbyId(lobbyId);
         gameService.placeRoad(lobbyId, playerId, settlementPositionId);
-        verify(gameboardMock).placeRoad(playerId, settlementPositionId);
+        verify(gameboardMock).placeRoad(playerId, PlayerColor.BLUE, settlementPositionId);
     }
 
     @Test
diff --git a/src/test/java/com/example/cataniaunited/game/board/GameBoardTest.java b/src/test/java/com/example/cataniaunited/game/board/GameBoardTest.java
index dcaa0cc9..30c084e7 100644
--- a/src/test/java/com/example/cataniaunited/game/board/GameBoardTest.java
+++ b/src/test/java/com/example/cataniaunited/game/board/GameBoardTest.java
@@ -3,6 +3,7 @@
 import com.example.cataniaunited.exception.GameException;
 import com.example.cataniaunited.game.board.tile_list_builder.Tile;
 import com.example.cataniaunited.game.buildings.Settlement;
+import com.example.cataniaunited.player.PlayerColor;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import io.quarkus.test.junit.QuarkusTest;
@@ -15,7 +16,13 @@
 import java.util.List;
 import java.util.stream.Stream;
 
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 @QuarkusTest
 class GameBoardTest {
@@ -95,14 +102,13 @@ void constructorExecutesGenerationSuccessfullyForValidPlayerCount(int playerCoun
         try {
             gameBoard = assertDoesNotThrow(() -> new GameBoard(playerCount),
                     "Board generation failed unexpectedly for " + playerCount + " players.");
-        } catch(Exception e) {
+        } catch (Exception e) {
             // Log the actual exception if assertDoesNotThrow isn't available or for more detail
             System.err.println("GameBoard constructor failed: " + e.getMessage());
             fail("GameBoard constructor threw an unexpected exception.");
         }
 
 
-
         assertNotNull(gameBoard, "GameBoard instance should be created");
         assertEquals(GameBoard.calculateSizeOfBoard(playerCount), gameBoard.sizeOfBoard, "Internal board size should be set correctly");
 
@@ -116,7 +122,7 @@ void constructorExecutesGenerationSuccessfullyForValidPlayerCount(int playerCoun
         assertFalse(graph.isEmpty(), "Generated settlement graph should not be empty");
     }
 
-    static Stream<Arguments> playerCountProvider(){
+    static Stream<Arguments> playerCountProvider() {
         return Stream.of(
                 Arguments.of(2),
                 Arguments.of(3),
@@ -131,7 +137,7 @@ static Stream<Arguments> playerCountProvider(){
     }
 
     @Test
-    void generateBoardThrowsExceptionIfGeneratingGraphBeforeTileList(){
+    void generateBoardThrowsExceptionIfGeneratingGraphBeforeTileList() {
         GameBoard gameBoard = new GameBoard(4);
         gameBoard.tileList = null;
         assertThrows(IllegalStateException.class,
@@ -143,10 +149,10 @@ void generateBoardThrowsExceptionIfGeneratingGraphBeforeTileList(){
     @Disabled("BenchmarkTest Tests how many Players theoretically can play a game, doesn't test functionality, therefore disabled")
     @ParameterizedTest
     @MethodSource("benchMarkTestProvider")
-    void benchMarkTest(int sizeOfBoard){
+    void benchMarkTest(int sizeOfBoard) {
         try {
             new GameBoard(sizeOfBoard);
-        } catch (OutOfMemoryError e){
+        } catch (OutOfMemoryError e) {
             fail("Out of Memory");
         }
 
@@ -171,10 +177,13 @@ static Stream<Arguments> benchMarkTestProvider() {
 
     @Test
     void testPlaceSettlement() throws GameException {
+        String playerId = "Player1";
         GameBoard gameBoard = new GameBoard(2);
         var settlementPosition = gameBoard.getSettlementPositionGraph().get(0);
-        String playerId = "Player1";
-        gameBoard.placeSettlement(playerId, settlementPosition.getId());
+        Road road = settlementPosition.roads.get(0);
+        road.setOwnerPlayerId(playerId);
+
+        gameBoard.placeSettlement(playerId, PlayerColor.BLUE, settlementPosition.getId());
         assertNotNull(settlementPosition.building);
         assertEquals(Settlement.class, settlementPosition.building.getClass());
         assertEquals(playerId, settlementPosition.building.getOwnerPlayerId());
@@ -183,7 +192,7 @@ void testPlaceSettlement() throws GameException {
     @Test
     void placeSettlementShouldThrowExceptionIfPositionIsLessThanZero() {
         GameBoard gameBoard = new GameBoard(2);
-        GameException ge = assertThrows(GameException.class, () -> gameBoard.placeSettlement("Player1", -1));
+        GameException ge = assertThrows(GameException.class, () -> gameBoard.placeSettlement("Player1", PlayerColor.BLUE, -1));
         assertEquals("Settlement position not found: id = %s".formatted(-1), ge.getMessage());
     }
 
@@ -191,16 +200,16 @@ void placeSettlementShouldThrowExceptionIfPositionIsLessThanZero() {
     void placeSettlementShouldThrowExceptionIfPositionIsBiggerThanSize() {
         GameBoard gameBoard = new GameBoard(2);
         int positionId = gameBoard.getSettlementPositionGraph().size() + 1;
-        GameException ge = assertThrows(GameException.class, () -> gameBoard.placeSettlement("Player1", positionId));
+        GameException ge = assertThrows(GameException.class, () -> gameBoard.placeSettlement("Player1", PlayerColor.BLUE, positionId));
         assertEquals("Settlement position not found: id = %s".formatted(positionId), ge.getMessage());
     }
 
     @ParameterizedTest
     @MethodSource("invalidPlayerIds")
-    void placeSettlementShouldThrowExceptionIfPlayerIdIsEmpty(String playerId){
+    void placeSettlementShouldThrowExceptionIfPlayerIdIsEmpty(String playerId) {
         GameBoard gameBoard = new GameBoard(2);
         int positionId = gameBoard.getSettlementPositionGraph().get(0).getId();
-        GameException ge = assertThrows(GameException.class, () -> gameBoard.placeSettlement(playerId, positionId));
+        GameException ge = assertThrows(GameException.class, () -> gameBoard.placeSettlement(playerId, PlayerColor.BLUE, positionId));
         assertEquals("Owner Id of building must not be empty", ge.getMessage());
     }
 
@@ -209,14 +218,14 @@ void testPlaceRoad() throws GameException {
         GameBoard gameBoard = new GameBoard(2);
         var road = gameBoard.roadList.get(0);
         String playerId = "Player1";
-        gameBoard.placeRoad(playerId, road.getId());
-        assertEquals(playerId, road.ownerPlayerId);
+        gameBoard.placeRoad(playerId, PlayerColor.BLUE, road.getId());
+        assertEquals(playerId, road.getOwnerPlayerId());
     }
 
     @Test
     void placeRoadShouldThrowExceptionIfRoadIdIsLessThanZero() {
         GameBoard gameBoard = new GameBoard(2);
-        GameException ge = assertThrows(GameException.class, () -> gameBoard.placeRoad("Player1", -1));
+        GameException ge = assertThrows(GameException.class, () -> gameBoard.placeRoad("Player1", PlayerColor.BLUE, -1));
         assertEquals("Road not found: id = %s".formatted(-1), ge.getMessage());
     }
 
@@ -224,20 +233,20 @@ void placeRoadShouldThrowExceptionIfRoadIdIsLessThanZero() {
     void placeRoadShouldThrowExceptionIfRoadIdIsGreaterThanSize() {
         GameBoard gameBoard = new GameBoard(2);
         int roadId = gameBoard.roadList.size() + 1;
-        GameException ge = assertThrows(GameException.class, () -> gameBoard.placeRoad("Player1", roadId));
+        GameException ge = assertThrows(GameException.class, () -> gameBoard.placeRoad("Player1", PlayerColor.BLUE, roadId));
         assertEquals("Road not found: id = %s".formatted(roadId), ge.getMessage());
     }
 
     @ParameterizedTest
     @MethodSource("invalidPlayerIds")
-    void placeRoadShouldThrowExceptionIfPlayerIdIsEmpty(String playerId){
+    void placeRoadShouldThrowExceptionIfPlayerIdIsEmpty(String playerId) {
         GameBoard gameBoard = new GameBoard(2);
         var road = gameBoard.roadList.get(0);
-        GameException ge = assertThrows(GameException.class, () -> gameBoard.placeRoad(playerId, road.getId()));
+        GameException ge = assertThrows(GameException.class, () -> gameBoard.placeRoad(playerId, PlayerColor.BLUE, road.getId()));
         assertEquals("Owner Id of road must not be empty", ge.getMessage());
     }
 
-    static Stream<Arguments> invalidPlayerIds(){
+    static Stream<Arguments> invalidPlayerIds() {
         return Stream.of(null, Arguments.of(""));
     }
 
@@ -318,7 +327,7 @@ void testGetJsonContentSize() {
 
     //@Disabled("test used for debugging purposes, passes automatically")
     @Test
-    void debuggingTest(){
+    void debuggingTest() {
         GameBoard board = new GameBoard(4);
         board.generateBoard();
         System.out.println(board.getJson());
diff --git a/src/test/java/com/example/cataniaunited/game/board/GraphBuilderTest.java b/src/test/java/com/example/cataniaunited/game/board/GraphBuilderTest.java
index 3720da3a..35d5a09f 100644
--- a/src/test/java/com/example/cataniaunited/game/board/GraphBuilderTest.java
+++ b/src/test/java/com/example/cataniaunited/game/board/GraphBuilderTest.java
@@ -1,19 +1,30 @@
 package com.example.cataniaunited.game.board;
 
-import com.example.cataniaunited.game.board.tile_list_builder.*;
+import com.example.cataniaunited.game.board.tile_list_builder.StandardTileListBuilder;
+import com.example.cataniaunited.game.board.tile_list_builder.Tile;
+import com.example.cataniaunited.game.board.tile_list_builder.TileListBuilder;
+import com.example.cataniaunited.game.board.tile_list_builder.TileListDirector;
+import com.example.cataniaunited.game.board.tile_list_builder.TileType;
 import io.quarkus.test.junit.QuarkusTest;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.MethodSource;
 import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
 
 import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Stream;
 
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 
 @QuarkusTest
@@ -163,10 +174,26 @@ void checkAndThrowAssertionErrorShouldThrowAssertionErrorWhenSuccessIsFalse() {
         String message = "Test failed";
         assertThrows(AssertionError.class,
                 () -> GraphBuilder.checkAndThrowAssertionError(false, message)
-        , "should throw exception"
+                , "should throw exception"
         );
     }
 
+    @Test
+    void getRoadListShouldThrowExceptionWhenRoadListIsNull() {
+        GraphBuilder graphBuilder = mock(GraphBuilder.class);
+        when(graphBuilder.getRoadList()).thenCallRealMethod();
+        IllegalStateException exception = assertThrows(IllegalStateException.class, graphBuilder::getRoadList);
+        assertEquals("Build graph before accessing road list.", exception.getMessage());
+    }
+
+    @Test
+    void getRoadListShouldThrowExceptionWhenRoadListIsEmpty() {
+        GraphBuilder graphBuilder = mock(GraphBuilder.class);
+        when(graphBuilder.getRoadList()).thenCallRealMethod();
+        graphBuilder.roadList = List.of();
+        IllegalStateException exception = assertThrows(IllegalStateException.class, graphBuilder::getRoadList);
+        assertEquals("Build graph before accessing road list.", exception.getMessage());
+    }
 
 }
 
diff --git a/src/test/java/com/example/cataniaunited/game/board/RoadTest.java b/src/test/java/com/example/cataniaunited/game/board/RoadTest.java
index 7b52c8c4..0361916d 100644
--- a/src/test/java/com/example/cataniaunited/game/board/RoadTest.java
+++ b/src/test/java/com/example/cataniaunited/game/board/RoadTest.java
@@ -1,6 +1,7 @@
 package com.example.cataniaunited.game.board;
 
 import com.example.cataniaunited.exception.GameException;
+import com.example.cataniaunited.player.PlayerColor;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import io.quarkus.test.junit.QuarkusTest;
@@ -9,7 +10,16 @@
 
 import java.util.Locale;
 
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
@@ -186,7 +196,7 @@ void toStringOutputsCorrectString() {
     void testSetOwnerPlayerId() throws GameException {
         String playerId = "Player1";
         road.setOwnerPlayerId(playerId);
-        assertEquals(playerId, road.ownerPlayerId);
+        assertEquals(playerId, road.getOwnerPlayerId());
     }
 
     @Test
@@ -197,6 +207,22 @@ void setOwnerPlayerIdShouldThrowErrorIfRoadIsAlreadyPlaced() throws GameExceptio
         assertEquals("Road cannot be placed twice: roadId = %s, playerId = %s".formatted(road.id, playerId), ge.getMessage());
     }
 
+    @Test
+    void testSetAndGetColor() throws GameException {
+        PlayerColor expectedColor = PlayerColor.BLUE;
+        road.setColor(expectedColor);
+        assertEquals(expectedColor, road.getColor());
+    }
+
+    @Test
+    void setColorShouldThrowErrorIfRoadIsAlreadyPlaced() throws GameException {
+        var firstColor = PlayerColor.BLUE;
+        var secondColor = PlayerColor.RED;
+        road.setColor(firstColor);
+        GameException ge = assertThrows(GameException.class, () -> road.setColor(secondColor));
+        assertEquals("Color of road cannot be changed twice: roadId = %s, color = %s".formatted(road.getId(), secondColor.getHexCode()), ge.getMessage());
+    }
+
     @Test
     void testToJsonInitialState() {
         ObjectNode jsonNode = road.toJson();
@@ -241,6 +267,8 @@ void testToJsonWithOwner() throws GameException {
         assertFalse(jsonNode.get("owner").isNull(), "Owner should not be null after setting");
         assertEquals(expectedOwner, jsonNode.get("owner").asText(), "Owner should match the set player ID in JSON");
 
+        assertTrue(jsonNode.get("color").isNull(), "Color should be null");
+
         // Check Coordinates (should still be initial)
         assertTrue(jsonNode.has("coordinates"), "JSON should contain 'coordinates' field");
         ArrayNode coordsArray = (ArrayNode) jsonNode.get("coordinates");
@@ -252,9 +280,22 @@ void testToJsonWithOwner() throws GameException {
         assertEquals(0.0, jsonNode.get("rotationAngle").asDouble(), 0.0001);
     }
 
+    @Test
+    void testToJsonWithColor() throws GameException {
+        PlayerColor expectedColor = PlayerColor.LAVENDER;
+        road.setColor(expectedColor);
+
+        ObjectNode jsonNode = road.toJson();
+        assertNotNull(jsonNode, "toJson() should return a non-null ObjectNode");
+
+        assertEquals(ROAD_ID, jsonNode.get("id").asInt());
+        assertEquals(expectedColor.getHexCode(), jsonNode.get("color").asText(), "Color should match the hex code of the color in JSON\"");
+    }
+
     @Test
     void testToJsonAfterCoordinateCalculationAndOwner() throws GameException {
         String expectedOwner = "Player33";
+        PlayerColor expectedColor = PlayerColor.LAVENDER;
 
         // Mock getCoordinates from SettlementPosition for calculation
         double[] coordsA = {5.0, -10.0};
@@ -264,6 +305,7 @@ void testToJsonAfterCoordinateCalculationAndOwner() throws GameException {
 
         // Set owner and calculate coordinates/angle
         road.setOwnerPlayerId(expectedOwner);
+        road.setColor(expectedColor);
         road.setCoordinatesAndRotationAngle();
 
         // Expected calculated values
@@ -285,6 +327,9 @@ void testToJsonAfterCoordinateCalculationAndOwner() throws GameException {
         assertTrue(jsonNode.has("owner"), "JSON should contain 'owner' field");
         assertEquals(expectedOwner, jsonNode.get("owner").asText(), "Owner should match the set player ID in JSON");
 
+        assertTrue(jsonNode.has("color"), "JSON should contain 'color' field");
+        assertEquals(expectedColor.getHexCode(), jsonNode.get("color").asText(), "Color should match the hex code of the color in JSON");
+
         // Check Coordinates
         assertTrue(jsonNode.has("coordinates"), "JSON should contain 'coordinates' field");
         assertTrue(jsonNode.get("coordinates").isArray(), "Coordinates should be a JSON array");
diff --git a/src/test/java/com/example/cataniaunited/game/board/SettlementPositionTest.java b/src/test/java/com/example/cataniaunited/game/board/SettlementPositionTest.java
index b7f55c06..13c0eb85 100644
--- a/src/test/java/com/example/cataniaunited/game/board/SettlementPositionTest.java
+++ b/src/test/java/com/example/cataniaunited/game/board/SettlementPositionTest.java
@@ -4,6 +4,7 @@
 import com.example.cataniaunited.game.board.tile_list_builder.Tile;
 import com.example.cataniaunited.game.buildings.Building;
 import com.example.cataniaunited.game.buildings.Settlement;
+import com.example.cataniaunited.player.PlayerColor;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import io.quarkus.test.junit.QuarkusTest;
@@ -12,8 +13,19 @@
 
 import java.util.List;
 
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.Mockito.*;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 @QuarkusTest
 class SettlementPositionTest {
@@ -246,24 +258,83 @@ void toStringOutputsCorrectString() {
     @Test
     void testSetBuilding() throws GameException {
         String playerId = "Player1";
-        Settlement settlement = new Settlement(playerId);
+        when(mockRoad1.getOwnerPlayerId()).thenReturn(playerId);
+        when(mockRoad1.getNeighbour(any(SettlementPosition.class))).thenReturn(mockNeighbour1);
+        settlementPosition.addRoad(mockRoad1);
+        Settlement settlement = new Settlement(playerId, PlayerColor.BLUE);
         settlementPosition.setBuilding(settlement);
         assertEquals(settlement, settlementPosition.building);
+        assertEquals(playerId, settlementPosition.getBuildingOwner());
     }
 
     @Test
     void setBuildingShouldThrowErrorOnPlayerMismatch() throws GameException {
         String playerId = "Player1";
-        Settlement settlement1 = new Settlement(playerId);
+        Settlement settlement1 = new Settlement(playerId, PlayerColor.BLUE);
+        when(mockRoad1.getOwnerPlayerId()).thenReturn(playerId);
+        when(mockRoad1.getNeighbour(any(SettlementPosition.class))).thenReturn(mockNeighbour1);
+        settlementPosition.addRoad(mockRoad1);
         settlementPosition.setBuilding(settlement1);
         assertEquals(settlement1, settlementPosition.building);
 
         String secondPlayerId = "Player2";
-        Settlement settlement2 = new Settlement(secondPlayerId);
+        Settlement settlement2 = new Settlement(secondPlayerId, PlayerColor.BLUE);
         GameException ge = assertThrows(GameException.class, () -> settlementPosition.setBuilding(settlement2));
         assertEquals("Player mismatch when placing building: positionId = %s, playerId = %s".formatted(settlementPosition.id, secondPlayerId), ge.getMessage());
     }
 
+    @Test
+    void setBuildingShouldThrowErrorWhenSpacingRuleGetsViolated() throws GameException {
+        String playerId = "Player1";
+        when(mockRoad1.getOwnerPlayerId()).thenReturn(playerId);
+        when(mockRoad1.getNeighbour(any(SettlementPosition.class))).thenReturn(mockNeighbour1);
+        when(mockNeighbour1.getBuildingOwner()).thenReturn(playerId);
+        settlementPosition.addRoad(mockRoad1);
+
+        String secondPlayerId = "Player2";
+        Settlement settlement = new Settlement(secondPlayerId, PlayerColor.BLUE);
+        GameException ge = assertThrows(GameException.class, () -> settlementPosition.setBuilding(settlement));
+        assertEquals("Placement of building is not allowed -> spacing rule violated: positionId = %s, playerId = %s".formatted(settlementPosition.id, secondPlayerId), ge.getMessage());
+    }
+
+    @Test
+    void setBuildingShouldThrowErrorWhenPlayerHasNoAdjacentRoad() throws GameException {
+        String playerId = "Player1";
+        Settlement settlement = new Settlement(playerId, PlayerColor.BLUE);
+        GameException ge = assertThrows(GameException.class, () -> settlementPosition.setBuilding(settlement));
+        assertEquals("Placement of building is not allowed -> no owned road adjacent: positionId = %s, playerId = %s".formatted(settlementPosition.id, playerId), ge.getMessage());
+    }
+
+    @Test
+    void setBuildingShouldThrowErrorWhenOnlyAnotherPlayerHasAdjacentRoad() throws GameException {
+        String playerId = "Player1";
+        when(mockRoad1.getOwnerPlayerId()).thenReturn(playerId);
+        when(mockRoad1.getNeighbour(any(SettlementPosition.class))).thenReturn(mockNeighbour1);
+        settlementPosition.addRoad(mockRoad1);
+
+        String secondPlayerId = "Player2";
+        Settlement settlement = new Settlement(secondPlayerId, PlayerColor.BLUE);
+        GameException ge = assertThrows(GameException.class, () -> settlementPosition.setBuilding(settlement));
+        assertEquals("Placement of building is not allowed -> no owned road adjacent: positionId = %s, playerId = %s".formatted(settlementPosition.id, secondPlayerId), ge.getMessage());
+    }
+
+    @Test
+    void setBuildingShouldWorkIfTwoPlayersHaveAdjacentRoads() throws GameException {
+        String playerId = "Player1";
+        String secondPlayerId = "Player2";
+        when(mockRoad1.getOwnerPlayerId()).thenReturn(playerId);
+        when(mockRoad1.getNeighbour(any(SettlementPosition.class))).thenReturn(mockNeighbour1);
+        when(mockRoad2.getOwnerPlayerId()).thenReturn(secondPlayerId);
+        when(mockRoad2.getNeighbour(any(SettlementPosition.class))).thenReturn(mockNeighbour2);
+        settlementPosition.addRoad(mockRoad1);
+        settlementPosition.addRoad(mockRoad2);
+
+        Settlement settlement = new Settlement(secondPlayerId, PlayerColor.BLUE);
+        settlementPosition.setBuilding(settlement);
+        assertEquals(settlement, settlementPosition.building);
+        assertEquals(secondPlayerId, settlementPosition.getBuildingOwner());
+    }
+
     @Test
     void testToJsonInitialState() {
 
@@ -298,12 +369,13 @@ void testToJsonWithCoordinatesAndBuildingSet() throws GameException {
         double expectedX = -25.5;
         double expectedY = 100.1;
         String buildingOwner = "Player1";
-        String expectedBuildingString = "Settlement{owner=" + buildingOwner + "}";
+        PlayerColor color = PlayerColor.LIGHT_ORANGE;
 
         // Use a mock Building
-        Building mockBuilding = mock(Building.class);
-        when(mockBuilding.toString()).thenReturn(expectedBuildingString);
-        when(mockBuilding.getOwnerPlayerId()).thenReturn(buildingOwner);
+        Building mockBuilding = new Settlement(buildingOwner, color);
+        when(mockRoad1.getOwnerPlayerId()).thenReturn(buildingOwner);
+        when(mockRoad1.getNeighbour(any(SettlementPosition.class))).thenReturn(mockNeighbour1);
+        settlementPosition.addRoad(mockRoad1);
 
         settlementPosition.setCoordinates(expectedX, expectedY);
         settlementPosition.setBuilding(mockBuilding);
@@ -319,7 +391,7 @@ void testToJsonWithCoordinatesAndBuildingSet() throws GameException {
 
         // Check Building (should be the string from building.toString())
         assertTrue(jsonNode.has("building"), "JSON should contain 'building' field");
-        assertEquals(expectedBuildingString, jsonNode.get("building").asText(), "Building string should match the building's toString() output");
+        assertEquals(mockBuilding.toJson().asText(), jsonNode.get("building").asText(), "Building string should match the building's toString() output");
 
         // Check Coordinates
         assertTrue(jsonNode.has("coordinates"), "JSON should contain 'coordinates' field");
diff --git a/src/test/java/com/example/cataniaunited/game/buildings/BuildingTest.java b/src/test/java/com/example/cataniaunited/game/buildings/BuildingTest.java
new file mode 100644
index 00000000..fb397680
--- /dev/null
+++ b/src/test/java/com/example/cataniaunited/game/buildings/BuildingTest.java
@@ -0,0 +1,51 @@
+package com.example.cataniaunited.game.buildings;
+
+import com.example.cataniaunited.exception.GameException;
+import com.example.cataniaunited.player.PlayerColor;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import io.quarkus.test.junit.QuarkusTest;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@QuarkusTest
+class BuildingTest {
+
+    @Test
+    void testToJson() throws GameException {
+        String playerId = "player1";
+        PlayerColor color = PlayerColor.LIGHT_ORANGE;
+        var building = new TestBuilding(playerId, color);
+
+        ObjectNode buildingJson = building.toJson();
+
+        assertEquals(playerId, buildingJson.get("owner").asText());
+        assertEquals(color.getHexCode(), buildingJson.get("color").asText());
+        assertEquals("TestBuilding", buildingJson.get("type").asText());
+    }
+
+    @Test
+    void constructorShouldThrowExceptionWhenPlayerIdIsNull() {
+        GameException ge = assertThrows(GameException.class, () -> new TestBuilding(null, PlayerColor.LAVENDER));
+        assertEquals("Owner Id of building must not be empty", ge.getMessage());
+    }
+
+    @Test
+    void constructorShouldThrowExceptionWhenPlayerIdIsEmpty() {
+        GameException ge = assertThrows(GameException.class, () -> new TestBuilding("", PlayerColor.LAVENDER));
+        assertEquals("Owner Id of building must not be empty", ge.getMessage());
+    }
+
+    @Test
+    void constructorShouldThrowExceptionWhenColorIsNull() {
+        GameException ge = assertThrows(GameException.class, () -> new TestBuilding("player1", null));
+        assertEquals("Color of building must not be null", ge.getMessage());
+    }
+}
+
+class TestBuilding extends Building {
+    protected TestBuilding(String playerId, PlayerColor color) throws GameException {
+        super(playerId, color);
+    }
+}
diff --git a/src/test/java/com/example/cataniaunited/lobby/LobbyServiceImplTest.java b/src/test/java/com/example/cataniaunited/lobby/LobbyServiceImplTest.java
index eeb5e88a..5b300e5b 100644
--- a/src/test/java/com/example/cataniaunited/lobby/LobbyServiceImplTest.java
+++ b/src/test/java/com/example/cataniaunited/lobby/LobbyServiceImplTest.java
@@ -3,25 +3,37 @@
 import com.example.cataniaunited.exception.GameException;
 import com.example.cataniaunited.player.PlayerColor;
 import io.quarkus.test.junit.QuarkusTest;
-import jakarta.inject.Inject;
+import io.quarkus.test.junit.mockito.InjectSpy;
 import org.jboss.logging.Logger;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
-import static org.junit.jupiter.api.Assertions.*;
-import java.util.*;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
 
 @QuarkusTest
 class LobbyServiceImplTest {
+    private static final Logger logger = Logger.getLogger(LobbyServiceImplTest.class);
+
+    @InjectSpy
+    LobbyServiceImpl lobbyService;
 
     @BeforeEach
     void setUp() {
         lobbyService.clearLobbies();
     }
-    private static final Logger logger = Logger.getLogger(LobbyServiceImplTest.class);
-
-    @Inject
-    LobbyServiceImpl lobbyService;
 
     @Test
     void testCreateLobby() {
@@ -56,8 +68,9 @@ void testGeneratedLobbyIdFormat() {
                     "Lobby Id should be in the format abc123 or 123abc");
         }
     }
+
     @Test
-    void testNoDuplicateLobbyIds () {
+    void testNoDuplicateLobbyIds() {
         Set<String> ids = new HashSet<>();
 
         for (int i = 0; i < 500; i++) {
@@ -68,7 +81,7 @@ void testNoDuplicateLobbyIds () {
     }
 
     @Test
-    void testJoinLobbyByValidCode () throws GameException {
+    void testJoinLobbyByValidCode() throws GameException {
         String hostPlayer = "HostPlayer";
         String joiningPlayer = "NewPlayer";
 
@@ -89,7 +102,7 @@ void testJoinLobbyByValidCode () throws GameException {
     }
 
     @Test
-    void testJoinLobbyByInvalidCode (){
+    void testJoinLobbyByInvalidCode() {
         boolean joined = lobbyService.joinLobbyByCode("InvalidCode", "New Player");
 
         assertFalse(joined, "Player should not be able to join the lobby with a valid code");
@@ -110,7 +123,7 @@ void testJoinLobbyAssignsUniqueColor() throws GameException {
     }
 
     @Test
-    void testJoinLobbyFailsWhenNoColorsAvailable (){
+    void testJoinLobbyFailsWhenNoColorsAvailable() {
         String lobbyId = lobbyService.createLobby("HostPlayer");
 
         for (int i = 0; i < PlayerColor.values().length; i++) {
@@ -134,14 +147,14 @@ void testRemovePlayerFromLobby() throws GameException {
     }
 
     @Test
-    void testRemovePlayerRestoresColor(){
+    void testRemovePlayerRestoresColor() {
         String lobbyId = lobbyService.createLobby("HostPlayer");
         lobbyService.joinLobbyByCode(lobbyId, "Player1");
 
         int colorPoolSizeBefore = PlayerColor.values().length - 2;
         lobbyService.removePlayerFromLobby(lobbyId, "Player1");
 
-        assertEquals(PlayerColor.values().length-1, colorPoolSizeBefore + 1);
+        assertEquals(PlayerColor.values().length - 1, colorPoolSizeBefore + 1);
     }
 
     @Test
@@ -154,4 +167,44 @@ void testRemovePlayerNotInLobby() {
         assertFalse(lobby.getPlayers().contains("GhostPlayer"));
     }
 
+    @Test
+    void getPlayerColorShouldThrowExceptionIfPlayerHasNoColor() throws GameException {
+        String lobbyId = "lobby1";
+        String playerId = "Player1";
+        Lobby lobbyMock = mock(Lobby.class);
+        when(lobbyMock.getPlayerColor(playerId)).thenReturn(null);
+        doReturn(lobbyMock).when(lobbyService).getLobbyById(lobbyId);
+        GameException ge = assertThrows(GameException.class, () -> lobbyService.getPlayerColor(lobbyId, playerId));
+        assertEquals("No color for player found: playerId=%s, lobbyId=%s".formatted(playerId, lobbyId), ge.getMessage());
+    }
+
+    @Test
+    void isPlayerTurnShouldThrowExceptionForNonExistingLobby() throws GameException {
+        String lobbyId = "NonExistingLobby";
+        GameException ge = assertThrows(GameException.class, () -> {
+            lobbyService.isPlayerTurn(lobbyId, "NonExistingPlayer");
+        });
+        assertEquals("Lobby with id %s not found".formatted(lobbyId), ge.getMessage());
+    }
+
+    @Test
+    void isPlayerTurnShouldReturnTrueForPlayerTurn() throws GameException {
+        String playerId = "player1";
+        String lobbyId = lobbyService.createLobby(playerId);
+        Lobby lobby = lobbyService.getLobbyById(lobbyId);
+        lobby.setActivePlayer(playerId);
+
+        assertTrue(lobbyService.isPlayerTurn(lobbyId, playerId));
+    }
+
+    @Test
+    void isPlayerTurnShouldReturnFalseForNotPlayerTurn() throws GameException {
+        String playerId = "player1";
+        String lobbyId = lobbyService.createLobby(playerId);
+        Lobby lobby = spy(lobbyService.getLobbyById(lobbyId));
+        lobby.setActivePlayer("anotherPlayer");
+
+        assertFalse(lobbyService.isPlayerTurn(lobbyId, playerId));
+    }
+
 }
\ No newline at end of file
diff --git a/src/test/java/com/example/cataniaunited/lobby/LobbyTest.java b/src/test/java/com/example/cataniaunited/lobby/LobbyTest.java
index a20b1eb7..fa61c952 100644
--- a/src/test/java/com/example/cataniaunited/lobby/LobbyTest.java
+++ b/src/test/java/com/example/cataniaunited/lobby/LobbyTest.java
@@ -2,9 +2,14 @@
 
 import com.example.cataniaunited.player.PlayerColor;
 import org.junit.jupiter.api.Test;
-import static org.junit.jupiter.api.Assertions.*;
+
 import java.util.Set;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
 class LobbyTest {
 
     @Test
@@ -31,7 +36,7 @@ void getPlayers_shouldReturnHostPlayer() {
     }
 
     @Test
-    void testRestoreColor_shouldOnlyAddColorIfNotPresent(){
+    void testRestoreColor_shouldOnlyAddColorIfNotPresent() {
         Lobby lobby = new Lobby("555xyz", "HostPlayer");
 
         PlayerColor color = lobby.assignAvailableColor();
@@ -46,4 +51,41 @@ void testRestoreColor_shouldOnlyAddColorIfNotPresent(){
         assertEquals(1, countAfter);
         assertEquals(countBefore, countAfter);
     }
+
+    @Test
+    void isPlayerTurnShouldReturnTrueForPlayerTurn() {
+        String playerId = "player1";
+        String lobbyId = "555xyz";
+        Lobby lobby = new Lobby(lobbyId, playerId);
+        lobby.setActivePlayer(playerId);
+        assertTrue(lobby.isPlayerTurn(playerId));
+    }
+
+    @Test
+    void isPlayerTurnShouldReturnFalseForNotPlayerTurn() {
+        String playerId = "player1";
+        String lobbyId = "555xyz";
+        Lobby lobby = new Lobby(lobbyId, playerId);
+        lobby.setActivePlayer("anotherPlayer");
+        assertFalse(lobby.isPlayerTurn(playerId));
+    }
+
+    @Test
+    void isPlayerTurnShouldReturnFalseIfPlayerIsNull() {
+        String playerId = "player1";
+        String lobbyId = "555xyz";
+        Lobby lobby = new Lobby(lobbyId, playerId);
+        lobby.setActivePlayer(playerId);
+        assertFalse(lobby.isPlayerTurn(null));
+    }
+
+    @Test
+    void getActivePlayerShouldReturnPlayer() {
+        String playerId = "player1";
+        String lobbyId = "555xyz";
+        Lobby lobby = new Lobby(lobbyId, playerId);
+        lobby.setActivePlayer(playerId);
+
+        assertEquals(playerId, lobby.getActivePlayer());
+    }
 }


Reviews:
user: login: towurzer
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-07T20:42:48Z
user: login: w0lphi
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-07T21:18:40Z

Review comments:
path: src/main/java/com/example/cataniaunited/api/GameWebSocket.java
user: login: towurzer
body: If we do anything with that error in the Frontend you could think about changing it? (No Lobby full or nonexistent)
If not. Just keep it that way. 

"throw new GameException("No lobby session");"
created_at: 2025-05-07T20:42:37Z
author_association: MEMBER
path: src/main/java/com/example/cataniaunited/api/GameWebSocket.java
user: login: w0lphi
body: The errors are currently not parsed in the app frontend, therefore I will leave it as is 
created_at: 2025-05-07T21:18:40Z
author_association: MEMBER

PR comments:
user: login: sonarqubecloud[bot]
created_at: 2025-05-07T20:16:25Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=CataniaUnited_catania-united-server&pullRequest=67) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [5 New issues](https://sonarcloud.io/project/issues?id=CataniaUnited_catania-united-server&pullRequest=67&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=CataniaUnited_catania-united-server&pullRequest=67&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=CataniaUnited_catania-united-server&pullRequest=67&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [96.4% Coverage on New Code](https://sonarcloud.io/component_measures?id=CataniaUnited_catania-united-server&pullRequest=67&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=CataniaUnited_catania-united-server&pullRequest=67&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=CataniaUnited_catania-united-server&pullRequest=67)


author_association: NONE