Sfoglia il codice sorgente

Add level stats (lines/speed) in select screen

Thomas Dy 3 anni fa
parent
commit
fc9944e9f0
5 ha cambiato i file con 80 aggiunte e 10 eliminazioni
  1. 14 5
      src/game/select.ts
  2. 1 0
      src/index.html
  3. 2 0
      src/kana.ts
  4. 59 0
      src/level.ts
  5. 4 5
      src/style.css

+ 14 - 5
src/game/select.ts

@@ -1,4 +1,4 @@
-import * as level from '../level';
+import { Level, LevelSet, calculateSpeed, calculateLines } from '../level';
 import * as util from '../util';
 import { GameContext, Screen } from './common';
 import { TypingScreen } from './typing';
@@ -87,6 +87,15 @@ export class SelectScreen implements Screen {
       link.textContent = 'More info';
       linkContainer.appendChild(link);
     }
+
+    const { lines, average } =
+      level.audio == null ? calculateLines(level) : calculateSpeed(level);
+
+    let lengthText = `${lines} lines`;
+    if (average > 0) {
+      lengthText += ` / ${Math.floor(average * 60)} KPM`;
+    }
+    this.songInfo.querySelector('.length')!.textContent = lengthText;
   }
 
   chooseSong(index: number): void {
@@ -115,14 +124,14 @@ export class SelectScreen implements Screen {
 
 class FolderSelectController {
   labelElement: HTMLElement;
-  levelSets: level.LevelSet[];
+  levelSets: LevelSet[];
   currentIndex: number;
   onFolderChange: (index: number) => void;
   listeners: util.ListenersManager;
 
   constructor(
     element: HTMLElement,
-    levelSets: level.LevelSet[],
+    levelSets: LevelSet[],
     onFolderChange: (index: number) => void
   ) {
     this.labelElement = util.getElement(element, '.label');
@@ -161,14 +170,14 @@ class FolderSelectController {
 
 class SongListController {
   element: HTMLElement;
-  levels: level.Level[];
+  levels: Level[];
   currentIndex: number;
   onSongChange: (index: number) => void;
   onSongChoose: (index: number) => void;
 
   constructor(
     context: GameContext,
-    levels: level.Level[],
+    levels: Level[],
     onSongChange: (index: number) => void,
     onSongChoose: (index: number) => void
   ) {

+ 1 - 0
src/index.html

@@ -28,6 +28,7 @@
             <div class="genre"></div>
             <div class="creator"></div>
             <div class="title"></div>
+            <div class="length"></div>
             <div class="link"></div>
           </div>
         </div>

+ 2 - 0
src/kana.ts

@@ -25,6 +25,8 @@ import {
   appendStates,
 } from './state';
 
+export const KANA_REGEX = /[ぁ-んァ-ン]/;
+
 function literal(source: string, ...extraBoundaries: number[]): StateMachine {
   let transitions: state.Transition[] = [];
   let meta = 0;

+ 59 - 0
src/level.ts

@@ -4,6 +4,8 @@
  * solely for display and the kana of the line which the input is based.
  */
 
+import { KANA_REGEX } from './kana';
+
 export interface Line {
   kanji: string;
   kana: string;
@@ -197,3 +199,60 @@ function parseTMSong(dom: Document): Line[] {
   }
   return lines;
 }
+
+interface LevelSpeed {
+  lines: number;
+  kana: number;
+  average: number;
+  maximum: number;
+}
+
+export function calculateLines(level: Level): LevelSpeed {
+  const lines = level.lines.length;
+  const kana = level.lines.reduce((acc, line) => acc + countKana(line.kana), 0);
+  return {
+    lines,
+    kana,
+    average: -1,
+    maximum: -1,
+  };
+}
+
+export function calculateSpeed(level: Level): LevelSpeed {
+  let count = 0;
+  let maximum = 0;
+  let total = 0;
+  let kanaTotal = 0;
+
+  for (const line of level.lines) {
+    if (line.kana === '' || line.kana === '@') {
+      continue;
+    }
+    if (line.start === undefined || line.end === undefined) {
+      continue;
+    }
+
+    const kanaCount = countKana(line.kana);
+    const duration = line.end - line.start;
+    const lineSpeed = kanaCount / duration;
+
+    count += 1;
+    maximum = Math.max(maximum, lineSpeed);
+    total += lineSpeed;
+    kanaTotal += kanaCount;
+  }
+  const average = total / count;
+  return {
+    lines: count,
+    kana: kanaTotal,
+    average,
+    maximum,
+  };
+}
+
+function countKana(input: string): number {
+  return input.split('').reduce((acc, c) => {
+    // non-kana is counted as half
+    return (KANA_REGEX.test(c) ? 1 : 0.5) + acc;
+  }, 0);
+}

+ 4 - 5
src/style.css

@@ -296,7 +296,7 @@
 /* song-info {{{ */
 
 #song-info {
-  margin-top: 10em;
+  margin-top: 9.5em;
   margin-left: 1.25em;
 }
 
@@ -312,18 +312,17 @@
 
 .song-info .genre {
   font-size: 0.75em;
+  height: 1.5em;
 }
 
 .song-info .creator {
   font-size: 1.25em;
+  height: 1.5em;
 }
 
 .song-info .title {
   font-size: 1.875em;
-}
-
-.song-info .link {
-  min-height: 1.5em;
+  height: 1.5em;
 }
 
 .song-info .link a {