![[백준 문제 추천/개발 일지] (1) 개발 이유 + sovled.ac API 사용하기](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCgwbV%2FbtsHJCqxblS%2F6n7DqKaXTzUXIwljDAorSk%2Fimg.png)
백준 문제 추천
알고리즘 스터디를 하다보니 다양한 실력을 가진 사람들을 만난다. 나보다 훨씬 뛰어난 실력으로 문제를 풀어가는 사람이 있는가 하면 내가 어떤 문제를 풀어보면 좋을 것 같다고 추천을 해줄 수 있는 사람들도 만난다. 근데 나를 포함한 이들의 모든 공통점이 어떤 문제를 풀어야 할지 고민을 한다. 자신의 실력대가 어디에 있는지, 자신의 실력대에 풀면 가장 좋은 문제가 뭔지, 어떤 알고리즘을 공부하고 싶은데 어떤 문제를 풀어야 하는지 고르기 힘들어 하거나 모른다. 이런 문제를 추천해주는 블로그, 포스트글 같은건 엄청 많다. 하지만 문제를 풀라고 하는 사람의 개인에 맞춘 추천을 해주지 않는다.
나는 그래서 사용자 개인에게 맞춤 문제 추천 사이트를 만드려고 한다.
요구사항
1. 개인의 실력에 맞춘 추천 서비스
2. 알고리즘 별 실력에 맞춘 추천 서비스
이 2가지를 무조건 충족 시키고 싶으며
더 나아가 스터디 백준 그룹 기능을 사용해서 스터디 별로 문제를 모을 수 있도록 하고 싶다.
그래서 어떻게 백준 문제를 가져올 꺼야?
고민을 꽤 많이 한 부분이다. 처음에 시도하려고 했던 부분은 내가 푼 문제를 가지고 추천하는 방식이였다.
나는 문제를 풀고 나면 github에 이런 형식으로 {문제 번호}_{문제 이름}으로 적는 방식을 선택했다. 따라서 내 문제들을 githhub API를 사용해서 불러온뒤 이 문제들 사이에서 알고리즘 종류를 나누고 추천해줄 까 생각했다.
내가 풀어본 문제들은 처음에는 막풀었지만 나중에는 나름 해당 알고리즘에서 유명한 문제 위주로 풀어봤기 때문에 좋은 추천이 될꺼라 생각했었다.
문제 1. 실력에 맞춘 추천 불가
실력에 맞춘 추천을 하기에는 사용자가 얼마나 문제를 잘푸는지 비교할 만한 지표가 없다.
문제 2. 알고리즘 별 나누기 힘듬
내가 직접 파일 어딘가에 난이도를 적어둔다 한들 내가 안풀어본 알고리즘 문제가 있을 것이고
내가 풀어본 횟수가 적어서 효율적인 추천을 못할 수 도 있다.
그러던중 문제 id를 알면 solved.ac에서 난이도를 가져올 수 있다는 블로그 글을 보았다.
@solvedac/unofficial-documentation
이 프로젝트는 solved.ac API를 문서화하는 커뮤니티 프로젝트입니다. 이 저장소는 원작자의 요청에 따라 언제든 지워질 수 있으며, 현재 API와 일치하지 않을 수도 있는 점 양해 부탁드립니다.
solvedac.github.io
solved.ac API
위 링크로 들어가면 sovled.ac API를 문서화 하는 커뮤니티 프로젝트를 볼 수 있다.
여기서 여러 아이디어를 얻었다.
처음 생각은 문제 추천이 필요한 사람의 이름(백준에서는 아이디 중복을 허용하지 않아서 key값으로 사용해도 무관하다)을 입력하면 사람의 이름을 통해서 푼 문제를 가져오고 내가 푼 문제랑 비교해서 내 문제중 안푼 문제를 추천해주거나
사용자가 비교하고 싶은 사람을 정해서 등록하면 그 사람들의 푼 문제들 중에서 추천해줄까 생각했다.
이렇게 읽어만 봐도 비효율적임을 알 수 있다.
일단 문제를 열심히 푸는 사람이 주변에 없어서 누굴 등록해야할지 모르는 사용자가 있을 수 있고
내가 그렇게 문제를 많이 푼건 아니라 이것 또한 효율적인 방법이 아닌거 같았다.
그래서 다음 방법을 사용하려고 한다.
1. 미리 백준의 모든 문제, 테그(알고리즘 종류 이름)를 가져와 DB에 저장한다.
2. 사용자가 이름을 입력하면 사용자의 정보 + 사용자가 푼문제를 가져와 DB에 저장한다.
3. 사용자가 푼문제를 바탕으로 사용자의 등급이 정해져 있으니 이를 비교해서 사용자에게 문제를 추천한다.
아직 추천 알고리즘은 생각해보지 않았다.
아마 사용자의 알고리즘 별 티어 혹은 총 티어가 계산되면
그 티어에서 사용자가 많이 푼 문제 상위 100개중 1개를 랜덤으로 풀어보라 추천할 꺼 같다.
Java언어로 sovled.ac API 사용하기
공식 문서를 보면 알 수 있겠지만 query가 상세히 설명되어 있지 않아서 애를 먹은 부분이다. 다른 sovled.ac API사용하는 분들에게 도움이 됐음 좋겠어서 작성한다. json형식은 공식 문서에서 확인하길 바란다.
1. 사용자 이름으로 사용자 정보 가져오기
//사용자 이름으로 사용자 정보 가져오기
private static String getUserByName(String User) {
String uri = "https://solved.ac/api/v3/search/user?query=" + User;
return uri;
}
User정보를 입력해주면 query에서 user를 검색하는 API를 return해주는 메소드 이다.
2. 사용자 이름으로 사용자가 푼 문제 가져오기
private static String getUserSolvedProblemByName(String User) {
String uri = "https://solved.ac/api/v3/search/problem?query=s%40" + User;
return uri;
}
User정보를 입력해주면 query에서 user가 푼 문제들을 가져와 주는 메소드이다.
query=s%40을 적어야 하던데 왜 s%40을 적어야 하는지는 도저히 모르겠다.
근데 안적으면 동작을 안한다. 다른 api들도 사용자를 query로 받을 때 앞에 이게 들어간다.
solved.ac 사이트의 html을 개발자 툴로 열심히 찾아서 알아냈다.
3. 백준 문제들을 숫자열을 입력해서 가져오기
private static String getProblemByArray(List<Integer> problemIds) {
String problemIdsParam = problemIds.stream()
.map(String::valueOf)
.collect(Collectors.joining(","));
String uri = "https://solved.ac/api/v3/problem/lookup?problemIds=" + problemIdsParam;
return uri;
}
숫자 배열을 넣어주면 그 숫자 배열에 해당하는 문제들을 return해준다.
[1000,1001] 이런식으로 하면 1000번 문제, 1001번 문제를 알려준다.
없는 문제를 입력하면 에러가 아닌 공백으로 알려주니 걱정 안해도 될것 같다.
4. 백준 문제들의 알고리즘 종류인 tag들 가져오기
private static String getTag(){
String uri = "https://solved.ac/api/v3/search/tag?query";
return uri;
}
백준의 알고리즘을 종류별로 정렬하고 이름을 붙이는데 그게 Tag이다.
이것을 한번에 어떻게 다 가져오지 고민했는데
뒤에 query만 붙이고 api를 보내봤더니 tag전부를 보내줬다.
운이 좋다고 할 수 있다.
만약 안되면 받아온 문제들을 가지고 tag를 만드려고 했다.
5. 위 API URI를 사용하기 (HTTP 요청 사용)
private static void solvedacAPIRequest(String uri) throws IOException, InterruptedException {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(uri))
.header("x-solvedac-language", "ko")
.header("Accept", "application/json")
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
// JSON 데이터를 객체로 변환
Gson gson = new GsonBuilder().setPrettyPrinting().create();
Object jsonObject = gson.fromJson(response.body(), Object.class);
// 내가 잘 데이터가 왔는지 출력해볼라고 적음 지워도 됨
String prettyJson = gson.toJson(jsonObject);
System.out.println(prettyJson);
}
내가 만든 프로그램에서는 아마도 API요청이 동기적으로 이루어져야한다.
(사용자가 푼 문제가 DB에 다들어가기도 전에 문제를 가져와달라고 할 수 없으니)
그리고 데이터는 Json방식이 사용하기 편하기도하고 Body에서 json형식으로 보내줘 json을 사용했다.
이는 나중에 필요한 곳에서 알아서 가공해서 사용하는 방식으로 사용하려고 한다.
회고
sovled.ac를 만드신 분 동아리에서 필요해서 만드셨다는 데 엄청나게 감명받았다.
sovled.ac를 통해서 코딩테스트를 풀고 레이팅을 올리는데 도움을 엄청 받았다.
나도 열심히 살고 누군가에게 꼭 도움을 주는 삶을 살아봐야지
'Project : 백준 문제 추천 서비스 > 개발일지' 카테고리의 다른 글
[백준 문제 추천/개발 일지] (5) 추천 시스템 구성 + 코드 리팩토링 (1) | 2024.07.01 |
---|---|
[백준 문제 추천/개발 일지] (4) Mapping table 중복 문제 + api호출 요청을 줄이기 위한 노력? (0) | 2024.06.13 |
[백준 문제 추천/개발 일지] (3) 문제 DB에 저장하기 + tag랑 Mapping하기 (1) | 2024.06.11 |
[백준 문제 추천/개발 일지] (2) 문제 Tag DB에 저장하기 + 회고 (0) | 2024.06.04 |
Coding, Software, Computer Science 내가 공부한 것들 잘 이해했는지, 설명할 수 있는지 적는 공간