쁘띠 TFT 프로젝트

유효성 평가 미들웨어 조정

  • 기존에 agent를 찾는 변수로 agent_name(str)과 agent_key(int)를 사용했는데, 이를 통합하여 key만 사용하게 설계함
  1. 기존 팀편성 / 대표 챔피언 설정 api 수정

    • 찾는 변수를 name에서 key로 변경 및 에러 메시지를 수정하였다.
     // 팀편성 API 내부
         myAgent[i] = await prisma.myAgents.findFirst({ where: { agentKey: +formation[i], userKey: +key } })
         //보유 챔피언 확인
         if (!myAgent[i]) return res
             .status(400)
             .json({errorMessage: `${agent[i].name}/${formation[i]}(은)는 현재 보유한 챔피언이 아닙니다.`})
         if (agent[i].position === "tanker") {
             tank = true;
         }
    
     // 챔피언 설정 API 내부
         const myAgent = await prisma.myAgents.findFirst({ where: { agentKey: +agent.agentKey, userKey: +key } })
         // 보유 챔피언 확인
         if (!myAgent) return res
             .status(400)
             .json({ errorMessage: `${agent.name}/${agent.agentKey}(은)는 현재 보유한 챔피언이 아닙니다.`})
    
  2. 유효성 평가 미들웨어 수정

    • 기존에 미들웨어 함수를 2개로 구분지어 export 하였으나, 이를 하나로 합칠 예정이기에 export default로 수정 해주었다.

    • 추가로 배열(다중입력)의 경우도 각각 유효성 평가를 할 수 있도록 재설계 해주었다.

     // 배열 값인지 판정
     if (Array.isArray(agentValues?.formation) || Array.isArray(agentValues) ) {
         const agents = [];
         // 팀편성의 경우
         if (agentValues?.formation) {
             for (let agentKey of agentValues.formation) {
                 // 입력값 유효성 평가
                 if (!Number.isInteger(agentKey)) return res
                     .status(400)
                     .json({ errorMessage: "선택할 챔피언의 <agent_key>를 숫자로 입력해주세요" })
    
                 // 챔피언 존재 여부 확인
                 const agent = await prisma.agents.findFirst({ where: { agentKey } })
                 if (!agent) return res
                     .status(404)
                     .json({ errorMessage: `<agent_key> ${agentKey}에 해당하는 챔피언은 존재하지 않습니다` })
                 // 챔피언 정보 할당
                 agents.push(agent)
             }
         // 일반 배열
         } else {
             for (let { agent } of agentValues) {
                 // 입력값 유효성 평가
                 if (!Number.isInteger(+agent)) return res
                     .status(400)
                     .json({ errorMessage: "선택할 챔피언의 <agent_key>를 숫자로 입력해주세요" })
    
                 // 챔피언 존재 여부 확인
                 const agentVerify = await prisma.agents.findFirst({ where: { agentKey: +agent } })
                 if (!agentVerify) return res
                     .status(404)
                     .json({ errorMessage: `<agent_key> ${agentKey}에 해당하는 챔피언은 존재하지 않습니다` })
                 // 챔피언 정보 할당
                 agents.push(agentVerify)
             }
         }
     }
     // 챔피언 정보 반환
     req.agent = agents
    

챔피언 매각 API 구현

  • 챔피언 매각을 다중으로도 가능하게 설계를 하기로 했다!
// 출력용 값 저장
let resJson = [];
// 다중 입력 확인
if (Array.isArray(agent)) {
    for (let i = 0;i < agent.length;i++) {
      const count = req.body[i].count
      const myAgent = await prisma.myAgents.findFirst({ where: { userKey: +key, agentKey: agent[i].agentKey } })
      const amount = agent[i].grade === "s" ? 300000 * +count : 100000 * +count 

      console.log(agent)

      if (!myAgent || myAgent.count < count) {0
        resJson = [...resJson, { errorMessage: `판매할 챔피언(${agent[i].name})(이)가 부족합니다` }]
      } else {
        // 저번 피드백으로 업데이트,생성 에 관계성이 있을 경우 한번의 쿼리로 해결하게 설계했다.
        const update = await prisma.users.update({
          where: { userKey: +key },
          data: {
            // 유저의 지갑 cash 업데이트
            asset: {
              update: {
                data: {
                  cash: { increment: +amount }
                }
              }
            },
            // 유저가 소유한 챔피언(인벤토리 개념) count 업데이트
            myAgent: {
              update: {
                where: { myAgentKey: +myAgent.myAgentKey },
                data: {
                  count: { decrement: +count }
                }
              }
            }
          }
        })

      resJson = [...resJson, { 
        message: `성공적으로 챔피언 ${agent[i].name}(을)를 ${count}만큼 판매하였습니다.`,
        amount: `+${amount}`
      }]
    }
  }
}
  • 추가로 count가 0이하인 myAgent들을 삭제하는 로직을 추가했다
