랜덤리즘에서 제일 중요한 기능은 '랜덤으로 문제를 보여주는 것' 이라고 할 수 있다.
랜덤으로 문제를 어떻게 보여줄 수 있을지?에 대한 고민을 했었는데, 이때 했었던 생각들을 작성해보고자 한다!
고민을 하게 된 이유
일단, 내가 사용한 API 를 제공하는 solved.ac 에서는 아래와 같이 레벨별로 혹은 알고리즘 분류 별로 문제를 제공한다.
원하는 레벨 혹은 알고리즘을 클릭하면 한 화면에 총 50개의 문제들을 오름차순으로 정렬된 ID(문제번호)를 기준으로 화면에 보여준다.
예시1) 브론즈4 레벨을 클릭한 경우, 브론즈4 에 해당되는 50개의 문제가 화면에 보여진다.
예시2) 그리디 알고리즘을 클릭한 경우, 그리디 알고리즘에 해당되는 50개의 문제가 화면에 보여진다.
고민한 방법들
1) 레벨/알고리즘을 선택하면 한 번에 모든 문제를 가져온 후, random() 함수를 통해 1개의 문제를 화면에 보여준다.
이 방법의 가장 큰 문제점은 알고리즘 <수학> 을 예시로 들어 얘기해보려고 한다.
<수학>의 총 문제 수는 5,955개, 네트워크 통신할 때 50개의 문제만 가져올 수 있다는 것을 생각해보면 120번의 네트워크 통신이 이루어진 후에 random() 함수를 통해 그 중 1개의 문제를 뽑아 화면에 보여주게 된다.
만약 사용자가 <수학> 을 선택했다가, <문자열> 을 선택하는 경우라면 120번 (수학) + 45번 (문자열) = 총 165번의 네트워크 통신이 이루어져야만 사용자는 문제를 볼 수 있다.
그렇다면 1문제를 확인하고 다른 알고리즘을 선택한다면 이렇게 많은 네트워크 통신을 하는 것이 좋은가? 불필요하게 많다는 생각이 들었다.
그리고 120번의 네트워크 통신을 하는 동안 UI 에는 로딩 프로그레스바가 표시될 것이고, 그 시간이 길어진다면 사용자는 앱을 이탈할 수 있다는 생각이 들었다.
그러므로 해당 방법은 좋지 않다고 판단되었다.
2) 한 페이지(50개의 문제)를 가져온 후, 10개의 문제가 보여졌다면 다음 페이지의 문제를 가져오는 것을 반복한다.
50개의 문제들을 List 에 담아놓고, 화면에 보여졌다는 표시를 하기 위해 Map 을 사용할 생각이었다. 아마도 Map<Boolean, Problem> 와 같은 형태로 되었을 것 같다.
그렇다면, key 가 false 인 문제들에 대해 random() 함수를 통해 1문제를 뽑아내고, 뽑아낸 문제의 key 는 true 로 변경한다.
아니면 random() 함수로 10개의 문제들을 뽑아낸 후, 새롭게 List 를 만들어내어 이 List 만 보여주어도 될 것 같다는 생각들었다!
그리고 화면에 보여준 문제의 개수를 카운팅하는 count 변수를 놓고 10개(새로운 문제셋을 받아오기 위한 임의의 기준선)가 되면 page = 1 가 아닌 page = 2 와 같이 다음 페이지로 request 를 보내어 다음 문제셋을 가져오는 것으로 생각했었다.
하지만, 아래와 같은 단점들이 있는 것 같아 좋은 방법이 아닌 것 같다고 판단되었다.
(1) List 의 형태를 또 다시 새롭게 Map 으로 만들어서 사용해야 한다는 점
(2) 이전에 화면에 보여졌는지 확인하기 위해 if 조건문을 사용해야 한다는 점
(3) 같은 레벨/알고리즘을 클릭할 때마다 1페이지부터 시작되니 사용자가 겹치는 문제들을 볼 수 있다는 점
(4) 매번 초반의 페이지만 사용이 되고, 후반 부 페이지의 데이터는 사용하지 않는다는 점
3) solved.ac 에서 제공하는 '시프트 마음대로' 필터 기능을 사용한다. ✅
지금까지는 내가 문제들을 random() 함수를 통해 컨트롤할 생각을 하였는데, 사이트를자세히 보니 '시프트 마음대로' 필터 기능이 있다는 것을 알았다.
https://solved.ac/problems/tags/greedy?sort=random&direction=asc&page=1
어떻게 랜덤으로 정렬되는 것인지 궁금하여서 개발자 도구를 통해 확인해보려 하였으나 html 을 제외하고는 다른 점이 보이지 않았다.
그래서 Web 을 공부하는 친구에게 혹시 어떻게 랜덤으로 정렬되는지 개발자 도구에서 알 수 있는 방법이 있냐고 물어보았으나 친구도 나와있지 않다며, 데이터베이스에서 처리되는 것 같다는 말을 해주었다.
'시프트 마음대로' 를 계속해서 누르면 쿼리가 direction=asc 부분이 direction=desc 로 변경되는 것 외에는 다른 변경점이 없었다.
이거다!!! 하나의 페이지(여기에서는 1페이지)만 가져와도 request 를 보낼 때마다 새로운 랜덤 문제들이 생성되니 쿼리문에서 page 를 변경해주지 않아도 되겠구나 싶었다.
다만, 한 번 요청할 때 50개의 문제들을 받을 수 있으니, count 변수를 두고 현재 몇 번째 문제를 보여주는지 체크하도록 하였다.
count 가 50개(네트워크로 가져온 문제리스트의 총 개수)가 되면 다시 네트워크 요청을 보내어 새로운 문제셋을 받도록 해주었다.
네트워크 요청을 보내서 50개의 문제들을 모두 사용하기 때문에 무분별하게 네트워크 요청을 보내는 1번의 단점을 가지지 않으며,
매번 문제셋이 달라지기때문에 2번의 단점도 해소할 수 있었다. (초반부의 데이터만 사용한다는 점, 같은 문제셋을 사용하지 않기때문에 겹치는 문제의 확률이 아주 낮다는 점)
적용한 방법
3번인 '시프트 마음대로' 기능을 사용하는 것으로 적용하였다!
관련 PR
1) 초기에 1번 방법으로 구현
[feat/RANDOM-7] 각 레벨/알고리즘 클릭 시, 1개의 문제가 화면에 표시 by w36495 · Pull Request #12 · w36495/r
ISSUE 각 레벨/알고리즘 클릭 시, 1개의 문제가 화면에 표시 구현 결과 레벨을 통한 문제 알고리즘을 통한 문제 고민한 부분 : 어떻게 1개의 문제를 보여줄 것인가? solved.ac 에서는 1페이지에 최대 50
github.com
2) 3번 방법으로 수정(적용)
[refactor/RANDOM-27] solved.ac 에서 제공하는 랜덤문제로 request 문 수정 by w36495 · Pull Request #28 · w36495/ra
ISSUE solved.ac 에서 제공하는 랜덤문제로 request 문 수정 (#27) 수정된 내용 수정 전 레벨/알고리즘에 대한 문제 목록을 가져올 때 문제번호로 정렬된 페이지(총 50문제) 를 가져왔다. 문제번호로 정렬
github.com
'Android > 랜덤리즘' 카테고리의 다른 글
[랜덤리즘] 관련 알고리즘 보이기/숨기기 기능 개발하기 -2 (1) | 2024.02.26 |
---|---|
[랜덤리즘] 관련 알고리즘 보이기/숨기기 기능 개발하기 -1 (0) | 2024.02.23 |
[랜덤리즘] 1차 배포하기 완료! (1) | 2024.02.21 |
개인정보처리방침 (0) | 2024.02.21 |
코딩테스트 편식하는 나를 위한 '랜덤리즘' (0) | 2024.02.03 |