All category에 해당하는 글 51

항해 플러스 코육대 참여 회고

Study-programing|2023. 10. 3. 22:27

목차

  • 기능 구현 및 설명
  • 참여 소감
  • 링크 페이지

기능 구현 및 설명

이번 코육대를 참여하며, 기존에 한번도 해보지 않은 분야인 FE 로 도전해보기로 하였으며, 특히 React 학습에 중점을 두었다.
결코(ㅋㅋㅋ) 좋은 코드라 할 수 없는 부분도 많지만, 경력과 무관하게, 일주일만의 React 도전기 라는걸 감안하며 봐주면 감사드리겠다.

가장 중요시한 부분

개인적으로 FE 개발 결과물을 평가해야 할 때 가장 중요시 하는 부분은, 웹은 이용자가 어떤 사이즈로 볼지 알 수 없다는 부분이었다.
그러다보니, 반응형 웹 개발에 가장 많은 시간을 쏟게 되었다.

반응형 구현

아래는 일부 예시이다.

#HiddenWord{
    position: relative;
    width: 100%;
    text-align: center;
    font-size: 4vh;
    font-weight: bold;
    margin-top: 0.5em;
    margin-bottom: 0.5em;
}

예시와 같이, font-size 등도 모두 vh 또는 vw 를 사용하여 화면 크기에 따라 다른 크기로 변화하도록 설계하였다.
다양한 사이즈에서 동적으로 허용되는걸 확인하였다.

State 구현

  const [selectedWord, setSelectedWord] = useState("");
  const [hiddenWord, setHiddenWord] = useState([]);
  const [disabledAlphabets, setDisabledAlphabets] = useState([]);
  const [errorCount, setErrorCount] = useState(0);
  //gameStatus 0:start, 1:win, 2:lose
  const [gameStatus, setGameStatus] = useState(0);

위 예시에서와 같이, 각종 값들은 React의 State 를 사용하여 관리하였다. State 라는 개념이 처음엔 다소 어색했는데, 사용하다보니 익숙해지기는 개뿔 여전히 객체지향이 그립다.

Hanging Man

생각보다 공을 들인 부분이 HangingMan 의 구현이다.
이거 하드코딩아닌 하드코딩아닌 하드코딩으로 해놨다.

const renderHangingMan = () => {
    return (
      <svg height="100%" width="100%" viewBox="0 0 250 200">
        {/* Base */}
      <path d="M 50 200 Q 75 190 150 200" style={{stroke:"#000", strokeWidth:4, fill:"none"}} />
      {/* Vertical Pole */}
      {errorCount > 0 && <path d="M 100 200 Q 105 125 100 50" style={{stroke:"#000", strokeWidth:3, fill:"none"}} />}
      {/* Horizontal Pole */}
      {errorCount > 0 && <path d="M 100 50 Q 125 45 150 50" style={{stroke:"#000", strokeWidth:3, fill:"none"}} />}
      {/* Rope */}
      {errorCount > 1 && <path d="M 140 50 Q 142 60 140 70" style={{stroke:"#000", strokeWidth:3, fill:"none"}} />}
      {/* Head */}
      {errorCount > 2 && <circle cx="140" cy="80" r="10" style={{stroke:"#000", strokeWidth:2, fill:"#fff"}} />}
      {/* Arms */}
      {errorCount > 3 && <path d="M 140 90 Q 145 100 160 110" style={{stroke:"#000", strokeWidth:2, fill:"none"}} />}
      {errorCount > 3 && <path d="M 140 90 Q 135 100 120 110" style={{stroke:"#000", strokeWidth:2, fill:"none"}} />}
      {/* Hands */}
      {errorCount > 4 && <circle cx="162" cy="112" r="2" style={{stroke:"#000", strokeWidth:3, fill:"#fff"}} />}
      {errorCount > 4 && <circle cx="118" cy="112" r="2" style={{stroke:"#000", strokeWidth:3, fill:"#fff"}} />}   
      {/* Body */}
      {errorCount > 5 && <path d="M 140 90 Q 140 100 140 120" style={{stroke:"#000", strokeWidth:2, fill:"none"}} />}
      {/* Legs */}
      {errorCount > 6 && <path d="M 140 120 Q 145 130 160 140" style={{stroke:"#000", strokeWidth:2, fill:"none"}} />}
      {errorCount > 6 && <path d="M 140 120 Q 135 130 120 140" style={{stroke:"#000", strokeWidth:2, fill:"none"}} />}
      {/* Feet */}
      {errorCount > 7 && <ellipse cx="162" cy="142" rx="4" ry="2" style={{stroke:"#000", strokeWidth:3, fill:"#fff"}} />}
      {errorCount > 7 && <ellipse cx="118" cy="142" rx="4" ry="2" style={{stroke:"#000", strokeWidth:3, fill:"#fff"}} />}

        {/* Eyes */}
        {errorCount > 2 && errorCount <= 7 && (
          <>
            <circle cx="137" cy="78" r="1" style={{fill:"#000"}} />
            <circle cx="143" cy="78" r="1" style={{fill:"#000"}} />
          </>
        )}
        {/* Angry Eyebrows when 5 errors */}
        {errorCount > 4 && errorCount <= 7 && (
          <>
            <line x1="136" y1="76" x2="138" y2="74" style={{stroke:"#000", strokeWidth:1}} />
            <line x1="144" y1="76" x2="142" y2="74" style={{stroke:"#000", strokeWidth:1}} />
          </>
        )}
        {/* Mouth */}
        {errorCount > 2 && errorCount <= 7 && (
          <line x1="137" y1="83" x2="143" y2="83" style={{stroke:"#000", strokeWidth:1}} />
        )}
        {errorCount > 7 && (
          <>
            {/* Eyes turned into X */}
            <line x1="135" y1="76" x2="139" y2="80" style={{stroke:"#000", strokeWidth:1}} />
            <line x1="135" y1="80" x2="139" y2="76" style={{stroke:"#000", strokeWidth:1}} />
            <line x1="141" y1="76" x2="145" y2="80" style={{stroke:"#000", strokeWidth:1}} />
            <line x1="141" y1="80" x2="145" y2="76" style={{stroke:"#000", strokeWidth:1}} />
          </>
        )}
      </svg>
    );
  };

