MBTI 테스트 개발일지 #1

김솔누리·2021년 11월 12일
4

알고리즘

1. MBTI의 네가지 척도인 E와 I, N과 S, F와 T, P와 J를 결정하는 문제가 3개씩 총 12문제가 나온다.
2. 각 척도마다 과반수로 나온 쪽으로 값이 결정된다. 예를 들어 E와 I를 결정하는 3문제 중에 E에 해당하는 문제 2개를 선택했다면 E000의 MBTI 결과값이 나올 것이다.
3. 각 척도별로 값이 나왔다면 그 값을 나열한 것이 최종 결과 값이다. E, N, F, P가 각각 나왔다면 최종 결과는 ENFP인 것이다.
4. ENFP에 해당하는 결과 페이지를 보여줄 것이다. 우리 팀은 MBTI 용어를 직접적으로 노출하는 대신, "선물 유형"이라는 컨셉을 덧입혔다.

구현 가능 여부에 초점을 맞추었기 때문에 알고리즘을 단순화했다.


페이지 구성

크게 보면 index.htmlresult로 나누어진다고 보면 되겠다.
index.html에는 메인화면과 문제화면이, result에는 말그대로 mbti 결과 페이지가 노출된다. result는 디렉토리이며 해당 디렉토리에는 16개의 mbti 유형 결과 페이지 html 파일이 들어있다.


메인페이지

메인페이지 구성은 심플하다.
* 보기 편하게 css 선택자들이나, 기능을 구현하는데 관련이 없는 html 소스들은 제외했다.

<div class="start">
   <h1>선물별<br>성격유형 테스트</h1>
   <h3>며칠 뒤면 나의 생일이다. 생일파티는 어떻게 준비하면 좋을까?</h3>
   <div>
      <img src="{{ url_for('static', filename='images/gift-main.png') }}">
   </div>
   <button type="button" onclick='start();'>유형 테스트 시작하기</button>
</div>
<div class="question">
   <!--이부분은 이후에 "문제페이지"에서 설명하겠다.-->
</div>

* img의 src 안의 링크가 url_for로 되어 있는 이유는, 파이썬의 인터프리터 "Flask"를 사용했기 때문이다.

위의 html 소스와 연결된 스크립트는 심플하다.

function start() {
   $(".start").hide();
   $(".question").show();
}

앞서 말했듯이 나는 index.html 페이지 안에 메인페이지와 문제페이지를 함께 넣었다. .start는 그 중 메인페이지를 의미하고, .question은 문제페이지다. 즉, 유형 테스트 시작하기 버튼을 클릭하면 메인페이는 숨기고, 문제페이지가 보일 수 있도록 한 것이다. 이를 위해서는 CSS 구문을 하나 넣어주어야 한다.

.question {
   display: none;
}

처음에 index.html이 로딩되면서 메인페이지가 화면에 떴을 때, 문제페이지는 화면에 보이지 않게 해두기 위함이다.


문제페이지

이 부분이 조금 어려웠다. 설명을 들으면서도 이해가 어려웠던 부분도 있었고, 응용해서 변경한 부분도 있기 때문에 정확하지 않을 수 있다.

정보를 담을 태그 생성

<div class="start">
   <!--생략-->
</div>

<div class="question">
   <h2 id="title">1번 문제</h2>
   <!--1번-->
   <input id="type" type="hidden" value="EI">
   <!--2번-->
   <button id="A" type="button">대답 E</button>
   <button id="B" type="button">대답 I</button>
</div>
   <!--3번-->
   <input type="hidden" id="EI" value="0">
   <input type="hidden" id="SN" value="0">
   <input type="hidden" id="TF" value="0">
   <input type="hidden" id="JP" value="0">

3번 먼저 설명을 하자면, 우리는 12문제에 대한 대답을 선택해야하고 그 대답을 어딘가에 저장을 해야한다. 그 대답을 저장하기 위해 여기서는 input태그를 사용했다.

앞서 말했듯 MBTI에는 네가지 척도가 있다. 그 척도별 값을 저장하기 위해 input을 네 가지를 만들고 id에는 각각 "EI", "SN", "TF", "JP"를 부여했다. 대답에 해당하는 <button>을 클릭했을 때, <input>의 value값이 오를 것이다. 이후에 저 value값으로 성향이 어느 쪽인지를 판단하는 식을 짤 것이다.

type에 hidden을 준 것은 화면상에서는 보여지지 않게 하기 위함이다.

2번을 보면 대답에 해당하는 button 태그가 두개가 있는데, 위의 것은 E, S, T, J의 값을 가지게 될 것이고, 아래는 I, N, F, J 값을 가지게 될 것이다. 위 아래 값이 고정되지 않게 하고 싶었으나, 지식 습득으로도 머리가 빠질뻔 했기 때문에 응용까지 하기엔 빠듯했다.

