Android/랜덤리즘

[랜덤리즘] 문제를 어떻게 랜덤으로 보여주어야 할까?에 대한 고민

김 안개 2024. 2. 13. 16:15

랜덤리즘에서 제일 중요한 기능은 '랜덤으로 문제를 보여주는 것' 이라고 할 수 있다.

랜덤으로 문제를 어떻게 보여줄 수 있을지?에 대한 고민을 했었는데, 이때 했었던 생각들을 작성해보고자 한다!

 

고민을 하게 된 이유

일단, 내가 사용한 API 를 제공하는 solved.ac 에서는 아래와 같이 레벨별로 혹은 알고리즘 분류 별로 문제를 제공한다.

 

레벨에 따른 문제
알고리즘 분류(태그)에 따른 문제

 

원하는 레벨 혹은 알고리즘을 클릭하면 한 화면에 총 50개의 문제들을 오름차순으로 정렬된 ID(문제번호)를 기준으로 화면에 보여준다.

예시1) 브론즈4 레벨을 클릭한 경우, 브론즈4 에 해당되는 50개의 문제가 화면에 보여진다.

 

레벨에 맞는 50개의 문제가 보여짐

 

예시2) 그리디 알고리즘을 클릭한 경우, 그리디 알고리즘에 해당되는 50개의 문제가 화면에 보여진다.

 

알고리즘에 맞는 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