Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
376c8eb901 | ||
|
|
66992e8770 | ||
|
|
52019a24c2 | ||
|
|
54b46e771e | ||
|
|
334a49c92e |
19
CHANGELOG.md
19
CHANGELOG.md
@@ -1,3 +1,22 @@
|
||||
## [4.4.4](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.4.3...v4.4.4) (2025-10-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **complement-race:** add pressure decay system and improve logging ([66992e8](https://github.com/antialias/soroban-abacus-flashcards/commit/66992e877065a42d00379ef8fae0a6e252b0ffcb))
|
||||
|
||||
## [4.4.3](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.4.2...v4.4.3) (2025-10-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **complement-race:** train now moves in sprint mode ([54b46e7](https://github.com/antialias/soroban-abacus-flashcards/commit/54b46e771e654721e7fabb1f45ecd45daf8e447f))
|
||||
|
||||
|
||||
### Code Refactoring
|
||||
|
||||
* simplify train debug logs to strings only ([334a49c](https://github.com/antialias/soroban-abacus-flashcards/commit/334a49c92e112c852c483b5dbe3a3d0aef8a5c03))
|
||||
|
||||
## [4.4.2](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.4.1...v4.4.2) (2025-10-17)
|
||||
|
||||
|
||||
|
||||
@@ -93,23 +93,10 @@ export function SteamTrainJourney({
|
||||
currentQuestion,
|
||||
currentInput,
|
||||
}: SteamTrainJourneyProps) {
|
||||
console.log('🚂 [SteamTrainJourney] Render:', {
|
||||
momentum,
|
||||
trainPosition,
|
||||
pressure,
|
||||
elapsedTime,
|
||||
currentQuestion,
|
||||
currentInput,
|
||||
})
|
||||
|
||||
const { state } = useComplementRace()
|
||||
console.log('🚂 [SteamTrainJourney] State from provider:', {
|
||||
stations: state.stations,
|
||||
passengers: state.passengers,
|
||||
currentRoute: state.currentRoute,
|
||||
gamePhase: state.gamePhase,
|
||||
isGameActive: state.isGameActive,
|
||||
})
|
||||
console.log(
|
||||
`🚂 Train: mom=${momentum} pos=${trainPosition} stations=${state.stations.length} passengers=${state.passengers.length}`
|
||||
)
|
||||
|
||||
const { getSkyGradient, getTimeOfDayPeriod } = useSteamJourney()
|
||||
const _skyGradient = getSkyGradient()
|
||||
|
||||
@@ -240,6 +240,9 @@ export function ComplementRaceProvider({ children }: { children: ReactNode }) {
|
||||
})
|
||||
}, [activePlayers, players])
|
||||
|
||||
// Debug logging ref (track last logged values)
|
||||
const lastLogRef = useState({ key: '', count: 0 })[0]
|
||||
|
||||
// Transform multiplayer state to look like single-player state
|
||||
const compatibleState = useMemo((): CompatibleGameState => {
|
||||
const localPlayer = localPlayerId ? multiplayerState.players[localPlayerId] : null
|
||||
@@ -306,7 +309,7 @@ export function ComplementRaceProvider({ children }: { children: ReactNode }) {
|
||||
// Sprint mode specific
|
||||
momentum: localPlayer?.momentum || 0,
|
||||
trainPosition: localPlayer?.position || 0,
|
||||
pressure: localPlayer?.momentum ? Math.min(100, localPlayer.momentum + 10) : 0,
|
||||
pressure: localPlayer?.pressure || 0, // Use actual pressure from server (has decay)
|
||||
elapsedTime: multiplayerState.gameStartTime ? Date.now() - multiplayerState.gameStartTime : 0,
|
||||
lastCorrectAnswerTime: localPlayer?.lastAnswerTime || Date.now(),
|
||||
currentRoute: multiplayerState.currentRoute,
|
||||
@@ -330,14 +333,28 @@ export function ComplementRaceProvider({ children }: { children: ReactNode }) {
|
||||
}
|
||||
}, [multiplayerState, localPlayerId, localUIState])
|
||||
|
||||
console.log('🚂 [Provider] Transformed sprint values:', {
|
||||
momentum: compatibleState.momentum,
|
||||
trainPosition: compatibleState.trainPosition,
|
||||
pressure: compatibleState.pressure,
|
||||
stations: compatibleState.stations?.length,
|
||||
passengers: compatibleState.passengers?.length,
|
||||
currentRoute: compatibleState.currentRoute,
|
||||
})
|
||||
// Debug logging: only log on answer submission or significant events
|
||||
useEffect(() => {
|
||||
if (compatibleState.style === 'sprint' && compatibleState.isGameActive) {
|
||||
const key = `${compatibleState.correctAnswers}`
|
||||
|
||||
// Only log on new answers (not every frame)
|
||||
if (lastLogRef.key !== key) {
|
||||
console.log(
|
||||
`🚂 Answer #${compatibleState.correctAnswers}: momentum=${compatibleState.momentum} pos=${Math.floor(compatibleState.trainPosition)} pressure=${compatibleState.pressure} streak=${compatibleState.streak}`
|
||||
)
|
||||
lastLogRef.key = key
|
||||
}
|
||||
}
|
||||
}, [
|
||||
compatibleState.correctAnswers,
|
||||
compatibleState.momentum,
|
||||
compatibleState.trainPosition,
|
||||
compatibleState.pressure,
|
||||
compatibleState.streak,
|
||||
compatibleState.style,
|
||||
compatibleState.isGameActive,
|
||||
])
|
||||
|
||||
// Action creators
|
||||
const startGame = useCallback(() => {
|
||||
|
||||
@@ -170,6 +170,7 @@ export class ComplementRaceValidator
|
||||
totalQuestions: 0,
|
||||
position: 0,
|
||||
momentum: 50, // Start with some momentum in sprint mode
|
||||
pressure: 60, // Start with initial pressure
|
||||
isReady: false,
|
||||
isActive: true,
|
||||
currentAnswer: null,
|
||||
@@ -317,12 +318,25 @@ export class ComplementRaceValidator
|
||||
updatedPlayer.position = Math.min(100, player.position + 100 / state.config.raceGoal)
|
||||
}
|
||||
} else if (state.config.style === 'sprint') {
|
||||
// Sprint: Update momentum
|
||||
// Sprint: Update momentum, pressure, AND position
|
||||
if (correct) {
|
||||
updatedPlayer.momentum = Math.min(100, player.momentum + 15)
|
||||
// Add pressure on correct answer (add steam to boiler)
|
||||
updatedPlayer.pressure = Math.min(100, player.pressure + 20)
|
||||
} else {
|
||||
updatedPlayer.momentum = Math.max(0, player.momentum - 10)
|
||||
// Less pressure added on wrong answer
|
||||
updatedPlayer.pressure = Math.min(100, player.pressure + 5)
|
||||
}
|
||||
|
||||
// Pressure decay: Every answer causes some steam to escape
|
||||
// Decay rate: 8 points per answer (pressure naturally decreases over time)
|
||||
updatedPlayer.pressure = Math.max(0, updatedPlayer.pressure - 8)
|
||||
|
||||
// Move train based on momentum (momentum/20 = position change per answer)
|
||||
// Higher momentum = faster movement
|
||||
const moveDistance = updatedPlayer.momentum / 20
|
||||
updatedPlayer.position = Math.min(100, player.position + moveDistance)
|
||||
} else if (state.config.style === 'survival') {
|
||||
// Survival: Always move forward, speed based on accuracy
|
||||
const moveDistance = correct ? 5 : 2
|
||||
@@ -522,12 +536,14 @@ export class ComplementRaceValidator
|
||||
return { valid: false, error: 'Routes only available in sprint mode' }
|
||||
}
|
||||
|
||||
// Reset all player positions to 0
|
||||
// Reset all player positions to 0 for new route
|
||||
const resetPlayers: Record<string, PlayerState> = {}
|
||||
for (const [playerId, player] of Object.entries(state.players)) {
|
||||
resetPlayers[playerId] = {
|
||||
...player,
|
||||
position: 0,
|
||||
momentum: 50, // Reset momentum to starting value
|
||||
pressure: 60, // Reset pressure to starting value
|
||||
passengers: [], // Clear any remaining passengers
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ export interface PlayerState {
|
||||
// Position & Progress
|
||||
position: number // 0-100% for practice/sprint, lap count for survival
|
||||
momentum: number // 0-100 (sprint mode only)
|
||||
pressure: number // 0-100 (sprint mode only, decays over time)
|
||||
|
||||
// Current state
|
||||
isReady: boolean
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "soroban-monorepo",
|
||||
"version": "4.4.2",
|
||||
"version": "4.4.4",
|
||||
"private": true,
|
||||
"description": "Beautiful Soroban Flashcard Generator - Monorepo",
|
||||
"workspaces": [
|
||||
|
||||
Reference in New Issue
Block a user