Compare commits

...

3 Commits

Author SHA1 Message Date
semantic-release-bot
0eed26966c chore(release): 3.20.0 [skip ci]
## [3.20.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v3.19.0...v3.20.0) (2025-10-15)

### Features

* adjust tier probabilities for more abacus flavor ([49219e3](49219e34cd))

### Code Refactoring

* use per-word-type tier selection for name generation ([499ee52](499ee525a8))
2025-10-15 19:10:15 +00:00
Thomas Hallock
49219e34cd feat: adjust tier probabilities for more abacus flavor
Change weighted selection from 70/20/10 to 50/25/25:
- Emoji-specific: 70% → 50%
- Category-specific: 20% → 25%
- Global abacus: 10% → 25%

This increases abacus-themed words by 2.5x, ensuring stronger
presence of core abacus vocabulary (Calculator, Abacist, Counter)
while still maintaining emoji personality theming.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-15 14:09:25 -05:00
Thomas Hallock
499ee525a8 refactor: use per-word-type tier selection for name generation
Changed from tier-then-mix approach to per-word-type selection:
- Before: Pick one tier, then optionally mix with abacus words
- After: Pick tier independently for adjective and noun

Benefits:
- Simpler, cleaner code
- More natural variety in name combinations
- Adjective and noun can come from different tiers naturally
- Examples: "Grinning Calculator" (emoji + global), "Ancient Smiler" (global + emoji)

Each word still uses weighted selection:
- 70% emoji-specific
- 20% category-specific
- 10% global abacus

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-15 14:03:21 -05:00
4 changed files with 36 additions and 46 deletions

View File

