fork(1) download
  1. import collections
  2.  
  3. def calculate_osu_replay(objects, clicks):
  4. # 將物件放入 Queue 方便操作
  5. obj_queue = collections.deque(objects)
  6.  
  7. # 初始化統計數據
  8. stats = {
  9. "count_300": 0,
  10. "count_100": 0,
  11. "count_50": 0,
  12. "count_miss": 0,
  13. "max_combo": 0
  14. }
  15.  
  16. current_combo = 0
  17. total_objects = len(objects)
  18.  
  19. # 處理玩家的每一次點擊
  20. for click in clicks:
  21. if not obj_queue:
  22. break # 譜面已經沒有物件了,忽略後續所有點擊
  23.  
  24. # 1. 檢查在這次點擊之前,是否有物件已經「過期 Miss」了
  25. # (即該物件的最晚判定時間 < 這次點擊的時間)
  26. while obj_queue and obj_queue[0] + 100 < click:
  27. obj_queue.popleft()
  28. stats["count_miss"] += 1
  29. current_combo = 0 # 斷康
  30.  
  31. if not obj_queue:
  32. break
  33.  
  34. target_obj = obj_queue[0]
  35. dt = abs(click - target_obj)
  36.  
  37. # 2. 判斷點擊是否落在判定區間內
  38. if dt <= 100:
  39. # 命中物件,從 queue 中移除
  40. obj_queue.popleft()
  41. current_combo += 1
  42. stats["max_combo"] = max(stats["max_combo"], current_combo)
  43.  
  44. if dt <= 20:
  45. stats["count_300"] += 1
  46. elif dt <= 60:
  47. stats["count_100"] += 1
  48. else: # 60 < dt <= 100
  49. stats["count_50"] += 1
  50.  
  51. # 3. 如果 dt > 100 (表示過早點擊),不處理,保留物件等待下一次點擊
  52.  
  53. # 迴圈結束後,如果 queue 裡面還有物件,代表玩家根本沒點,全部算 Miss
  54. while obj_queue:
  55. obj_queue.popleft()
  56. stats["count_miss"] += 1
  57. current_combo = 0
  58.  
  59. # 計算準確度
  60. if total_objects == 0:
  61. accuracy = 0.0
  62. else:
  63. total_score = (stats["count_300"] * 300) + (stats["count_100"] * 100) + (stats["count_50"] * 50)
  64. max_possible_score = total_objects * 300
  65. accuracy = (total_score / max_possible_score) * 100
  66.  
  67. stats["accuracy"] = round(accuracy, 2)
  68.  
  69. return stats
  70.  
  71. # ==========================================
  72. # 測試區塊
  73. # ==========================================
  74. if __name__ == "__main__":
  75. # 測資 1: 完美全接 (Perfect SS)
  76. print("Test 1: Perfect SS")
  77. objects1 = [1000, 2000, 3000]
  78. clicks1 = [1005, 1990, 3000]
  79. print(calculate_osu_replay(objects1, clicks1))
  80.  
  81. # 測資 2: 包含空揮、Miss、斷Combo (範例測資)
  82. print("\nTest 2: Normal Play with Misses")
  83. objects2 = [1000, 1500, 2000, 2200, 3000]
  84. clicks2 = [500, 1015, 1450, 2150, 3090, 3150]
  85. print(calculate_osu_replay(objects2, clicks2))
  86.  
  87. # 測資 3: 中途放棄遊戲 (後面物件全部放推)
  88. print("\nTest 3: Quit halfway")
  89. objects3 = [1000, 1500, 2000, 2500, 3000]
  90. clicks3 = [1000, 1500]
  91. print(calculate_osu_replay(objects3, clicks3))
Success #stdin #stdout 0.02s 9448KB
stdin
Standard input is empty
stdout
Test 1: Perfect SS
{'count_300': 3, 'count_100': 0, 'count_50': 0, 'count_miss': 0, 'max_combo': 3, 'accuracy': 100.0}

Test 2: Normal Play with Misses
{'count_300': 1, 'count_100': 2, 'count_50': 1, 'count_miss': 1, 'max_combo': 2, 'accuracy': 36.67}

Test 3: Quit halfway
{'count_300': 2, 'count_100': 0, 'count_50': 0, 'count_miss': 3, 'max_combo': 2, 'accuracy': 40.0}