궤도

[백엔드] 시험지 채점 알고리즘 만들기 (2) 본문

💻 현생/📃 VIVA

[백엔드] 시험지 채점 알고리즘 만들기 (2)

영이오 2021. 5. 20. 14:52

https://myunji.tistory.com/391

 

[백엔드] 시험지 채점 알고리즘 만들기 (1)

오늘은 이 그림에서 7번을 구현할 것이다. 먼저 시험지를 촬영해서 욜로에 보내면...욜로는 우리가 설정한 클래스의 객체를 찾아낸다. 그리고 제이슨 형태로 결과를 반환하는데 뭐... label : OOO rec

myunji.tistory.com

여기에서 이어진다.

 

저때는 모든 객관식을 찾은 희망편이었고 이제 절망편을 해야한다.

절망편에는 어떻게 되는지 간단하게 보여주자면

 

이게

 

이렇게 된다.

 

객체를 하나 찾아내지 못해 번호가 앞으로 다 땡겨져 올 것이기 때문이다...

우리가 계속 실험을 해봤는데 다행히 아무리 많이 못찾아도 한 문제당 2개 정도가 최대였다. 이제 보정을 해야한다.

 

번호 배치는

이럴 수도 있고

 

이럴 수도 있다...

 

일단 좀 더 쉬운 일자 배치부터 구현하자.

대충 json을 보고 분석한 결과 연속된 두 번호의 x좌표차이는 70언저리였다.

그래서 정렬후 연속된 두 객체의 x좌표 차이가 130을 넘으면 중간에 번호가 빠졌겠거니 하기로 했다.

 

근데 1번이 빠지면 어떻게 할까..?

이걸 고민하면서 시험지를 뚫어져라 쳐다봤더니 답이 나왔다.

바로 spn의 x좌표다.

 

사진을 보면 알겠지만 spn과 1번의 x좌표는 매우 유사하다. 실제로 보니 대충 10언저리로 차이나는 듯하다.

그래서 spn의 x좌표를 첫번째 기준점으로 삼아서 채워나가면 되겠다 싶었다.

 

5번이 빠지면 어떻게 될까?

이 부분도 고려해서 코드를 짜봤는데 실행을 해보곤 쓸모없다는 것을 깨달았다.

객체를 못찾아서 답이 달라지는 이유는 위치가 땡겨지기 때문인데, 5번은 어차피 마지막이므로 위치 변화에 영향을 주지 않는다. 그래서 그냥 5번이 빠진건 보정하지 않도록 했다.

 

            spn_list = new Array();
            spn_list = cur.recognition_word; //spn에서 찾은 모든 단어
            spn_x = cur.x;
            spn = findSpn(spn_list);

일단 기존의 spn을 찾는 과정에 x좌표를 추가하고

 

                if (cnt > 1) //객관식 정리
                    check_list = refactoringCheck(spn_x, check_list);

refactoringCheck에 같이 넘겨준다.

 

    if (Math.abs(check_list[0].x_pos - spn_x) > 15) { //1번이 빠짐
        check_list.splice(0, 0, new check_info("uncheck_box", spn_x + 10, first_y));
    }
    for (var i=1;i<check_list.length;i++) {
        if (Math.abs(check_list[i].x_pos-check_list[i-1].x_pos) > 130) {
            check_list.splice(i, 0, new check_info("uncheck_box", check_list[i-1].x_pos + 70, check_list[i-1].y_pos));
        }
    }

정렬 이후에 등장하는 코드다.

먼저 check_list의 첫번째 객체의 x좌표와 spn의 x좌표 차이가 15보다 크면 1번이 빠진 것이므로 추가한다.

 

그리고 check_list를 돌면서 이전 객체와의 x좌표 차이가 130보다 크면 빠진 것으로 감안하고 보정한다.

 

그래서 출력으로 확인하면

기본 : 빠진 객체 없음
1번이 빠짐
3번이 빠짐
2번과 3번이 빠짐(연속)
2번과 4번이 빠짐(불연속)
5번이 빠짐(객체 4개여도 답 찾기에는 문제 없음)

이렇게 일자 배치는 해결했다.

 

그리고 두 줄 배치를 해결하려고 봤더니...간격 처리를 일자 배치 때처럼 하면 안될 듯 했다.

그래서 일단 코드를 지저분하게 짜놨는데 나중에 수정해야겠다.

    if (Math.abs(check_list[0].x_pos - spn_x) > 15) { //1번이 빠짐
        check_list.splice(0, 0, new check_info("uncheck_box", spn_x + 10, Math.min(first_y, second_y)));
    }
    if(second_y==100000) { //1줄
        for (var i = 1; i < check_list.length; i++) {
            if (Math.abs(check_list[i].x_pos - check_list[i - 1].x_pos) > 130) {
                check_list.splice(i, 0, new check_info("uncheck_box", check_list[i - 1].x_pos + 70, check_list[i - 1].y_pos));
            }
        }
    }
    else{ //2줄
        for(var i=1;i<check_list.length;i++){
            if((check_list[i].y_pos==check_list[i-1].y_pos)&&Math.abs(check_list[i].x_pos - check_list[i - 1].x_pos) > 230) //같은 줄
                check_list.splice(i, 0, new check_info("uncheck_box", check_list[i - 1].x_pos + 120, check_list[i - 1].y_pos));
            else if(check_list[i].y_pos!=check_list[i-1].y_pos){ //다른 줄
                if(i<3) //2, 3번이 빠진 상황
                    check_list.splice(i, 0, new check_info("uncheck_box", check_list[i - 1].x_pos + 120, check_list[i - 1].y_pos));
                else if(Math.abs(check_list[i].x_pos-check_list[0].x_pos)>20) //4번이 빠진 상황
                    check_list.splice(i, 0, new check_info("uncheck_box", check_list[i].x_pos - 120, check_list[i].y_pos));
            }
        }
    }

빠진 1번을 추가하는 방법은 둘 다 같다.

이제 second_y의 갱신 여부를 확인해서 1/2줄 배치를 구분한다.

 

만약 2줄일 때 두 객체의 y좌표가 같고 그 차이가 230을 넘으면 중간에(보통은 2번) 뭐가 빠진 것이니 추가한다.

만약 두 객체가 다른 줄이라면 2, 3번이 빠졌을 수도 있고 4번이 빠졌을 수도 있다.

 

2, 3번이 빠졌을 때는 인덱스 i가 3보다 작을 것이다. 왜인지는 구딩 설명하지 않겠다.

아무튼 그런 경우엔 윗줄에 객체를 추가하고 아닐 경우엔 1번과의 x좌표를 비교해서 i번째 객체가 4번인지 5번인지 확인한다. 만약 5번인게 확인 됐으면 4번이 빠진 것이니 추가하고...

 

일단은 돌아가는 것 같은데 영 코드가 지저분 해보여서 수정은 해야할 것 같다.

 

기본 : 빠진 객체 없음
2번 빠짐
4번 빠짐
2번, 4번 빠짐

아무튼 이렇게 되긴 됐는데...아직 테스트 데이터를 덜 확보해서 나중에 다시 확인해야겠다.

Comments