// 남은 숫자가 0 이하인 챔피언 삭제
const deleteMyAgent = await prisma.myAgents.deleteMany({where: {count: {lte: 0}, userKey: +key}})

프로젝트 병합 및 기능별 묶기

  • 각자 작업을 마친 파일들을 한 branch에(dev) 병합한 후 기능에 따라 묶어주는 작업을 하였다!

before

after

  • 이후 미들웨어들을 사용하는 API들에 중복된 로직을 간략화(리팩토링)해주며 미들웨어를 적용 시켜주었다.

개선점 분석

  • 발표 자료도 준비하기 시작해야겠다

지식창고

알고리즘 코드 카타

대충 만든 자판

  • 문제

휴대폰의 자판은 컴퓨터 키보드 자판과는 다르게 하나의 키에 여러 개의 문자가 할당될 수 있습니다. 키 하나에 여러 문자가 할당된 경우, 동일한 키를 연속해서 빠르게 누르면 할당된 순서대로 문자가 바뀝니다.

같은 규칙을 적용해 아무렇게나 만든 휴대폰 자판이 있습니다. 이 휴대폰 자판은 키의 개수가 1개부터 최대 100개까지 있을 수 있으며, 특정 키를 눌렀을 때 입력되는 문자들도 무작위로 배열되어 있습니다. 또, 같은 문자가 자판 전체에 여러 번 할당된 경우도 있고, 키 하나에 같은 문자가 여러 번 할당된 경우도 있습니다. 심지어 아예 할당되지 않은 경우도 있습니다. 따라서 몇몇 문자열은 작성할 수 없을 수도 있습니다.

이 휴대폰 자판을 이용해 특정 문자열을 작성할 때, 키를 최소 몇 번 눌러야 그 문자열을 작성할 수 있는지 알아보고자 합니다.

1번 키부터 차례대로 할당된 문자들이 순서대로 담긴 문자열배열 keymap과 입력하려는 문자열들이 담긴 문자열 배열 targets가 주어질 때, 각 문자열을 작성하기 위해 키를 최소 몇 번씩 눌러야 하는지 순서대로 배열에 담아 return 하는 solution 함수를 완성해 주세요.

  • 조건

    • 1 ≤ keymap의 길이 ≤ 100

    • 1 ≤ keymap의 원소의 길이 ≤ 100

    • keymap[i]는 i + 1번 키를 눌렀을 때 순서대로 바뀌는 문자를 의미합니다.
      예를 들어 keymap[0] = “ABACD” 인 경우 1번 키를 한 번 누르면 A,
      두 번 누르면 B, 세 번 누르면 A 가 됩니다.

    • keymap의 원소의 길이는 서로 다를 수 있습니다.

    • keymap의 원소는 알파벳 대문자로만 이루어져 있습니다.

    • 1 ≤ targets의 길이 ≤ 100

    • 1 ≤ targets의 원소의 길이 ≤ 100

    • targets의 원소는 알파벳 대문자로만 이루어져 있습니다.

function solution(keymap, targets) {
    var answer = [];
    
    for (let str of targets) {
        let total_count = 0;
        // 문자당 누름 횟수 찾기
        for (let i = 0;i < str.length;i++) {
            let count = 0;
            const x = str[i]
            // 문자 최소로 찾기
            for (let j = 0;j < keymap.length;j++) {
                if (!keymap[j].includes(x)) continue
                if (count <= 0) count = keymap[j].indexOf(x)+1
                else count = Math.min(count,keymap[j].indexOf(x)+1)
            }
            // 없을 경우 나가기
            if (count === 0) {
                answer.push(-1)
                total_count = ""
                break
            }
            // 한 글자에 필요한 누름 횟수를 총 누름 횟수에 더하기
            total_count += count 
        }
        if (total_count > 0 ) {
            answer.push(total_count)
        }
    }
    
    return answer;
}
  • 다른 코드 분석
function solution(keymap, targets) {
    const answer = [];
    const map = {}
    
    for (const items of keymap) {
        /*문자 당 최소 누름 횟수를 map객체에 A(문자) : 1(횟수) 형태로 저장 
        [index+1]은 누름 횟수를 뜻함 (A 가 keymap의 0번 일 때 1번 누른 횟수이기에) */
        items.split('').map((item, index) => map[item] = (map[item] < index+1 ? map[item] : index+1))
    }
    // 누름 횟수 확인
    for (const items of targets) {
        /* reduce 를 이용해 map{}에서 글자를 찾아 최소 누름 횟수를 더한 후 넣음, 
        또한 못찾을 경우 대신 -1을 넣음 (cur에 undefine이 들어가 최종값이 NaN이 됨)*/
        answer.push(items.split('').reduce((cur, item) => cur += map[item], 0) || -1)
    }
    return answer;
}

Reference

programmers
스파르타코딩클럽