본문 바로가기

부트캠프

Nalgangdoo_Project 2일차

팀별과제 2일차
각자 담당한 API를 만들기 시작함

구현해야 하는 기능

① . 친선게임 
1.게임을 할 유저를 지목하여 게임을 플레이할수있음
2.토큰이 필요한 기능이다. 즉 회원가입 , 로그인이 필요하다.
3.한명의 유저는 하나의 팀을 가지고있다. 하나의 팀은 3개의 캐릭터를 가지고있으며 캐릭터가 3개 미만이라면 게임을 플레이할 수없음
4.유저가 보유한 캐릭터의 스탯의 총 합을 구해 승률을 비교해야함
5.승/패는 스탯을 비교하여 a팀과 b팀이 랜덤하게 결정됨
6.점수가 같다면 무승부도 가능
7.게임이 끝난다면 결과를 리턴해주고 유저의 승/무/패 카운터를 추가 해줘야함
1.게임할 유저를 지목하기위해 URL에 파라미터로 상대의 아이디를 넣어준다.
2.토큰이 필요한 기능이므로 토큰 검증을 위한 미들웨어도 추가
router.post("/games/:userId", authMiddleware, async (req, res, next) => {
}

3.한명의 유저가 팀을 편성했는지 확인하기위해 유저의정보를 불러올때 incloud쿼리를 사용해
현재 사용자의 캐릭터와 상대 사용자의 캐릭터를 조회한다.

  //현재 사용자의 캐릭터 가져오기
    const currentUserCharacters = await prisma.account.findFirst({
      where: { userId: currentUserId },
      include: { characters: true },
    });

    //상대 사용자의 캐릭터 가져오기
    const enemyUserCharacters = await prisma.account.findFirst({
      where: { userId },
      include: { characters: true },
    });


팀 구성이 완료된 캐릭터가 정확하게 3개인지 체크하기위해 filter메서드를 사용해 isFormation값이 true인 캐릭터들만 필터링해준다.
현재 사용자와 상대 사용자를 따로 관리해줘야함!

    //팀 구성 인원 체크
    currentUserCharacters.characters = currentUserCharacters.characters.filter(
      (character) => character.isFormation === true
    );

    enemyUserCharacters.characters = enemyUserCharacters.characters.filter(
      (character) => character.isFormation === true
    );

만약 팀 구성 인원이 3명보다 많거나 적다면 에러메시지를 출력해준다.

    if (currentUserCharacters.characters.length !== 3) {
      return res
        .status(400)
        .json({ message: "현재 사용자의 팀 구성원이 3명이 아닙니다." });
    }
    console.log(currentUserCharacters);

    if (enemyUserCharacters.characters.length !== 3) {
      return res
        .status(400)
        .json({ message: "상대 사용자의 팀 구성원이 3명이 아닙니다." });
    }


4.유저가 보유한 캐릭터의 스텟을 비교하기위해 가중치를 생성하고 
각팀의 총 점수를  계산하기 위해 현재 사용자와 상대 사용자가 가진 캐릭터를map메서드를 사용해 새로운 배열로 받아와 각자 변수에 할당했다.

   //스텟 가중치
    const statWeight = {
      speed: 0.1,
      goalDetermination: 0.2,
      shootPower: 0.15,
      defense: 0.4,
      stamina: 0.2,
    };
   // 현재 사용자의 캐릭터 ID 배열
    const currentUserCharacterIds = currentUserCharacters.characters.map(
      (char) => char.characterId
    );

    // 상대 사용자의 캐릭터 ID 배열
    const enemyUserCharacterIds = enemyUserCharacters.characters.map(
      (char) => char.characterId
    );


각팀의 캐릭터 정보를 가져와 스탯에 가중치를 곱하여 합을 구한다.
이를 위해 Promise.all을 사용하여 현재 유저와 상대 유저의 캐릭터ID를 배열로 반환하게함
Promise.all은 여럭의 프로미스를 동시에 실행하여 모든 프로미스가 성공할때까지 기다린다. 코드 효율성을 높임
여튼 Promise.all로 얻은 배열을 구조분해할당을 통해 변수에 할당해줌

 // 각 팀의 캐릭터 정보 가져오기
    const [currentUserCharactersDetails, enemyUserCharactersDetails] =
      await Promise.all([
        prisma.character.findMany({
          where: { characterId: { in: currentUserCharacterIds } },
        }),
        prisma.character.findMany({
          where: { characterId: { in: enemyUserCharacterIds } },
        }),
      ]);

map으로 뽑은 배열안에 있는캐릭터 아이디가 조회하려는 캐릭터아이디s라는 상세정보를~ 이라는 조건추가

이후 뽑아온 값을 calculateScore라는 함수를 생성하여 반복문을통해 계산해주고 결과값을 리턴해줌

    // 점수 계산 함수
    function calculateScore(characters) {
      let totalScore = 0;
      for (let i = 0; i < characters.length; i++) {
        const score =
          characters[i].speed * statWeight.speed +
          characters[i].goalDetermination * statWeight.goalDetermination +
          characters[i].shootPower * statWeight.shootPower +
          characters[i].defense * statWeight.defense +
          characters[i].stamina * statWeight.stamina;
        totalScore += score;
      }
      return totalScore;
    }


5.승/패 비교

scoreA팀의 점수를 현재 사용자의 캐릭터점수의 합으로 선언
scoreB팀의 점수를 상대 사용자의 캐릭터점수의 합으로 선언

   const scoreA = calculateScore(currentUserCharactersDetails); //현재 사용자의 팀 점수
    const scoreB = calculateScore(enemyUserCharactersDetails); //상대 사용자의 팀 점수


승패를 결정하기 위해 두 팀의 팀점수를 합치고 랜덤메서드를 사용함 점수가 높을수록 승률이 올라가도록 설정

    const maxScore = scoreA + scoreB;
    const rendomWinner = Math.random() * maxScore; //팀 스탯 점수에 비례하여 승률확인


6.점수가 같을경우 무승부가 나오도록처리하고 drowCount가 1씩 올라가도록 작성함

//무승부일 경우
    if (scoreA === scoreB) {
      //현재 사용자
      await prisma.account.update({
        where: { userId: currentUserId },
        data: { drowCount: { increment: 1 } },
      });
      //상대 사용자
      await prisma.account.update({
        where: { userId },
        data: { drowCount: { increment: 1 } },
      });
      return res.status(200).json({ message: "무승부 입니다!" });
    }


7 .조건문을 사용해 현재 사용자가 이겼을 경우와 상대 사용자가 이겼을 경우를 각각 정의함
랜덤 메서드를사용해 랜덤한 값을 도출하도록 설정하고 result변수에 결과를 할당해줌
a팀이 이긴다면 현재 사용자의 wincount 상대 사용자는 loseCount가 1씩 올라가도록 설정함
위 과정이 모두 끝났다면 result값을 응답해줌

   if (rendomWinner < scoreA) {
      //현재 유저 승리 처리
      const aScore = Math.floor(Math.random() * 4) + 2;
      const bScore = Math.floor(Math.random() * Math.min(5, aScore)); //A스코어보다 작은값
      result = `${currentUserId}팀 승리: ${currentUserId} :${aScore} - ${bScore} : ${userId}`;

      //승리팀
      await prisma.account.update({
        where: { userId: currentUserId },
        data: {
          winCount: { increment: 1 },
        },
      });

      //패배팀
      await prisma.account.update({
        where: { userId },
        data: {
          loseCount: { increment: 1 },
        },
      });
    } else {
      //상대 유저 승리 처리
      const bScore = Math.floor(Math.random() * 4) + 2;
      const aScore = Math.floor(Math.random() * Math.min(5, bScore)); //B스코어보다 작은값
      result = `${userId}팀 승리: ${userId} :${bScore} - ${aScore} : ${currentUserId}`;

      //승리팀
      await prisma.account.update({
        where: { userId },
        data: {
          winCount: { increment: 1 },
        },
      });

      //패배팀
      await prisma.account.update({
        where: { userId: currentUserId },
        data: {
          loseCount: { increment: 1 },
        },
      });
    }
    //게임 결과를 응답으로 반환
    return res.status(200).json({ message: result });
  } catch (err) {
    console.log(err);
    return res.status(500).json({ message: "서버 에러가 발생했습니다." });
  }

'부트캠프' 카테고리의 다른 글

Nalgangdoo_Project 4일차  (0) 2024.09.23
Nalgangdoo_Project 3일차  (0) 2024.09.20
Nalgangdoo_project 1일차  (1) 2024.09.13
Item Simulator 과제 정리  (0) 2024.09.12
EC2접속 , 로컬과 AWS EC2 간 파일 올리기, 내려받기  (1) 2024.09.12