first commit
This commit is contained in:
158
game.ts
Normal file
158
game.ts
Normal file
@@ -0,0 +1,158 @@
|
||||
// Game logic for morse code practice
|
||||
|
||||
import { textToMorse, compareMorse, normalizeMorse } from "./morse.ts";
|
||||
|
||||
export type GameMode = 'letters' | 'numbers' | 'words' | 'phrases';
|
||||
|
||||
export interface GameConfig {
|
||||
mode: GameMode;
|
||||
rounds: number;
|
||||
timePerRound: number; // seconds
|
||||
}
|
||||
|
||||
export interface RoundResult {
|
||||
challenge: string;
|
||||
expectedMorse: string;
|
||||
userInput: string;
|
||||
correct: boolean;
|
||||
timeSpent: number; // milliseconds
|
||||
}
|
||||
|
||||
export interface GameSession {
|
||||
config: GameConfig;
|
||||
currentRound: number;
|
||||
results: RoundResult[];
|
||||
currentStreak: number;
|
||||
bestStreak: number;
|
||||
}
|
||||
|
||||
// Word banks for different difficulty levels
|
||||
const LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
|
||||
const NUMBERS = '0123456789'.split('');
|
||||
const WORDS = [
|
||||
'HELLO', 'WORLD', 'CODE', 'TIME', 'GAME', 'TEST', 'PLAY',
|
||||
'FAST', 'SLOW', 'HELP', 'GOOD', 'BEST', 'NICE', 'COOL',
|
||||
'MORSE', 'SIGNAL', 'RADIO', 'SEND', 'MESSAGE', 'QUICK',
|
||||
'LEARN', 'PRACTICE', 'SKILL', 'MASTER', 'EXPERT',
|
||||
];
|
||||
const PHRASES = [
|
||||
'HELLO WORLD',
|
||||
'GOOD MORNING',
|
||||
'HOW ARE YOU',
|
||||
'THANK YOU',
|
||||
'SEE YOU SOON',
|
||||
'HAVE A NICE DAY',
|
||||
'MORSE CODE',
|
||||
'QUICK BROWN FOX',
|
||||
'THE END',
|
||||
'WELL DONE',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get a random challenge based on game mode
|
||||
*/
|
||||
export function getChallenge(mode: GameMode): string {
|
||||
switch (mode) {
|
||||
case 'letters':
|
||||
return LETTERS[Math.floor(Math.random() * LETTERS.length)];
|
||||
case 'numbers':
|
||||
return NUMBERS[Math.floor(Math.random() * NUMBERS.length)];
|
||||
case 'words':
|
||||
return WORDS[Math.floor(Math.random() * WORDS.length)];
|
||||
case 'phrases':
|
||||
return PHRASES[Math.floor(Math.random() * PHRASES.length)];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new game session
|
||||
*/
|
||||
export function createGameSession(config: GameConfig): GameSession {
|
||||
return {
|
||||
config,
|
||||
currentRound: 0,
|
||||
results: [],
|
||||
currentStreak: 0,
|
||||
bestStreak: 0,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a round result
|
||||
*/
|
||||
export function processRound(
|
||||
session: GameSession,
|
||||
challenge: string,
|
||||
userInput: string,
|
||||
timeSpent: number
|
||||
): RoundResult {
|
||||
const expectedMorse = textToMorse(challenge);
|
||||
const normalizedInput = normalizeMorse(userInput);
|
||||
const correct = compareMorse(expectedMorse, normalizedInput);
|
||||
|
||||
const result: RoundResult = {
|
||||
challenge,
|
||||
expectedMorse,
|
||||
userInput: normalizedInput,
|
||||
correct,
|
||||
timeSpent,
|
||||
};
|
||||
|
||||
session.results.push(result);
|
||||
session.currentRound++;
|
||||
|
||||
// Update streak
|
||||
if (correct) {
|
||||
session.currentStreak++;
|
||||
session.bestStreak = Math.max(session.bestStreak, session.currentStreak);
|
||||
} else {
|
||||
session.currentStreak = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if game is complete
|
||||
*/
|
||||
export function isGameComplete(session: GameSession): boolean {
|
||||
return session.currentRound >= session.config.rounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get game summary statistics
|
||||
*/
|
||||
export function getGameSummary(session: GameSession) {
|
||||
const totalRounds = session.results.length;
|
||||
const correct = session.results.filter(r => r.correct).length;
|
||||
const incorrect = totalRounds - correct;
|
||||
const accuracy = totalRounds > 0 ? (correct / totalRounds) * 100 : 0;
|
||||
const averageTime = totalRounds > 0
|
||||
? session.results.reduce((sum, r) => sum + r.timeSpent, 0) / totalRounds
|
||||
: 0;
|
||||
|
||||
return {
|
||||
totalRounds,
|
||||
correct,
|
||||
incorrect,
|
||||
accuracy,
|
||||
averageTime,
|
||||
streak: session.bestStreak,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get difficulty description for a mode
|
||||
*/
|
||||
export function getDifficultyDescription(mode: GameMode): string {
|
||||
switch (mode) {
|
||||
case 'letters':
|
||||
return 'Single letters A-Z';
|
||||
case 'numbers':
|
||||
return 'Single digits 0-9';
|
||||
case 'words':
|
||||
return 'Common 4-6 letter words';
|
||||
case 'phrases':
|
||||
return 'Short phrases';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user