glicko_to_elo.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. import Database from 'better-sqlite3';
  2. import ProgressBar from 'progress';
  3. import db from '../database.js';
  4. import {save_game_and_update_rating} from '../elo.js';
  5. db.pragma('synchronous = OFF');
  6. db.pragma('count_changes = OFF');
  7. db.pragma('journal_mode = MEMORY');
  8. db.pragma('temp_store = MEMORY');
  9. const RANK_DIVISIONS = [
  10. 'Cardboard',
  11. 'Wood',
  12. 'Wood+',
  13. 'Bronze',
  14. 'Bronze+',
  15. 'Silver',
  16. 'Silver+',
  17. 'Gold',
  18. 'Gold+',
  19. 'Platinum',
  20. 'Platinum+',
  21. 'Diamond',
  22. 'Diamond+',
  23. 'Legendary',
  24. ];
  25. function get_rank_text(rank_float) {
  26. if (rank_float == 1.0) {
  27. return 'The One';
  28. }
  29. // Epic rank distribution algorithm
  30. for (let i = 0; i < RANK_DIVISIONS.length; i++) {
  31. // Turn current 'Cardboard' rank into a value between 0 and 1
  32. const rank_nb = (i + 1) / RANK_DIVISIONS.length;
  33. // To make climbing ranks more satisfying, we make lower ranks more common.
  34. // Visual representation: https://graphtoy.com/?f1(x,t)=1-((cos(x%5E0.8*%F0%9D%9C%8B)/2)+0.5)&v1=true&f2(x,t)=&v2=true&f3(x,t)=&v3=false&f4(x,t)=&v4=false&f5(x,t)=&v5=false&f6(x,t)=&v6=false&grid=true&coords=0.3918011117299855,0.3722110561434862,1.0068654346588846
  35. const cutoff = 1 - ((Math.cos(Math.pow(rank_nb, 0.8) * Math.PI) / 2) + 0.5);
  36. if (rank_float < cutoff) {
  37. return RANK_DIVISIONS[i];
  38. }
  39. }
  40. // Ok, floating point errors, who cares
  41. return RANK_DIVISIONS[RANK_DIVISIONS.length - 1];
  42. }
  43. function save_s2_divisions() {
  44. db.exec('BEGIN TRANSACTION;');
  45. console.info('Saving S2 divisions...');
  46. const save_division = db.prepare(`UPDATE rating SET s2_division = ?, s2_scores = ? WHERE user_id = ? AND mode = ?`);
  47. const save_scores = db.prepare(`UPDATE rating SET s2_scores = ? WHERE user_id = ? AND mode = ?`);
  48. const old_db = new Database('old.db');
  49. for (let mode = 0; mode < 4; mode++) {
  50. const ratings = old_db.prepare(`SELECT user_id, s1_scores, total_scores FROM rating WHERE mode = ? AND sig < 100 ORDER BY elo DESC`).all(mode);
  51. const bar = new ProgressBar('[:bar] :rate/s | :etas remaining', {
  52. complete: '=', incomplete: ' ', width: 20, total: ratings.length,
  53. });
  54. for (let i = 0; i < ratings.length; i++) {
  55. const s2_scores = ratings[i].total_scores - ratings[i].s1_scores;
  56. if (s2_scores > 9) {
  57. const division = get_rank_text(1.0 - (i / ratings.length));
  58. save_division.run(division, s2_scores, ratings[i].user_id, mode);
  59. } else {
  60. save_scores.run(s2_scores, ratings[i].user_id, mode);
  61. }
  62. bar.tick(1);
  63. }
  64. }
  65. db.exec('COMMIT;');
  66. }
  67. async function glicko_to_elo() {
  68. db.exec('BEGIN TRANSACTION;');
  69. console.info('Loading games...');
  70. const old_db = new Database('old.db');
  71. const games = old_db.prepare(`SELECT * FROM game ORDER BY game_id ASC`).all();
  72. const get_scores = old_db.prepare(`SELECT * FROM score WHERE game_id = ?`);
  73. const bar = new ProgressBar('[:bar] :rate/s | :etas remaining', {
  74. complete: '=', incomplete: ' ', width: 20, total: games.length,
  75. });
  76. for (const game of games) {
  77. const scores = get_scores.all(game.game_id);
  78. await save_game_and_update_rating({id: game.match_id}, {
  79. id: game.game_id,
  80. mode_int: game.play_mode,
  81. beatmap: {
  82. id: game.beatmap_id,
  83. },
  84. start_time: new Date(game.start_time).toISOString(),
  85. end_time: new Date(game.end_time).toISOString(),
  86. scoring_type: game.scoring_type,
  87. team_type: game.team_type,
  88. mods: JSON.parse(game.mods),
  89. scores: scores.map((score) => {
  90. return {
  91. accuracy: score.accuracy,
  92. max_combo: score.max_combo,
  93. mods: JSON.parse(score.enabled_mods),
  94. statistics: {
  95. count_50: score.count_50,
  96. count_100: score.count_100,
  97. count_300: score.count_300,
  98. count_miss: score.count_miss,
  99. count_geki: score.count_geki,
  100. count_katu: score.count_katu,
  101. },
  102. perfect: score.perfect,
  103. created_at: new Date(score.created_at).toISOString(),
  104. score: score.score,
  105. user_id: score.user_id,
  106. dodged: score.dodged,
  107. };
  108. }),
  109. });
  110. bar.tick(1);
  111. }
  112. console.info('Saving...');
  113. db.exec('COMMIT;');
  114. console.info('Done!');
  115. }
  116. save_s2_divisions();
  117. glicko_to_elo().catch(console.error);