ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 투덱 20만점 버그 구현
    BEMANI 2014. 2. 9. 08:36

    게임 도중의 점수는 부동 소수점 형태로 저장되지만 정수로 표시된다. 이로 인해 최종 점수에 반올림 오류가 발생해, 받아야 할 점수보다 1점 적은 점수를 받는 경우도 간혹 있는데, 이 과정에 대한 구체적인 알고리즘은 알려져 있지 않다고 한다.

    -- 리그베다 위키, [[beatmania IIDX]] 항목, 버전 1.70, 일부 표현 수정



    뭐, 그렇다고 하네요.

    계절학기 때 C++ 수업을 들었었는데 남는 시간을 약간 들여서 이걸 구현해 보는 소스를 짰었습니다. (수치 공식은 해당 항목에 명시된 것을 이용) 한동안 드랍박스 구석에 처박아 뒀다가 방금 갑자기 이게 생각나서 꺼내서 좀 수정해 봤죠.

    소스: http://pastebin.com/xP0vABej

    이 프로그램에서는 모든 노트를 PGREAT로 처리하는 퍼펙트 플레이(라기보다는 오토플레이?)를 가정하고, 아래 조건에서 현재 점수를 표기합니다.

    • 처음 10개 노트.
    • 이후 100단위 노트.
    • 마지막 10개 노트.

    노트 수가 573개일 경우의 결과입니다: http://pastebin.com/RN0waW5S

    여기서 주목해야 할 부분은 바로 마지막, 573번째 노트인데요. 실제로 구동해 보면 이런 결과가 나옵니다.

    1. PGREAT   573 SCORE 200000 / 199999.99999999965
    2.         (199999, 200000.00000000000) +349.88583158429

    200,000 또는 199,999로 시작하는 수치 4개는 모두 같은 변수에서 표시방법만 다르게 한 거였는데요, 각각

    1. setprecision(0)
    2. setprecision(11)
    3. static_cast<int>
    4. round()

    를 적용해서 나타낸 것입니다. (소스 54-55행) 거의 모든 경우에서 1번과 4번은 같게 표시되었습니다.

    역시 가장 중요한 건 2번입니다. 부동소수점의 특성으로 인해 발생하는 약간의 오차가 쌓여서 실제 값은 20만에 아주 약간 못 미치게 되고, 이걸 int형으로 cast 할 때에는 소수점 이하를 잘라버리기 때문에 200,000으로 표시되어야 할 값은 199,999가 돼 버리는 거죠.

    실제로 투덱 게임 상에서 이런 식으로 계산을 하는지는 모르겠지만, 아마도 이렇게 할 가능성이 높다고 봅니다. 점수는 정수로 표기되어야 하고, 그렇다면 생각하기 가장 쉬운 것은 역시 casting이겠죠. 이것이 KONMAI의 코딩 퀄리티인가 한 번 더 생각했다면 일어나지 않았을 버그라고 봅니다.

    PS. 난 왜 밤샘 하고 와서 잠도 안자고 이런거나 쓰고 있는가... ⅢOTL
    PS. 코드 다시 봤는데, 25~28행은 C++11에서는 필요없는 부분입니다. 학교 컴이 VS2010이라 round() 쪽이 꼬여버려서 임의로 만들어둔 건데 빼는 걸 잊어버렸네요.
    PS. 위키에 링크 걸면서 다시 생각해 봤는데, 반올림 오류라기보다는 오차 누적이 더 정확하겠네요. 수정했습니다


    'BEMANI' 카테고리의 다른 글

    Virkato Wakhmaninov (연표)  (0) 2017.03.30
    日天悦扇紊舞 / Akhuta  (0) 2017.01.29
    地の記 獄編 / あさき  (0) 2015.12.01
    PENDUAL TALISMAN 줄거리  (0) 2015.09.30
    TЁЯRA - ЁVOLUTIΦN  (0) 2014.01.28
Designed by Tistory.