diff --git a/backend/src/main/java/io/f1/backend/domain/game/Player.java b/backend/src/main/java/io/f1/backend/domain/game/Player.java deleted file mode 100644 index e3fff7ab..00000000 --- a/backend/src/main/java/io/f1/backend/domain/game/Player.java +++ /dev/null @@ -1,12 +0,0 @@ -package io.f1.backend.domain.game; - -public class Player { - - public String nickname; - - private boolean isReady = false; - - private ConnectionState state; - - private int correctCount = 0; -} diff --git a/backend/src/main/java/io/f1/backend/domain/game/Room.java b/backend/src/main/java/io/f1/backend/domain/game/Room.java deleted file mode 100644 index d5929f8c..00000000 --- a/backend/src/main/java/io/f1/backend/domain/game/Room.java +++ /dev/null @@ -1,27 +0,0 @@ -package io.f1.backend.domain.game; - -import io.f1.backend.domain.question.entity.Question; - -import lombok.AllArgsConstructor; - -import java.time.LocalDateTime; -import java.util.List; -import java.util.Map; - -@AllArgsConstructor -public class Room { - - private final Long id; - - private final RoomSetting roomSetting; - private GameSetting gameSetting; - private RoomState state = RoomState.WAITING; - - private Player host; - - private List questions; - - private Map playerSessionMap; - - private final LocalDateTime createdAt = LocalDateTime.now(); -} diff --git a/backend/src/main/java/io/f1/backend/domain/game/RoomManager.java b/backend/src/main/java/io/f1/backend/domain/game/RoomManager.java deleted file mode 100644 index 099cff56..00000000 --- a/backend/src/main/java/io/f1/backend/domain/game/RoomManager.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.f1.backend.domain.game; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -public class RoomManager { - private final Map rooms = new ConcurrentHashMap<>(); -} diff --git a/backend/src/main/java/io/f1/backend/domain/game/RoomSetting.java b/backend/src/main/java/io/f1/backend/domain/game/RoomSetting.java deleted file mode 100644 index ebb441f8..00000000 --- a/backend/src/main/java/io/f1/backend/domain/game/RoomSetting.java +++ /dev/null @@ -1,3 +0,0 @@ -package io.f1.backend.domain.game; - -public record RoomSetting(String title, int maxUserCount, String password) {} diff --git a/backend/src/main/java/io/f1/backend/domain/game/api/RoomController.java b/backend/src/main/java/io/f1/backend/domain/game/api/RoomController.java new file mode 100644 index 00000000..a276b9d1 --- /dev/null +++ b/backend/src/main/java/io/f1/backend/domain/game/api/RoomController.java @@ -0,0 +1,38 @@ +package io.f1.backend.domain.game.api; + +import io.f1.backend.domain.game.app.RoomService; +import io.f1.backend.domain.game.dto.request.RoomCreateRequest; +import io.f1.backend.domain.game.dto.response.RoomCreateResponse; + +import jakarta.validation.Valid; + +import lombok.RequiredArgsConstructor; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequestMapping("/rooms") +@RequiredArgsConstructor +public class RoomController { + + private final RoomService roomService; + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public RoomCreateResponse saveRoom(@RequestBody @Valid RoomCreateRequest request) { + + Map loginUser = new HashMap<>(); + loginUser.put("id", 1L); + loginUser.put("nickname", "빵야빵야"); + + return roomService.saveRoom(request, loginUser); + } +} diff --git a/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java b/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java new file mode 100644 index 00000000..14c44f85 --- /dev/null +++ b/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java @@ -0,0 +1,41 @@ +package io.f1.backend.domain.game.app; + +import static io.f1.backend.domain.game.mapper.RoomMapper.toRoomSetting; + +import io.f1.backend.domain.game.dto.request.RoomCreateRequest; +import io.f1.backend.domain.game.dto.response.RoomCreateResponse; +import io.f1.backend.domain.game.model.GameSetting; +import io.f1.backend.domain.game.model.Player; +import io.f1.backend.domain.game.model.Room; +import io.f1.backend.domain.game.model.RoomSetting; +import io.f1.backend.domain.game.store.RoomRepository; + +import lombok.RequiredArgsConstructor; + +import org.springframework.stereotype.Service; + +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; + +@Service +@RequiredArgsConstructor +public class RoomService { + + private final RoomRepository roomRepository; + private final AtomicLong roomIdGenerator = new AtomicLong(0); + + public RoomCreateResponse saveRoom(RoomCreateRequest request, Map loginUser) { + + // todo 제일 작은 index quizId 가져와서 gameSetting(round 설정) + GameSetting gameSetting = new GameSetting(1L, 10, 60); + // todo security에서 가져오는걸로 변경 + Player host = new Player((Long) loginUser.get("id"), loginUser.get("nickname").toString()); + RoomSetting roomSetting = toRoomSetting(request); + + Long newId = roomIdGenerator.incrementAndGet(); + + roomRepository.saveRoom(new Room(newId, roomSetting, gameSetting, host)); + + return new RoomCreateResponse(newId); + } +} diff --git a/backend/src/main/java/io/f1/backend/domain/game/dto/request/RoomCreateRequest.java b/backend/src/main/java/io/f1/backend/domain/game/dto/request/RoomCreateRequest.java new file mode 100644 index 00000000..30a94481 --- /dev/null +++ b/backend/src/main/java/io/f1/backend/domain/game/dto/request/RoomCreateRequest.java @@ -0,0 +1,15 @@ +package io.f1.backend.domain.game.dto.request; + +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +public record RoomCreateRequest( + @NotBlank(message = "방 제목은 필수입니다.") String roomName, + @NotNull(message = "인원 수 입력은 필수입니다.") + @Min(value = 2, message = "방 인원 수는 최소 2명입니다.") + @Max(value = 8, message = "방 인원 수는 최대 8명 입니다.") + Integer maxUserCount, + @NotNull String password, + @NotNull boolean locked) {} diff --git a/backend/src/main/java/io/f1/backend/domain/game/dto/response/RoomCreateResponse.java b/backend/src/main/java/io/f1/backend/domain/game/dto/response/RoomCreateResponse.java new file mode 100644 index 00000000..042545a7 --- /dev/null +++ b/backend/src/main/java/io/f1/backend/domain/game/dto/response/RoomCreateResponse.java @@ -0,0 +1,3 @@ +package io.f1.backend.domain.game.dto.response; + +public record RoomCreateResponse(Long roomId) {} diff --git a/backend/src/main/java/io/f1/backend/domain/game/mapper/RoomMapper.java b/backend/src/main/java/io/f1/backend/domain/game/mapper/RoomMapper.java new file mode 100644 index 00000000..648bb25d --- /dev/null +++ b/backend/src/main/java/io/f1/backend/domain/game/mapper/RoomMapper.java @@ -0,0 +1,12 @@ +package io.f1.backend.domain.game.mapper; + +import io.f1.backend.domain.game.dto.request.RoomCreateRequest; +import io.f1.backend.domain.game.model.RoomSetting; + +public class RoomMapper { + + public static RoomSetting toRoomSetting(RoomCreateRequest request) { + return new RoomSetting( + request.roomName(), request.maxUserCount(), request.locked(), request.password()); + } +} diff --git a/backend/src/main/java/io/f1/backend/domain/game/ConnectionState.java b/backend/src/main/java/io/f1/backend/domain/game/model/ConnectionState.java similarity index 61% rename from backend/src/main/java/io/f1/backend/domain/game/ConnectionState.java rename to backend/src/main/java/io/f1/backend/domain/game/model/ConnectionState.java index 34c290e6..6ae6aa0c 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/ConnectionState.java +++ b/backend/src/main/java/io/f1/backend/domain/game/model/ConnectionState.java @@ -1,4 +1,4 @@ -package io.f1.backend.domain.game; +package io.f1.backend.domain.game.model; public enum ConnectionState { DISCONNECTED, diff --git a/backend/src/main/java/io/f1/backend/domain/game/GameSetting.java b/backend/src/main/java/io/f1/backend/domain/game/model/GameSetting.java similarity index 58% rename from backend/src/main/java/io/f1/backend/domain/game/GameSetting.java rename to backend/src/main/java/io/f1/backend/domain/game/model/GameSetting.java index 95167b32..7643d861 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/GameSetting.java +++ b/backend/src/main/java/io/f1/backend/domain/game/model/GameSetting.java @@ -1,5 +1,10 @@ -package io.f1.backend.domain.game; +package io.f1.backend.domain.game.model; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor public class GameSetting { private Long quizId; diff --git a/backend/src/main/java/io/f1/backend/domain/game/model/Player.java b/backend/src/main/java/io/f1/backend/domain/game/model/Player.java new file mode 100644 index 00000000..3d3230c1 --- /dev/null +++ b/backend/src/main/java/io/f1/backend/domain/game/model/Player.java @@ -0,0 +1,22 @@ +package io.f1.backend.domain.game.model; + +import lombok.Getter; + +@Getter +public class Player { + + public final Long id; + + public final String nickname; + + private boolean isReady = false; + + private ConnectionState state = ConnectionState.CONNECTED; + + private int correctCount = 0; + + public Player(Long id, String nickname) { + this.id = id; + this.nickname = nickname; + } +} diff --git a/backend/src/main/java/io/f1/backend/domain/game/model/Room.java b/backend/src/main/java/io/f1/backend/domain/game/model/Room.java new file mode 100644 index 00000000..ba0c56b5 --- /dev/null +++ b/backend/src/main/java/io/f1/backend/domain/game/model/Room.java @@ -0,0 +1,38 @@ +package io.f1.backend.domain.game.model; + +import io.f1.backend.domain.question.entity.Question; + +import lombok.Getter; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Getter +public class Room { + + private final Long id; + + private final RoomSetting roomSetting; + + private GameSetting gameSetting; + + private RoomState state = RoomState.WAITING; + + private Player host; + + private List questions = new ArrayList<>(); + + private Map playerSessionMap = new ConcurrentHashMap<>(); + + private final LocalDateTime createdAt = LocalDateTime.now(); + + public Room(Long id, RoomSetting roomSetting, GameSetting gameSetting, Player host) { + this.id = id; + this.roomSetting = roomSetting; + this.gameSetting = gameSetting; + this.host = host; + } +} diff --git a/backend/src/main/java/io/f1/backend/domain/game/model/RoomSetting.java b/backend/src/main/java/io/f1/backend/domain/game/model/RoomSetting.java new file mode 100644 index 00000000..7cf6b985 --- /dev/null +++ b/backend/src/main/java/io/f1/backend/domain/game/model/RoomSetting.java @@ -0,0 +1,3 @@ +package io.f1.backend.domain.game.model; + +public record RoomSetting(String roomName, int maxUserCount, boolean locked, String password) {} diff --git a/backend/src/main/java/io/f1/backend/domain/game/RoomState.java b/backend/src/main/java/io/f1/backend/domain/game/model/RoomState.java similarity index 61% rename from backend/src/main/java/io/f1/backend/domain/game/RoomState.java rename to backend/src/main/java/io/f1/backend/domain/game/model/RoomState.java index 4898c776..50d30dca 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/RoomState.java +++ b/backend/src/main/java/io/f1/backend/domain/game/model/RoomState.java @@ -1,4 +1,4 @@ -package io.f1.backend.domain.game; +package io.f1.backend.domain.game.model; public enum RoomState { WAITING, diff --git a/backend/src/main/java/io/f1/backend/domain/game/store/RoomRepository.java b/backend/src/main/java/io/f1/backend/domain/game/store/RoomRepository.java new file mode 100644 index 00000000..d03aab93 --- /dev/null +++ b/backend/src/main/java/io/f1/backend/domain/game/store/RoomRepository.java @@ -0,0 +1,7 @@ +package io.f1.backend.domain.game.store; + +import io.f1.backend.domain.game.model.Room; + +public interface RoomRepository { + void saveRoom(Room room); +} diff --git a/backend/src/main/java/io/f1/backend/domain/game/store/RoomRepositoryImpl.java b/backend/src/main/java/io/f1/backend/domain/game/store/RoomRepositoryImpl.java new file mode 100644 index 00000000..132e0d9e --- /dev/null +++ b/backend/src/main/java/io/f1/backend/domain/game/store/RoomRepositoryImpl.java @@ -0,0 +1,24 @@ +package io.f1.backend.domain.game.store; + +import io.f1.backend.domain.game.model.Room; + +import org.springframework.stereotype.Repository; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Repository +public class RoomRepositoryImpl implements RoomRepository { + + private final Map roomMap = new ConcurrentHashMap<>(); + + @Override + public void saveRoom(Room room) { + roomMap.put(room.getId(), room); + } + + // 테스트 전용 메소드 + public Room getRoomForTest(Long roomId) { + return roomMap.get(roomId); + } +} diff --git a/backend/src/test/java/io/f1/backend/domain/game/store/RoomRepositoryTests.java b/backend/src/test/java/io/f1/backend/domain/game/store/RoomRepositoryTests.java new file mode 100644 index 00000000..81067624 --- /dev/null +++ b/backend/src/test/java/io/f1/backend/domain/game/store/RoomRepositoryTests.java @@ -0,0 +1,64 @@ +package io.f1.backend.domain.game.store; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.f1.backend.domain.game.dto.request.RoomCreateRequest; +import io.f1.backend.domain.game.model.GameSetting; +import io.f1.backend.domain.game.model.Player; +import io.f1.backend.domain.game.model.Room; +import io.f1.backend.domain.game.model.RoomSetting; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +class RoomRepositoryTests { + + RoomRepositoryImpl roomRepository; + + @BeforeEach + void setUp() { + roomRepository = new RoomRepositoryImpl(); + } + + @Test + @DisplayName("게임 방 생성 테스트") + void saveRoom_test() { + + RoomCreateRequest request = new RoomCreateRequest("방제", 3, "password1", true); + Map loginUser = new HashMap<>(); + + loginUser.put("id", 1L); + loginUser.put("nickname", "빵야빵야"); + + GameSetting gameSetting = new GameSetting(1L, 10, 60); + + Player host = new Player((Long) loginUser.get("id"), loginUser.get("nickname").toString()); + + RoomSetting roomSetting = + new RoomSetting( + request.roomName(), + request.maxUserCount(), + request.locked(), + request.password()); + + Long newId = 1L; + + Room newRoom = new Room(newId, roomSetting, gameSetting, host); + + roomRepository.saveRoom(newRoom); + + Room savedRoom = roomRepository.getRoomForTest(newId); + + assertThat(savedRoom.getHost().getId()).isEqualTo(loginUser.get("id")); + assertThat(savedRoom.getHost().getNickname()).isEqualTo(loginUser.get("nickname")); + + assertThat(savedRoom.getRoomSetting().roomName()).isEqualTo(request.roomName()); + assertThat(savedRoom.getRoomSetting().maxUserCount()).isEqualTo(request.maxUserCount()); + assertThat(savedRoom.getRoomSetting().locked()).isEqualTo(request.locked()); + assertThat(savedRoom.getRoomSetting().password()).isEqualTo(request.password()); + } +}