1번의 input은 3번과 동일한 용도의 태그다. <h2 id="title">1번 문제</h2>가 "EI", "SN", "TF", "JP" 중 어떤 타입을 물어보는 문제인지 알아야 하기 때문에 필요하다. 더 자세한 내용은 아래서 설명하겠다.


버튼 클릭시 점수 적용

자 이제부터 본격적이다.

$("#A").click(function () {
    var type = $("#type").val();
    var preValue = $("#" + type).val();
    $("#" + type).val(parseInt(preValue) + 1);
});

A라는 id를 가지고 있는 button에 해당하는 내용이다. click()에서 눈치챘겠지만 클릭했을 때 무언가를 실행시키겠다는 것이다. 그 제이쿼리 안에 함수를 넣었다.

일단 val()에 대해서 설명하자면, 선택한 것의 value를 가져오기 위한 함수다.

type이라는 변수를 선언하고, 그 변수 안에 type이라는 id를 가지고 있는 input의 value를 가져온다. 예시로 <input id="type" type="hidden" value="EI"> 이면 value인 "EI"를 가져오겠다는 것. 그렇다면 type이라는 변수에는 EI라는 값이 들어간다.

그런 다음 preValue라는 변수를 선언하고, 그 안에 #과 변수 type의 값을 더한 것의 value를 가져온다. 앞선 예시를 통해 "EI"라는 값을 받았으면 #EI, 즉 id가 EI인 것의 value를 가져오면 되는 것이다. 위의 html에서 대답을 저장하기 위해 사용했던 <input type="hidden" id="EI" value="0">를 보면 된다.

그 다음은,
1) #과 변수 type의 값을 더한 것의 value를 가져온다.
2) preValue 변수값에 1을 더한다.
위의 예시와 연결해서 설명하면 <input type="hidden" id="EI" value="0">의 value값을 가져와서, 그 value값에 1을 더해주겠다는 것.
parseInt()가 중간에 들어가 있는데, 이건 문자열을 숫자로 변경해주는 함수다. value값을 가져와 1을 더해줬더니 01 이런 식으로 표현되는데, value값이 문자열, 1은 숫자로 인식하기 때문에 벌어진 현상이다.


문제 정보 저장

이제 버튼을 눌렀을 때, 점수가 올라가면서 앞서 만들어둔 input의 value에 값이 저장되고, 다음 문제로 넘어가게 해야하는데... 그럴러면 문제에 대한 정보가 필요하다. 그 정보를 자바스크립트 객체에 저장해보았다. 자바스크립트 객체에 대한 내용은 여기서 확인.
이후에 수업 때 배운내용대로 DB에 저장하고 불러오고 방식을 적용해봐야겠다. 주루룩 나열했더니 영 지저분하고 맘에 들지 않는다.

var num = 1; //현재 몇번 문제에 있는지를 나타내는 변수
var q = {
   1: {"title": "1번 문제", "type": "EI", "A": "대답 E", "B": "대답 I"},
   2: {"title": "2번 문제", "type": "EI", "A": "대답 E", "B": "대답 I"},
   //생략
   12: {"title": "12번 문제", "type": "JP", "A": "대답 J", "B": "대답 P"}
}

3개씩 총 12개의 문제가 자바스크립트 객체에 저장될 것이다. title, type, A, B 어디서 많이 보던 단어들인데.. 맞다. 문제와 문제의 타입을 규정하기 위한 input 그리고 대답을 위한 button 2개의 id 값이다.

var num은 내가 지금 몇번 문제에 있는지 알려주기 위한 변수다. 아래에서 이 변수값에 변화를 주면서, 자바스크립트 객체 안의 정보를 제공하게 될 것이다.


저장된 정보로 다음 문제 출력

function next() { //1번
   $("#title").html(q[num]["title"]); //2번
   $("#type").val(q[num]["type"]); //3번
   $("#A").html(q[num]["A"]); //4번
   $("#B").html(q[num]["B"]); //5번
   num++; //6번
}

1번부터 시작해보자. 자바스크립트에 대해서 정확한 지식을 가지고 있기때문에 내가 아는대로 쓸테다. function next(){} 로 시작된다. next()라는 함수를 내가 커스터마이즈 해놓고, 원할때 가져다 쓰겠다는 뜻.

next() 안의 내용을 확인하기 전에 일단 먼저 알아두고 가야 할 것 두가지가 있다. .html()은 선택한 요소 안의 내용을 가져오거나, 다른 내용으로 바꿀 때 사용한다. val()은 위에서도 언급했듯이, 선택한 것의 value를 가져오기 위한 함수다.

