항해 플러스 코육대 참여 회고
목차
- 기능 구현 및 설명
- 참여 소감
- 링크 페이지
기능 구현 및 설명
이번 코육대를 참여하며, 기존에 한번도 해보지 않은 분야인 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회 코육대
미션
- 가족들이 함께 볼 수 있도록 프론트도 구현해서 배포하세요.
- 문제를 선택할 수 있도록 영어 단어를 랜덤으로 3개 띄워주세요.
- 선택한 문제의 단어를 글자 단위로 숨깁니다. (e.g., "apple" -> "_ _ _ _ _")
- 화면에 26개 알파벳을 띄워주세요.
- 선택한 알파벳과 정답을 비교합니다.
- 일치하는 알파벳이 있을 경우 기존 UI에서 사라지고 해당 위치에 표시됩니다.
- 틀릴 경우 기존 위치에서 알파벳이 빨간색으로 바뀌고, 오류 횟수를 증가시킵니다.
- 오류 날 때마다 ‘교수대-밧줄-머리-팔-손-몸통-다리-발’ 순서로 그려서 그림이 완성되면 ‘실패’ 를 띄웁니다. (오류 횟수 8번 이상은 실패)
제약 사항
- 랜덤으로 띄워주기 위해 영어 단어는 30개 이상 등록되어 있어야 합니다.
- 등록된 영어 단어의 글자 수는 최대 10개입니다.
- 사용자가 모든 글자를 맞추거나 오류 횟수가 8번 이상일 경우 게임이 종료됩니다.
- 게임이 종료되면 정답을 표시하고 결과 메시지를 출력하세요.
이걸 맞춰나가는건 어렵지 않아서 딱히 할말이 없을 무 이시겠다.
하다가 막히면, 챗지피티 님이 도와주신다. 챗멘.
참여 소감
이렇게 누가 등 떠밀지 않으면, 새로운 기술스택은 쌓이질 않는다.
기회 만들어준 항해 플러스에게 감사를 드리며, 태어나서 처음 작성해본 FE 결과물 특히 React 는 진짜 머리털 나고 처음이니 이쁘게 봐주시길 바란다.
문제시 일단 머리털을 밀어보겠다.
그럼 머리털 나고 처음만큼은 실현(강제) 되지 않겠나?
조금 불평좀 하자면,
참여 링크