Codestates SEB FE 42기

S1 unit7 회고 | 실제 작동하는 계산기 만들기 (상급)

2realzoo 2022. 11. 8. 13:15

과제 이름부터가 nightmare 라니ㅋㅋㅋ
일부러 '못해도 괜찮아' 라고 안심시켜 주시는 것 같았다 ㅎㅎ
그래도 난 꼭 풀고 말거야!
결국 풀고야 말았지만 엄청 지저분? 하게 풀어버렸다. 이번에는 내가 푼 코드와 운도님 설명을 듣고 다시 푼 코드를 비교도 해가면서 적어보겠다!

(1) 3,*,3,Enter,Enter,Enter,Enter를 연속으로 누르면 243이(가) 화면에 표시되어야 합니다.
(2) 3,-,3,Enter,Enter,Enter,Enter를 연속으로 누르면 -9이(가) 화면에 표시되어야 합니다.
(3) 3,+,3,Enter,Enter,Enter,Enter를 연속으로 누르면 15이(가) 화면에 표시되어야 합니다.
(4) 3,/,3,Enter,Enter,Enter,Enter를 연속으로 누르면 0.037037037037037035이(가) 화면에 표시되어야 합니다.

enter를 반복적으로 눌렀을 때 계산이 되어야 위 조건들을 충족할 수 있다.

if (action === 'calculate') {
     if(previousKey === 'calculate') {
       firstNum = display.textContent;
       display.textContent = calculate(firstNum, operatorForAdvanced, previousNum);
       previousKey = 'calculate';
     }
     else {
       previousNum = display.textContent;
       display.textContent = calculate(firstNum, operatorForAdvanced, previousNum);
       previousKey = 'calculate';
     }
   }

따라서 calculate에 분기를 만들어 주었다.
previousKey === 'calculate' 일 때는 이미 계산을 했다는 의미이므로 계산한 값, 즉 화면에 나온 값을 firstNum에 할당했다.
그리고 다시 계산을 하여 결과값에 반복적으로 계산이 되게 만들었다.

(1) 3,Enter,Enter,Enter,*,3,Enter를 연속으로 누르면 9이(가) 화면에 표시되어야 합니다.
(2) 3,Enter,Enter,Enter,-,3,Enter를 연속으로 누르면 0이(가) 화면에 표시되어야 합니다.
(3) 3,Enter,Enter,Enter,+,3,Enter를 연속으로 누르면 6이(가) 화면에 표시되어야 합니다.
(4) 3,Enter,Enter,Enter,/,3,Enter를 연속으로 누르면 1이(가) 화면에 표시되어야 합니다.

하지만 여전히 같은 Enter 문제인 이 녀석들은 풀리지 않았다...
그 이유는 숫자 하나만 누르고 enter를 눌렀기 때문에 else쪽으로 들어가게 되어서 잘못 계산된 것이다.

if (action === 'calculate') {
      if(previousKey === 'calculate') {
        firstNum = display.textContent;
        display.textContent = calculate(firstNum, operatorForAdvanced, previousNum);
        previousKey = 'calculate';
      }
      else if(previousKey !== 'calculate' && firstNum) {
        previousNum = display.textContent;
        display.textContent = calculate(firstNum, operatorForAdvanced, previousNum);
        previousKey = 'calculate';
      }
    }

뒤의 else를 else if로 바꾸고 조건을 달아주었다.
숫자만 입력하고 operator를 입력하지 않은 건 들여보내지 않기 위해 firstNum가 참이 될 때만 들어오도록 했다. (operator 을 지나야 firstNum 생기게 코드를 짜두었다.)

5,1,-,.,1,2,Enter를 연속으로 누르면 50.88이(가) 화면에 표시되어야 합니다.
1,0,0,/,.,5,Enter를 연속으로 누르면 200이(가) 화면에 표시되어야 합니다.
1,0,0,+,.,.,5,Enter를 연속으로 누르면 100.5이(가) 화면에 표시되어야 합니다.
1,0,0,,.,.,5,Enter를 연속으로 누르면 50이(가) 화면에 표시되어야 합니다.
3,.,.,.,.,.,2,+,3,Enter를 연속으로 누르면 6.2이(가) 화면에 표시되어야 합니다.
3,.,.,.,.,.,2,-,2,Enter를 연속으로 누르면 1.2000000000000002이(가) 화면에 표시되어야 합니다.
3,.,2,1,2,4,+,2,.,1,1,2,3,Enter를 연속으로 누르면 5.3247이(가) 화면에 표시되어야 합니다.
6,2,3,.,1,2,9,3,8,/,1,2,4,Enter를 연속으로 누르면 5.02523693548387이(가) 화면에 표시되어야 합니다.
1,2,.,.,.,1,2,3,8,,2,3,Enter를 연속으로 누르면 278.8474이(가) 화면에 표시되어야 합니다.

