2025년 2월 25일

김동환·어제
0

오늘의 TIL (Today I Learned) - 마피아 게임 WebSocket 서버 개발

오늘 작업한 내용

오늘은 마피아 게임의 밤(NIGHT) 페이즈 로직을 집중적으로 개발하면서, 게임 진행에 필요한 핵심 기능들을 추가하고 개선했다.


1. 특정 역할(role)을 가진 살아있는 플레이어 찾기

  • getPlayerByRole(roomId: string, role: string): 특정 역할(예: 경찰, 의사, 마피아)을 가진 살아있는 플레이어의 ID를 반환하는 메서드를 구현했다.
  • Redis에 저장된 현재 게임 데이터에서 players 배열을 조회하여, 해당 역할을 가진 살아있는 플레이어를 필터링하여 ID를 반환하도록 설계했다.
  • 만약 해당 역할의 플레이어가 없다면 null을 반환한다.

2. 밤(NIGHT) 페이즈 시작 처리

  • startNightPhase(roomId: string):
    • 게임의 phasenight으로 설정하고, 밤 횟수(nightNumber)를 증가시킴.
    • 현재 게임에 남아있는 마피아 목록과 사망자 목록을 조회하여, 클라이언트에 밤 시작 이벤트를 전송함.
    • 게임 상태 변경을 위해 Redis에 데이터를 저장하고, 로그를 남겼다.

3. 경찰 조사 결과 처리

  • getPoliceResult(roomId: string):
    • 현재 살아있는 경찰이 조사한 대상의 역할(시민 또는 마피아)을 반환하는 기능을 구현했다.
    • 조사 대상이 없으면 경찰 ID만 반환하고, 조사한 대상이 있다면 마피아 여부를 판별하여 역할 정보를 제공한다.
    • 결과는 JSON 형식으로 { policeId, targetUserId, role } 형태로 반환됨.

4. 플레이어 사망 처리

  • markPlayerAsDead(roomId: string, playerId: number):
    • 특정 플레이어를 사망 처리(Alive → Dead) 하는 기능을 구현했다.
    • 해당 플레이어의 isAlive 값을 false로 변경하고, Redis에 반영함.

5. 밤 횟수(night count) 관리

  • getNightCount(roomId: string):
    • 밤이 진행될 때마다 nightNumber를 증가시키는 기능을 추가했다.
    • Redis에 nightNumber 값을 저장하여 밤 횟수를 지속적으로 관리할 수 있도록 설계했다.

6. 의사 보호 기능

  • setPlayerAlive(roomId: string, playerId: number):
    • 특정 플레이어를 살아있는 상태로 복구하는 기능을 추가했다.
    • 의사가 특정 플레이어를 보호하면, 해당 플레이어는 사망하지 않도록 처리함.
    • Redis의 players 데이터를 업데이트하여 상태를 반영함.

7. 밤 행동 완료 여부 저장

  • setNightActionComplete(roomId: string, role: 'mafia' | 'police' | 'doctor'):
    • 밤 동안 마피아, 경찰, 의사가 각자의 행동을 완료했는지 여부를 Redis에 저장하도록 구현했다.
    • 예를 들어, 마피아가 타겟을 선택했거나 경찰이 조사를 완료했다면, nightAction:mafia = true 와 같은 데이터를 저장함.

8. 모든 밤 행동 완료 여부 체크

  • checkAllNightActionsCompleted(roomId: string):
    • 마피아, 경찰, 의사가 모든 밤 행동을 완료했는지 확인하는 기능을 구현했다.
    • 살아있는 플레이어만 체크하며, 죽은 플레이어는 자동으로 완료된 것으로 간주함.
    • 모든 역할이 행동을 완료하면 true, 아직 완료되지 않았다면 false를 반환함.

9. 게임 종료 조건 체크

  • checkEndGame(roomId: string):
    • 게임이 종료될 조건을 검사하는 기능을 구현했다.
    • 남아있는 마피아 수와 시민 수를 비교하여 승리 조건을 판단한다.
      • 마피아 ≥ 시민이면 마피아 승리
      • 마피아가 0명이면 시민 승리
    • 게임이 종료될 경우 { isGameOver: true, winningTeam: 'mafia' | 'citizens' } 형식으로 결과를 반환함.

10. 밤 결과 처리 (마피아, 경찰, 의사 능력 반영)

  • processNightResult(roomId: string):
    • 밤이 끝났을 때, 마피아의 공격, 의사의 보호, 경찰의 조사 결과를 반영하는 기능을 구현했다.
    • 마피아가 지목한 플레이어 중 랜덤으로 한 명을 선택하여 사망 처리하지만, 의사가 보호한 경우 생존함.
    • 경찰 조사 결과도 반환하여 경찰이 마피아를 정확히 조사했는지 여부를 전달함.
    • 최종 결과는 { killedUserId, details, policeResult } 형태로 반환됨.

11. 밤이 끝나고 낮(DAY) 페이즈로 전환

  • triggerNightProcessing(roomId: string):
    • 모든 밤 행동이 완료되면 자동으로 밤 결과를 처리하고, 게임이 종료되었는지 검사함.
    • 게임이 끝나지 않았다면 낮(DAY) 페이즈로 전환되도록 구현함.
    • Redis에 phase = 'day'로 업데이트한 뒤, 낮이 시작되도록 설정함.

12. 현재 게임의 Phase(낮/밤) 가져오기

  • getGamePhase(roomId: string):
    • 게임의 현재 상태(낮인지, 밤인지)를 조회하는 기능을 구현함.
    • Redis에서 phase 값을 읽어와 현재 진행 중인 페이즈를 반환함.

오늘의 배운 점 & 개선할 점

배운 점

  • Redis를 활용한 게임 상태 관리 방법을 익혔고, WebSocket 기반의 이벤트 처리 구조를 정리할 수 있었다.
  • 마피아, 경찰, 의사의 행동을 비동기적으로 처리하면서, 게임 로직을 좀 더 깔끔하게 정리할 수 있었다.
  • 게임 종료 로직을 명확하게 정의하여, 게임이 자연스럽게 종료될 수 있도록 개선했다.

개선할 점

  • 밤 페이즈에서 마피아의 투표 방식(랜덤 vs 다수결 반영)을 좀 더 정교하게 만들 필요가 있음.
  • 낮(DAY) 페이즈에서 플레이어들이 토론하고 투표하는 기능을 추가해야 함.
  • 클라이언트 측에서 WebSocket을 통해 밤이 끝난 후 결과를 적절히 UI에 표시하는 부분을 추가해야 함.

완성도를 높여서 더욱 재밌는 마피아 게임을 만들어보자!

profile
Node.js 7기

0개의 댓글

관련 채용 정보