2,4,5번은 구조가 동일하다. 2번을 예시로 설명하자면, 변수 num의 값을 가져와 선택한 요소 h2 id="title""내용을 변경" 해준다는 의미다. 변수 num의 값이 1이면, 문제 정보가 담겨있던 변수 q에 담겨있던 내용 중에 1:{}에 들어있던 title에 해당하는 내용을 id가 title인 h2태그 안에 넣어주는 것이다. 변수 num의 값이 바뀌면 바뀐 것에 해당하는 내용이 들어간다. 아래 이미지를 참고하자.

3번도 비슷하지만, .html()이 아닌 val()를 썼다는 차이가 있다. "내용을 변경"하는 것이 아니라, "속성을 변경" 해주는 것이다. input id="type"의 value=""안의 값을 바꿔주는 것.

6번은 클릭하면 변수 num의 값이 증가한다. 자바스크립트 증감 연산자를 사용한 것.


문제 진행사항 보여주기

일반적인 MBTI 테스트는 총 몇문항이 있고 현재 몇번째 문제를 답하고 있는지 알려주는 경우가 많아서 그 부분을 추가했다. Q1 해서 몇번째 문항인지, 1/12로 표현해서 몇문제 남아있는지 숫자로도 보여줬고, 시각적인 효과를 위해 부트스트랩의 프로그레스 바를 가져와 사용하였다.

<div class="question">
   <div> <!--몇번째 문항인지 숫자로 표현-->
       <h1 class="q-num">Q1</h1>
       <p class="progress-txt">1/12</p>
   </div>
   <div> <!--부트스트랩 프로그레스 바-->
       <div class="progress-bar"></div>
   </div>
   <h2 id="title">1번 문제</h2>
   <input id="type" type="hidden" value="EI">
   <button id="A" type="button">대답 E</button>
   <button id="B" type="button">대답 I</button>
</div>

먼저 h1, p 그리고 부트스트랩 프로그레스바 html 소스를 상단에 추가해주었다. 그리고 4번에서 만든 스크립트에도 몇 줄을 추가해주었는데

function next() {
   //추가된 내용
   $(".q-num").html('Q' + num); //1번
   $(".progress-txt").html(num + ' / 12'); //2번
   $(".progress-bar").attr('style', 'width: calc(100/12*' + num + '%)'); //3번
   //앞에서 작성한 내용
   $("#title").html(q[num]["title"]);
   $("#type").val(q[num]["type"]);
   $("#A").html(q[num]["A"]);
   $("#B").html(q[num]["B"]);
}

1번,2번 스크립트를 먼저 추가해 주었다. 앞에서 작성한 방법과 동일하다. 변수 num의 값을 가져와 선택한 요소 h1 class="q-num"p class="progress-txt"의 내용을 변경해준다는 html(내용) 메서드를 그대로 사용했다.

조금 다른 점은 3번인데, 이건 쉽게 설명하자면 '한문제가 진행될수록 프로그레스 바의 12분의 1만큼 움직이게 하겠다' 라는 내용이다. attr() 은 속성 값을 가져오거나 추가하기 위한 것이고, calc()는 괄호 안의 식을 계산한 결과를 속성값으로 사용하게 해주는 함수다.

calc(100/12*' + num + '%)은 전체 width가 100%인 프로그레스 바의 가로 길이를 12로 나눠서 진행된 문제 개수만큼 곱해주겠다는 뜻이고, .attr('style', 'width: calc()')calc()에서 계산한 결과값을 width의 값으로 사용하여 .progress-bar의 속성에 적용하겠다는 의미.


버튼 클릭시 다음 문제 넘어갈 수 있게

이렇게 열심히 커스터마이징 한 next()를 적용해 줄 차례.

$("#A").click(function () {
    var type = $("#type").val();
    var preValue = $("#" + type).val();
    $("#" + type).val(parseInt(preValue) + 1);
    next();
});
$("#B").click(function () {
    next();
});

대답에 해당하는 button 두 개의 function 안에 넣어주면, 대답을 클릭했을 때 다음 문제가 잘 뜬다.

그런데 어랏? 메인화면에서 유형 테스트 시작하기 버튼을 클릭하면 바로 1번 문제가 뜨지 않고 임의로 써놨던, html 태그 안의 내용들이 뜬다.

<div class="question">
   <h2 id="title">1번 문제</h2>
   <!--1번-->
   <input id="type" type="hidden" value="EI">
   <!--2번-->
   <button id="A" type="button">대답 E</button>
   <button id="B" type="button">대답 I</button>
</div>

이러면 안되는데.. 했는데 생각해보니 유형 테스트 시작하기 버튼을 누르면 곧이어 1번 문제가 떠야하므로, 시작하기 버튼도 어떻게 보면 다음문제로 넘어가는 버튼과 동일한 개념인 것. next()을 적용해야 한다.

function start() {
   $(".start").hide();
   $(".question").show();
   next();
}
profile
웹개발에 도전하는 프리랜서 디자이너

0개의 댓글