이거 맞냐구요?
아뇨 오답 같은데요... 근데 돌잖아요?

SVG로 그려낸 행맨인데, 여기에 React 잖아? 조건문을 박아버렸다.
CSS로 행맨을 State 에 따라 구워낸다. 이거 맞아? 아뇨 뚱인데요.

Game Status

처음엔 게임 상태를 찾아내는걸 매번 조건문으로 했었다. 그러다가 발견한 useEffect 님이 나를 구원하셨으니...

  //Check game status
  useEffect(() => {
    if (errorCount >= 8) {
      setGameStatus(2);
    } else if (!hiddenWord.includes("_")) {
      setGameStatus(1);
    } else {
      setGameStatus(0);
    }
  }, [errorCount, hiddenWord]);

이제 errorCount 와 hiddenWord 에 따라 알아서! GameStatus 가 변경된다.
이게 기적이지...

기타 제약조건들

행맨의 제약조건들은 아래와 같다.
출처 : 항해 플러스 : 제 1회 코육대

미션

  1. 가족들이 함께 볼 수 있도록 프론트도 구현해서 배포하세요.
  2. 문제를 선택할 수 있도록 영어 단어를 랜덤으로 3개 띄워주세요.
  3. 선택한 문제의 단어를 글자 단위로 숨깁니다. (e.g., "apple" -> "_ _ _ _ _")
  4. 화면에 26개 알파벳을 띄워주세요.
  5. 선택한 알파벳과 정답을 비교합니다.
  6. 일치하는 알파벳이 있을 경우 기존 UI에서 사라지고 해당 위치에 표시됩니다.
  7. 틀릴 경우 기존 위치에서 알파벳이 빨간색으로 바뀌고, 오류 횟수를 증가시킵니다.
  8. 오류 날 때마다 ‘교수대-밧줄-머리-팔-손-몸통-다리-발’ 순서로 그려서 그림이 완성되면 ‘실패’ 를 띄웁니다. (오류 횟수 8번 이상은 실패)

제약 사항

  • 랜덤으로 띄워주기 위해 영어 단어는 30개 이상 등록되어 있어야 합니다.
  • 등록된 영어 단어의 글자 수는 최대 10개입니다.
  • 사용자가 모든 글자를 맞추거나 오류 횟수가 8번 이상일 경우 게임이 종료됩니다.
  • 게임이 종료되면 정답을 표시하고 결과 메시지를 출력하세요.

이걸 맞춰나가는건 어렵지 않아서 딱히 할말이 없을 무 이시겠다.
하다가 막히면, 챗지피티 님이 도와주신다. 챗멘.

참여 소감

이렇게 누가 등 떠밀지 않으면, 새로운 기술스택은 쌓이질 않는다.
기회 만들어준 항해 플러스에게 감사를 드리며, 태어나서 처음 작성해본 FE 결과물 특히 React 는 진짜 머리털 나고 처음이니 이쁘게 봐주시길 바란다.

 

문제시 일단 머리털을 밀어보겠다.
그럼 머리털 나고 처음만큼은 실현(강제) 되지 않겠나?

 

조금 불평좀 하자면,

참여 링크 

항해 플러스 : 제 1회 코육대

댓글()