이 문제는 소수점이 잘 작동하는 지 물어보고 있다.
소수점 버튼을 연속으로 누르는 경우나, 앞에 숫자가 없이 소수점을 누르는 경우가 있다.

if (action === 'decimal') {
      if(previousKey === 'operator' ) {
        display.textContent = '0.';
      }
      else if(previousKey !== 'decimal') {
        display.textContent += buttonContent;
      }
      previousKey = action;
    }

previousKey === 'operator'인 경우에는 아예 두번째 숫자의 첫 시작이라고 보고 '0.' 을 display.textContent에 할당하였다.
마찬가지로 decimal 버튼을 누르면 반드시 previousKey에 action을 할당했다.
그리고 previousKey !== 'decimal' 조건을 추가했다. 앞에 소수점이 오지 않는 것만 display.textContent에 buttonContent를 더해서 할당해주었다.

1,0,0,.,.,1,2,5,2,+,1,2,+,1,5,-,-,2,3,-,1,4,4,2,/,2,3,/,/,1,2,*,2,3,Enter를 연속으로 누르면 -111.48956666666668이(가) 화면에 표시되어야 합니다.

대망의 마지막 문제이다.
이 문제가 너무 어려워서 하루종일 잡다가 결국 푼...
하... 다시 풀어도 너무 어렵다...
차근차근 생각해야하는데 자꾸 마음이 다급해지는 게 문제인 것 같다.

if (action === 'operator') {
      if (previousKey !== 'operator' && !firstNum) { // 맨 처음 누르는 것
        firstNum = display.textContent;
        operatorForAdvanced = buttonContent;
      }
      else if (previousKey === 'operator'){ // 앞에 있는데 계속 누르는 것
        operatorForAdvanced = buttonContent;
      }
      else if (operatorForAdvanced && firstNum && previousKey === 'number') {
      //firstNum, operatorForAdvanced 있고, 이전에 number 누른 것
        previousNum = display.textContent;
        display.textContent = calculate(firstNum, operatorForAdvanced, previousNum);
        operatorForAdvanced = buttonContent;
        firstNum = display.textContent;
      }
      previousKey = action;
    }

우선 operator의 경우를 세가지로 나누었다.
처음 누르는 것은 firstNum가 없을테니까 !firstNum로 조건을 붙이고, 계속 누르는 것과 겹치지 않도록 previousKey !== 'operator'를 and로 붙여주었다.

두번째는 앞에 연산자가 있는데 계속 누르는 것이다.
그러면 마지막 연산자만 저장되야 하므로 누를 때마다 저장만 한다.

마지막은 firstNum, operatorForAdvanced 있고, number 누른 것이다.
이전에 number버튼을 눌렀으니 previousKey는 'number'가 된다.
따라서 조건을 previousKey === 'number'로 붙여주었다.

그리고 계산을 해야하는데 이미 firstNum은 앞 연산자에 의해 할당되어 있다. 그래서 priviousNum를 할당하고 계산한 뒤에 display.textContent 에 할당했다.
또 계산 값이 이후의 firstNum이 되도록 할당해주고 operatorForAdvanced에도 buttonContent를 재할당 해주었다.


내가 직접 풀었던 풀이는 비슷하지만 엄청 어지럽게 되어있다.

