현재 개발중인 '바로보카'는 영어 단어 퀴즈앱입니다.
단어장에서 랜덤으로 단어를 뽑아서 퀴즈를 만들어줘요.
이번 포스팅에서는 랜덤 퀴즈 기능에 대한 핵심 알고리즘(?)을 풀어보려고 합니다. 너무 간단해서 알고리즘이라고 하기도 애매합니다.
우선 기본 틀은 이렇게 생겼습니다. 문제와 선택지 4개가 주어집니다.
문제를 만드는 로직은 아래와 같습니다.
1. 데이터셋에서 4개의 단어를 랜덤으로 뽑습니다.
2. 4개의 데이터 중에 1개를 출제 문제로 정합니다. ( 문제에 대한 대답이 들어가는 버튼 위치 또한 랜덤으로 계속 바뀝니다. )
3. 클릭한 대답버튼이 문제에 해당하는 단어면 정답처리, 다른 단어면 오답처리합니다.
그럼 1번부터 차근차근 보겠습니다.
1. 데이터셋에서 4개의 데이터를 랜덤으로 뽑는다.
우선 대답 버튼에 들어갈 answers라는 배열과 출제 문제에 해당하는 questionData를 선언해줍니다. answers 배열에는 초기값을 0으로 줘도 되고, 안줘도 되는데 저는 허전해서 그냥 0으로 줬습니다.
const [answers, setAnswers] = useState([0, 0, 0, 0]);
const [questionData, setQuestionData] = useState({
'id': '',
'english': '',
'korean': ''
})
이제 데이터셋 배열에서 추출할 4개의 랜덤 숫자를 만듭니다.
let array = [];
for (let i = 0; i < 4; i++) {
let random = Math.floor(Math.random() * arrayLength);
if (array.includes(random)) {
i--;
} else {
array.push(random)
}
}
1) 파라미터로 들어가는 arrayLength는 데이터셋에 들어있는 단어의 총 개수입니다. 만약, 나의 데이터셋이 토익단어장이고 여기에는 1000개의 단어가 들어있다면 arrayLength에는 1000이 들어갑니다.
2) array = [] 는 뽑은 4개의 랜덤숫자가 들어갈 배열입니다.
3) for문은 arrayLength 중에 랜덤으로 숫자 4개를 뽑는 코드입니다.
만약, arrayLength가 1000이라면 0~999중에서 4개를 뽑습니다.
Math.floor는 숫자를 내림해주는 함수입니다. (ex. 44.3 -> 44)
그리고 같은 숫자를 2번 뽑으면(즉 같은 단어가 2개 들어가면) 안되기 때문에 중복 숫자가 뽑히면 i--를 실행해서 반복문이 한 번 더 돌도록 합니다.
이렇게 4개의 숫자가 정해지면 다음 단계로 넘어갑니다.
2. 4개의 데이터 중에 1개를 출제 문제로 정합니다.
let random = Math.floor(Math.random() * 4);
let questionData = vocaData.data[array[random]]
setQuestionData({
'id': questionData.id,
'english': questionData.english,
'korean': questionData.korean
})
뽑은 4개의 숫자중에 출제문제에 해당하는 숫자를 정합니다.
우선, vocaData.data 는 데이터셋입니다.(단어장) 데이터셋은 id, english, korean의 속성을 가진 객체 배열로 구성되어 있습니다.
출제 문제에 대한 정답 위치도 계속해서 바뀌어야합니다. (가령 두번째 버튼에만 계속 정답이 들어가면 재미가 없죠)
아까 array에 저장한 랜덤한 숫자 4개 중에서도, 출제 문제를 랜덤하게 정하는 코드입니다. array의 4개 숫자중에 랜덤으로 다시 한 번 뽑는거죠!
예를 들어, arrayLength 가 1000이고, array = [ 12, 455, 33, 495 ] 가 들어갔습니다.
그럼 array에서 랜덤으로 하나를 뽑아서 출제 문제로 정합니다. (ex. array[3]인 495)
그러면 vocaData.data(단어장)에 있는 495번째 단어가 questionData에 저장됩니다.
대답 선택지를 세팅합니다.
아까 선언한 answers를 추출한 4개의 단어로 초기화합니다. 대답 선택지에 영어는 필요 없으니 따로 저장하지 않았습니다.
아래처럼 하지 않고 answers 배열에 vocaData.data[num] 객체 자체를 저장해도 됩니다.
setAnswers([
{
'id': vocaData.data[array[0]].id,
'korean': vocaData.data[array[0]].korean,
},
{
'id': vocaData.data[array[1]].id,
'korean': vocaData.data[array[1]].korean,
},
{
'id': vocaData.data[array[2]].id,
'korean': vocaData.data[array[2]].korean,
},
{
'id': vocaData.data[array[3]].id,
'korean': vocaData.data[array[3]].korean,
},
])
그럼 이 중에 하나는 정답 데이터와 id가 일치하게 됩니다. 같은 뜻을 가진 영단어가 있을 수도 있어서 단어마다 고유 id를 부여해서 id를 기준으로 객체를 구분합니다.
3. 정답 / 오답을 처리합니다.
아래 코드는 대답을 선택했을 때 정답/오답을 구분하는 코드입니다.
파라미터로는 클릭한 선택지에 아이템 객체를 받아옵니다.
const clickAnswer = (clickedAnswer) => {
if (clickedAnswer.id === questionData.id) {
//정답
} else {
//오답
}
}
즉, answers 배열 중 하나의 요소(객체)를 받아옵니다. 위 코드에서 clickedAnswer에 해당하는 객체는 아래처럼 생겼을 것입니다.
{
'id': '',
'korean': '',
}
그리고 클릭한 객체의 id와 출제문제의 id를 비교하여 정답 / 오답을 구분합니다.
끝입니다!
실제 코드에서는 다양한 상태값을 구분하는 코드들이 더 포함되어있습니다.
그런 것들은 빼고, 랜덤 퀴즈를 만드는 부분만 따로 정리해봤습니다.
굳이 영단어가 아니더라도 다른 데이터셋에서 값을 랜덤으로 뽑아서 사지선다 혹은 오지선다 등 객관식 일치/불일치 문제로 얼마든지 활용할 수 있습니다.
<< 4개의 랜덤값을 뽑는 전체 코드 >>
const settingQuizData = (arrayLength) => {
let array = [];
for (let i = 0; i < 4; i++) {
let random = Math.floor(Math.random() * arrayLength);
if (array.includes(random)) {
i--;
} else {
array.push(random)
}
}
let random = Math.floor(Math.random() * 4);
let questionData = vocaData.data[array[random]]
setQuestionData({
'id': questionData.id,
'english': questionData.english,
'korean': questionData.korean
})
setAnswers([
{
'id': vocaData.data[array[0]].id,
'korean': vocaData.data[array[0]].korean,
},
{
'id': vocaData.data[array[1]].id,
'korean': vocaData.data[array[1]].korean,
},
{
'id': vocaData.data[array[2]].id,
'korean': vocaData.data[array[2]].korean,
},
{
'id': vocaData.data[array[3]].id,
'korean': vocaData.data[array[3]].korean,
},
])
}
'React Native > 캐시보카' 카테고리의 다른 글
React Native로 앱테크 서비스 만들기: 리워드 시스템 편 (2) | 2024.06.11 |
---|---|
기획부터 배포까지 일주일만에 영단어 퀴즈 앱 만들기 (앱스토어 첫 출시 심사 4시간만에 승인!) (4) | 2022.01.05 |