@@ -1,3 +1,15 @@
## [3.20.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v3.19.0...v3.20.0) (2025-10-15)
### Features
* adjust tier probabilities for more abacus flavor ([49219e3](https://github.com/antialias/soroban-abacus-flashcards/commit/49219e34cde32736155a11929d10581e783cba69))
### Code Refactoring
* use per-word-type tier selection for name generation ([499ee52](https://github.com/antialias/soroban-abacus-flashcards/commit/499ee525a835249b439044cf602bf9f0ff322cec))
## [3.19.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v3.18.1...v3.19.0) (2025-10-15)

View File

@@ -73,7 +73,9 @@
"Bash(git restore:*)",
"Bash(timeout 10 npm run dev:*)",
"Bash(timeout 30 npm run dev)",
"Bash(pkill:*)"
"Bash(pkill:*)",
"Bash(for i in {1..30})",
"Bash(do gh run list --limit 1 --json conclusion,status,name,databaseId --jq '.[0] | \"\"\\(.status) - \\(.conclusion // \"\"running\"\") - Run ID: \\(.databaseId)\"\"')"
],
"deny": [],
"ask": []

View File

@@ -6,12 +6,7 @@
* Falls back gracefully: emoji-specific → category → generic abacus theme
*/
import {
EMOJI_SPECIFIC_WORDS,
EMOJI_TO_THEME,
THEMED_WORD_LISTS,
type ThemedWordList,
} from './themedWords'
import { EMOJI_SPECIFIC_WORDS, EMOJI_TO_THEME, THEMED_WORD_LISTS } from './themedWords'
// Generic abacus-themed words (used as ultimate fallback)
const ADJECTIVES = [
@@ -125,31 +120,30 @@ const NOUNS = [
]
/**
* Get themed word list for an emoji avatar using probabilistic tier selection
* Strongly prefers emoji-specific (70%), then category (20%), then global (10%)
* This adds variety while maintaining personality-matched theming
* Select a word list tier using weighted random selection
* Balanced mix: emoji-specific (50%), category (25%), global abacus (25%)
*/
function getThemedWordsForEmoji(emoji: string): ThemedWordList {
function selectWordListTier(emoji: string, wordType: 'adjectives' | 'nouns'): string[] {
// Collect available tiers
const availableTiers: Array<{ weight: number; words: ThemedWordList }> = []
const availableTiers: Array<{ weight: number; words: string[] }> = []
// Emoji-specific tier (70% preference)
// Emoji-specific tier (50% preference)
const emojiSpecific = EMOJI_SPECIFIC_WORDS[emoji]
if (emojiSpecific) {
availableTiers.push({ weight: 70, words: emojiSpecific })
availableTiers.push({ weight: 50, words: emojiSpecific[wordType] })
}
// Category tier (20% preference)
// Category tier (25% preference)
const category = EMOJI_TO_THEME[emoji]
if (category) {
const categoryTheme = THEMED_WORD_LISTS[category]
if (categoryTheme) {
availableTiers.push({ weight: 20, words: categoryTheme })
availableTiers.push({ weight: 25, words: categoryTheme[wordType] })
}
}
// Global abacus tier (10% preference)
availableTiers.push({ weight: 10, words: { adjectives: ADJECTIVES, nouns: NOUNS } })
// Global abacus tier (25% preference)
availableTiers.push({ weight: 25, words: wordType === 'adjectives' ? ADJECTIVES : NOUNS })
// Weighted random selection
const totalWeight = availableTiers.reduce((sum, tier) => sum + tier.weight, 0)
@@ -163,16 +157,16 @@ function getThemedWordsForEmoji(emoji: string): ThemedWordList {
}
// Fallback (should never reach here)
return { adjectives: ADJECTIVES, nouns: NOUNS }
return wordType === 'adjectives' ? ADJECTIVES : NOUNS
}
/**
* Generate a random player name by combining an adjective and noun
* Optionally themed based on avatar emoji for ultra-personalized names!
* Uses probabilistic tier selection and cross-tier mixing for abacus flavor
* Uses per-word-type probabilistic tier selection for natural variety
*
* @param emoji - Optional emoji avatar to theme the name around
* @returns A creative player name like "Grinning Calculator" or "Lightning Abacist"
* @returns A creative player name like "Grinning Calculator" or "Lightning Smiler"
*/
export function generatePlayerName(emoji?: string): string {
if (!emoji) {
@@ -182,31 +176,13 @@ export function generatePlayerName(emoji?: string): string {
return `${adjective} ${noun}`
}
// Get themed words using probabilistic tier selection
const themedWords = getThemedWordsForEmoji(emoji)
const abacusWords = { adjectives: ADJECTIVES, nouns: NOUNS }
// Select tier independently for each word type
// This creates natural mixing: adjective might be emoji-specific while noun is global
const adjectiveList = selectWordListTier(emoji, 'adjectives')
const nounList = selectWordListTier(emoji, 'nouns')
// 60% chance: Use themed words for both adjective and noun
// 30% chance: Mix themed adjective with abacus noun (infuses abacus flavor)
// 10% chance: Mix abacus adjective with themed noun (infuses abacus flavor)
const mixStrategy = Math.random()
let adjective: string
let noun: string
if (mixStrategy < 0.6) {
// Pure themed
adjective = themedWords.adjectives[Math.floor(Math.random() * themedWords.adjectives.length)]
noun = themedWords.nouns[Math.floor(Math.random() * themedWords.nouns.length)]
} else if (mixStrategy < 0.9) {
// Themed adjective + abacus noun
adjective = themedWords.adjectives[Math.floor(Math.random() * themedWords.adjectives.length)]
noun = abacusWords.nouns[Math.floor(Math.random() * abacusWords.nouns.length)]
} else {
// Abacus adjective + themed noun
adjective = abacusWords.adjectives[Math.floor(Math.random() * abacusWords.adjectives.length)]
noun = themedWords.nouns[Math.floor(Math.random() * themedWords.nouns.length)]
}
const adjective = adjectiveList[Math.floor(Math.random() * adjectiveList.length)]
const noun = nounList[Math.floor(Math.random() * nounList.length)]
return `${adjective} ${noun}`
}

View File

@@ -1,6 +1,6 @@
{
"name": "soroban-monorepo",
"version": "3.19.0",
"version": "3.20.0",
"private": true,
"description": "Beautiful Soroban Flashcard Generator - Monorepo",
"workspaces": [