if (target.matches('button')) {
    if (action === 'number') {
      if (display.textContent === '0' && previousKey !== 'operator'&& previousKey !=='operatorNumber') { // 첫번째 숫자의 첫번째 글자
        display.textContent = buttonContent;
        firstNum = display.textContent;
        }
      else if (display.textContent !== '0' && previousKey !== 'operator'&& previousKey !=='operatorNumber') { //첫번째 숫자의 두번째 글자 
        display.textContent = display.textContent + buttonContent;
        firstNum = display.textContent;

        }
      else if (display.textContent !== '0' && previousKey === 'operator') { 
        if (display.textContent === firstNum) { //두번째 숫자의 첫글자 작성
          display.textContent = buttonContent;
          previousNum = display.textContent;
          previousKey = 'operatorNumber';
        }   
        else if (display.textContent !== firstNum) { // operator 후 바로 소숫점 사용할 때
          display.textContent = display.textContent + buttonContent;
          previousNum = display.textContent;
        }
      }
      else if (previousKey === 'operatorNumber') { // operator랑 두번째 숫자 지나가서 previousnkey === 'operatorNumber'된 아이들
        display.textContent = display.textContent + buttonContent; // 두번째 숫자 두번째 글자추가하는 경우
        previousNum = display.textContent;
        
      }
      
  }
    if (action === 'operator') {
      // 오퍼레이터 처음 사용 : previousNum, firstNum , previousKey === ''존재
      // 오퍼레이터 연속으로 여러 번 사용할 경우 : 존재 유무 관계 없이 마지막 하나만 적용 : 12+++++++++++,12+1-------------
      // 오퍼레이터 1번 사용 후 숫자 넣고 한 번 더 사용할 경우 : oper : 1,2,+,1-5
      if(previousKey !== 'operator' && previousKey !=='operatorNumber') { // 아예 처음 숫자 + 오퍼레이터도 한번도 안옴
        operatorForAdvanced = buttonContent;
        previousKey = 'operator';
      }
      else if(previousKey === 'operatorNumber') { // 첫 숫자, 오퍼레이터, 두번째숫자 
        display.textContent = calculate(firstNum, operatorForAdvanced, previousNum);
        operatorForAdvanced = buttonContent;
        firstNum = display.textContent
        previousKey = 'operator'
      }
      else if(previousKey === 'operator') {
        operatorForAdvanced = buttonContent;
      }
      }
    }
    if (action === 'decimal') {
      // 두번째 숫자 중간에 . 누름
      if(display.textContent[(display.textContent).length-1] === '.'){  // .을 많이 누를 때
      }
      else if(display.textContent === '0') { // 첫번째 숫자 처음
        display.textContent = '0' + buttonContent;
      }
      else if(previousKey !== 'operator' && display.textContent === firstNum) { // 첫번째 숫자 중간
        display.textContent = display.textContent + buttonContent;
      }
      else if(previousKey === 'operator' && display.textContent === firstNum) { // 두번째 숫자 처음
        display.textContent = '0' + buttonContent;
     }      
      else if (previousKey === 'operatorNumber' && display.textContent === previousNum) { //두번째 숫자 중간
          display.textContent = display.textContent + buttonContent;
      } 
    }

    if (action === 'clear') {
      operatorForAdvanced = '';
      previousKey = '';
      firstNum = '0';
      previousNum = '';
      display.textContent = '0';
    }
    if (action === 'calculate') {
      if(display.textContent === previousNum) { //firstnum, operator, previousNum 있고 enter 여러 번 누르지 않은 경우
        display.textContent = calculate(firstNum, operatorForAdvanced, previousNum);
      }
      else if (display.textContent === firstNum && previousKey === 'operator') {
        display.textContent = calculate(firstNum, operatorForAdvanced, firstNum); //firstnum과 operator 만 제공했을 때 previousnum = firstnum;
      }

      else {
        firstNum = display.textContent // 엔터를 여러 번 누를 경우 firstnum을 자동으로 결과값으로 바꿈.
        display.textContent = calculate(firstNum, operatorForAdvanced, previousNum);
      }
      previousKey ='';
    }

우선 첫번째로 다른 점은 clear를 undefined로 두지 않았다는 점이다.
뭔가 그러면 오류가 날 것 같다는 생각에 사용하지 않았는데...
그래서 더욱 복잡한 코드가 되었다.

두번째로 다른 점은 소수점 버튼을 더욱 복잡하게 풀었다는 점이다.
나는 firstNum 일 경우, previousNum일 경우 별로 맨 처음에 오는 소수점과 중간에 오는 소수점으로 나누어 풀었다.
previousKey를 어떻게 사용할 지 고민하다가 버튼 별로 새로운 문자열을 할당하는 게 아닌, 특정 버튼만 할당하는 것으로 했기 때문이다.
그래서 나는 앞에 소수점이 왔는지 아닌지를 몰랐고,
display.textContent[(display.textContent).length-1] === '.'
이런 기묘한 코드를 쓰게 되었다.
나머지도 previousKey가 operator 일 때와 아닐 때로 나누려다 보니까 복잡해진 것 같다.

세번째로 다른 점은 내가 두번째로 오는 숫자에만 previousKey = 'operatorNumber'을 줬다는 점이다. 두번째 숫자를 작성하고 나면 previousKey = 'operatorNumber' 가 실행되게 만들어 두어서 operator 버튼 코드를 작성할 때도 이런 점을 고려해야 했다.

문제점은 previousKey를 버튼마다 다르게 주지 않았다는 점이다.
컴퓨터에게 내 말을 알아듣게 하려면 각각의 행동을 할 때마다 이게 어떤 행동이었는지 꼬리표를 달아주는 게 편리하다는 것을 배웠다.
또 undefined를 잘 사용할 수 있게 되었다.

이번 문제는 정말 어려웠지만 나름 풀면서 재미도 있었고, 페어분에게 어떻게 푸는 건지 내 방식대로 설명하는 것도 좋았다. 내가 아는 게 다 아는 게 아니라는 생각이 들었다.
뭔가 알 것 같은데 설명을 잘 못하는 게 너무 답답했다.
그런 커뮤니케이션 스킬을 좀 키워야 할 것 같다.

전부 통과된 나이트메어 사진으로 끝!❤😆