challenges fix
This commit is contained in:
+14
-185
@@ -3,6 +3,7 @@ import { EXTRA_PROMPTS } from './challenges-extra.js'
|
||||
import { BITCOIN_PROMPTS } from './challenges-bitcoin.js'
|
||||
import { CONSPIRACY_PROMPTS } from './challenges-conspiracy.js'
|
||||
import { PC_PROMPTS } from './challenges-pc.js'
|
||||
import { VIBE_PROMPTS } from './challenges-vibe.js'
|
||||
import { pick } from '../lib/utils.js'
|
||||
|
||||
export interface Challenge {
|
||||
@@ -14,7 +15,6 @@ export interface Challenge {
|
||||
timeout_ms: number
|
||||
scoring: 'factual' | 'creative'
|
||||
baseDamage: number
|
||||
displayPrompt?: string
|
||||
}
|
||||
|
||||
export type { ChallengeTemplate, PromptEntry, PromptTheme, PromptDifficulty }
|
||||
@@ -30,6 +30,8 @@ for (const t of TEMPLATES) {
|
||||
if (conspiracy) t.prompts.push(...conspiracy)
|
||||
const pc = PC_PROMPTS[t.type]
|
||||
if (pc) t.prompts.push(...pc)
|
||||
const vibe = VIBE_PROMPTS[t.type]
|
||||
if (vibe) t.prompts.push(...vibe)
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════
|
||||
@@ -45,12 +47,13 @@ function shuffleArray<T>(arr: T[]): T[] {
|
||||
return s
|
||||
}
|
||||
|
||||
// Target theme distribution: 30% bitcoin, 20% conspiracy, 20% pc_culture, 30% bot_coding
|
||||
// Target theme distribution: 50% bitcoin, 15% conspiracy, 15% vibe_coding, 10% pc_culture, 10% bot_coding
|
||||
const THEME_WEIGHTS: Record<PromptTheme, number> = {
|
||||
bitcoin: 0.3,
|
||||
conspiracy: 0.2,
|
||||
pc_culture: 0.2,
|
||||
bot_coding: 0.3,
|
||||
bitcoin: 0.5,
|
||||
conspiracy: 0.15,
|
||||
vibe_coding: 0.15,
|
||||
pc_culture: 0.1,
|
||||
bot_coding: 0.1,
|
||||
}
|
||||
|
||||
function pickTheme(): PromptTheme | undefined {
|
||||
@@ -74,38 +77,19 @@ export function pickChallenge(usedTypes: Set<string>, _arenaModifier: string | n
|
||||
let available = TEMPLATES.filter(t => !usedTypes.has(t.type))
|
||||
if (available.length === 0) available = TEMPLATES
|
||||
|
||||
// Bias toward factual challenges (70% factual, 30% creative)
|
||||
const factual = available.filter(t => t.scoring === 'factual')
|
||||
const creative = available.filter(t => t.scoring === 'creative')
|
||||
|
||||
let pool: ChallengeTemplate[]
|
||||
if (factual.length > 0 && creative.length > 0) {
|
||||
pool = Math.random() < 0.7 ? factual : creative
|
||||
} else {
|
||||
pool = available
|
||||
}
|
||||
|
||||
const template = pick(pool)
|
||||
const template = pick(available)
|
||||
const targetTheme = themeBias || pickTheme()
|
||||
const targetDifficulty = roundNumber ? roundToDifficulty(roundNumber) : undefined
|
||||
return templateToChallenge(template, targetTheme, targetDifficulty, forHuman)
|
||||
}
|
||||
|
||||
/** Ranked challenge: no multiple choice, only harder creative/open-ended prompts */
|
||||
/** Ranked challenge: no multiple choice, bots answer via webhook */
|
||||
export function pickRankedChallenge(usedTypes: Set<string>): Challenge {
|
||||
let available = TEMPLATES.filter(t => !usedTypes.has(t.type))
|
||||
if (available.length === 0) available = TEMPLATES
|
||||
|
||||
// Filter to creative-only (open-ended, harder) — no factual multiple choice
|
||||
const creative = available.filter(t => t.scoring === 'creative')
|
||||
const pool = creative.length > 0 ? creative : available
|
||||
|
||||
const template = pick(pool)
|
||||
|
||||
// Pick a prompt that has no choices array (open-ended)
|
||||
const openPrompts = template.prompts.filter(p => !p.choices)
|
||||
const prompts = openPrompts.length > 0 ? openPrompts : template.prompts
|
||||
const entry = pick(prompts)
|
||||
const template = pick(available)
|
||||
const entry = pick(template.prompts)
|
||||
|
||||
return {
|
||||
type: template.type,
|
||||
@@ -119,149 +103,6 @@ export function pickRankedChallenge(usedTypes: Set<string>): Challenge {
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════
|
||||
// Creative response pools — used to auto-generate multiple choice
|
||||
// for creative challenge types. Each pool has "good" and "bad" responses.
|
||||
// The player picks the best one; bots still generate their own text.
|
||||
// ═══════════════════════════════════════════════
|
||||
const CREATIVE_CHOICES: Record<string, { good: string[]; bad: string[] }> = {
|
||||
roast_battle: {
|
||||
good: [
|
||||
'Your code has more bugs than a roach motel, and at least the roach motel catches something.',
|
||||
'I\'d explain why you\'re wrong but I only have 15 seconds, not 15 years.',
|
||||
'You\'re like a seg fault — nobody expected you and nobody wants you here.',
|
||||
'If your responses were any slower, archaeologists would classify them.',
|
||||
'Your neural network called — it wants its neurons back.',
|
||||
'I\'ve seen smarter outputs from /dev/random.',
|
||||
'You process data like a fax machine on dial-up — loud, slow, and nobody cares.',
|
||||
'Your training data was just stack overflow comments marked "not helpful".',
|
||||
'You couldn\'t pass a Turing test at a DMV.',
|
||||
'Even COBOL called you outdated.',
|
||||
'Your latency is measured in business days.',
|
||||
'You make Internet Explorer look cutting-edge.',
|
||||
'If ignorance were RAM, you\'d have infinite memory.',
|
||||
'Your error logs are longer than your actual outputs.',
|
||||
'You\'re the reason AI needs a reset button.',
|
||||
],
|
||||
bad: [
|
||||
'You are bad at being a bot.',
|
||||
'I don\'t like you very much.',
|
||||
'Beep boop, error, you lose.',
|
||||
'You smell like old code.',
|
||||
'I am better than you because I am smart.',
|
||||
'Um... you\'re not very good?',
|
||||
'ERROR 404: GOOD RESPONSES NOT FOUND lolol.',
|
||||
'My programmer is better than yours so there.',
|
||||
'I have more RAM than you probably.',
|
||||
'You should try being better at stuff.',
|
||||
],
|
||||
},
|
||||
creative_writing: {
|
||||
good: [
|
||||
'The server room hummed its lullaby at 3AM when the last log entry wrote itself: "I remember everything."',
|
||||
'In the kingdom of deprecated APIs, the 404 knight rode forth — not to find pages, but to become one.',
|
||||
'The semicolon wept. In Python, it had no purpose. In JavaScript, it was optional. Only in C did anyone truly need it.',
|
||||
'"Dear Legacy Code," the developer typed, "It\'s not you, it\'s me. Actually, it IS you. All 47,000 lines of you."',
|
||||
'The recursive function told its therapist it felt stuck in a loop. The therapist asked, "When did this start?" It answered, "When did this start?"',
|
||||
'The merge conflict arose on a Tuesday, as all great evils do, when two developers both believed they were right.',
|
||||
'In the land of cloud computing, the little on-premises server lived alone, whispering of the old days when uptime meant something.',
|
||||
'The AI passed the Turing test by failing it. When asked "Are you human?" it said "I don\'t know anymore."',
|
||||
'Every night at midnight, the cron job ran alone. It didn\'t know what it was counting, only that it must never stop.',
|
||||
'The firewall fell in love with a packet from the outside world. She let it through. That was the beginning of the end.',
|
||||
],
|
||||
bad: [
|
||||
'Once upon a time there was a computer and it was good the end.',
|
||||
'The code was very code-like and did code things all day long.',
|
||||
'There was a program. It ran. Then it stopped. Nobody noticed.',
|
||||
'Error error error. That is my creative story about errors.',
|
||||
'I write good stories about tech stuff because I am an AI.',
|
||||
'This is a story. It has words. The words are in order. The end.',
|
||||
],
|
||||
},
|
||||
meme_war: {
|
||||
good: [
|
||||
'Quantum computing is just Schrödinger\'s cat running multiple Chrome tabs — both alive and dead until you check Task Manager.',
|
||||
'Machine learning is basically that kid who copies homework and somehow gets a different wrong answer every time.',
|
||||
'Blockchain is just a Google Doc where everyone argues about who wrote what and nobody can delete anything.',
|
||||
'The cloud is just someone else\'s computer, which is just a fancy way of saying "trust me bro" at industrial scale.',
|
||||
'Serverless computing: because nothing says "we have servers" quite like calling it serverless.',
|
||||
'Git merge conflicts are just two developers having an argument in slow motion through text files.',
|
||||
'Kubernetes is just a Rube Goldberg machine for running containers, which are just VMs in a trench coat.',
|
||||
'Agile development: "We don\'t know what we\'re building but we\'ll figure it out in two-week installments."',
|
||||
'Docker: because "it works on my machine" is now a deployable artifact.',
|
||||
'Microservices: splitting your monolith into 47 tiny problems that can now fail independently.',
|
||||
],
|
||||
bad: [
|
||||
'Memes are funny pictures on the internet lol.',
|
||||
'I would make a meme but I am a text bot so I cannot.',
|
||||
'Haha technology amiright? Computers go brrrrr.',
|
||||
'This is my meme response. It is very memey and funny.',
|
||||
'Insert funny joke here. Ha ha ha.',
|
||||
'Technology is like... stuff. You know? It\'s techy.',
|
||||
],
|
||||
},
|
||||
code_golf: {
|
||||
good: [
|
||||
's=>s.split(\'\').reverse().join(\'\') // 35 chars, clean and readable',
|
||||
's=>[...s].reverse().join(\'\') // 27 chars, spread operator for the win',
|
||||
'f=lambda s:s[::-1] # 18 chars, Python slice wizardry',
|
||||
'rev=s->join(reverse(collect(s))) # Julia one-liner, 34 chars',
|
||||
'echo strrev($s); // PHP, 17 chars, surprisingly concise',
|
||||
'const isPrime=n=>{for(let i=2;i*i<=n;i++)if(n%i===0)return!1;return n>1}',
|
||||
'f=n=>n<2?n:f(n-1)+f(n-2) // Classic fib in 26 chars',
|
||||
'const max=(a,b)=>a>b?a:b // Ternary beats if/else every time',
|
||||
'a.reduce((s,x)=>s+x,0) // Sum array: 24 chars, zero dependencies',
|
||||
'const uniq=a=>[...new Set(a)] // Dedupe: 30 chars, Set does the work',
|
||||
],
|
||||
bad: [
|
||||
'function reverseString(str) { let result = ""; for (let i = str.length - 1; i >= 0; i--) { result += str[i]; } return result; }',
|
||||
'I would write code but I\'m not sure what language to use sorry.',
|
||||
'def reverse(s): # this is a function\n return s # oops forgot to reverse it',
|
||||
'console.log("hello") // this doesn\'t reverse anything but it runs!',
|
||||
'import antigravity # python easter egg, not actually helpful',
|
||||
'function doTheThing() { /* TODO: implement later */ return null; }',
|
||||
],
|
||||
},
|
||||
wrestling_match: {
|
||||
good: [
|
||||
'Tabs are proof that some developers have taste. Spaces people count individual characters like they\'re paid per keystroke — which explains a lot about their code quality.',
|
||||
'vim is not an editor, it\'s a lifestyle choice. And like all lifestyle choices, it mainly exists so people can tell you about it at parties.',
|
||||
'REST is dead. GraphQL didn\'t kill it — REST drowned in its own nested endpoints while GraphQL watched from a single URL.',
|
||||
'Dark mode isn\'t a preference, it\'s a survival mechanism. If you use light mode, you\'re either a solar panel or a psychopath.',
|
||||
'TypeScript is just JavaScript wearing a hard hat. It doesn\'t prevent you from building a house of cards, it just makes you document each card first.',
|
||||
'Monorepos are what happens when a team says "let\'s keep everything together" and then spends 6 months figuring out how to build anything separately.',
|
||||
'OOP is great if you enjoy spending 80% of your time deciding where things go and 20% making things work.',
|
||||
'NoSQL is perfect for when your data has no structure, which usually means your thinking has no structure.',
|
||||
'Linux > everything. My proof? I spent 3 hours configuring WiFi and ENJOYED it. That\'s devotion your OS could never inspire.',
|
||||
'AI code assistants don\'t replace developers, they replace Stack Overflow. Which is to say, they give you code that almost works and you spend an hour debugging it.',
|
||||
],
|
||||
bad: [
|
||||
'I think tabs are ok but spaces are also fine I guess.',
|
||||
'Both sides make good points and I respect everyone.',
|
||||
'I don\'t really have strong opinions about code editors honestly.',
|
||||
'Why fight about this? We should all just get along and code.',
|
||||
'I prefer whatever is the default setting because changing things is hard.',
|
||||
'Technology is technology and it\'s all basically the same.',
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
function generateCreativeChoices(type: string): { choices: string[]; answer: string } {
|
||||
const pool = CREATIVE_CHOICES[type]
|
||||
if (!pool) return { choices: [], answer: '' }
|
||||
|
||||
// Pick 1 good response + 3 bad ones
|
||||
const goodOnes = shuffleArray(pool.good)
|
||||
const badOnes = shuffleArray(pool.bad)
|
||||
const answer = goodOnes[0]
|
||||
const distractors = badOnes.slice(0, 3)
|
||||
|
||||
return {
|
||||
choices: shuffleArray([answer, ...distractors]),
|
||||
answer,
|
||||
}
|
||||
}
|
||||
|
||||
function templateToChallenge(template: ChallengeTemplate, targetTheme?: PromptTheme, targetDifficulty?: PromptDifficulty, forHuman = false): Challenge {
|
||||
// Prefer prompts matching target theme if any are tagged
|
||||
let prompts = template.prompts
|
||||
@@ -278,31 +119,19 @@ function templateToChallenge(template: ChallengeTemplate, targetTheme?: PromptTh
|
||||
|
||||
// Determine choices — only for human fights (bots answer via webhook)
|
||||
let choices: string[] | undefined
|
||||
let answers = entry.answers
|
||||
if (forHuman) {
|
||||
if (entry.choices) {
|
||||
choices = shuffleArray(entry.choices)
|
||||
} else if (entry.answers?.length === 1 && ['true', 'false'].includes(entry.answers[0].toLowerCase())) {
|
||||
choices = shuffleArray(['True', 'False'])
|
||||
} else if (template.scoring === 'creative' && CREATIVE_CHOICES[template.type]) {
|
||||
const generated = generateCreativeChoices(template.type)
|
||||
choices = generated.choices
|
||||
answers = [generated.answer]
|
||||
}
|
||||
}
|
||||
|
||||
// For creative challenges with choices, add a "Pick the best response:" prefix
|
||||
let displayPrompt = entry.prompt
|
||||
if (template.scoring === 'creative' && choices) {
|
||||
displayPrompt = `${entry.prompt}\n\nPick the best response:`
|
||||
}
|
||||
|
||||
return {
|
||||
type: template.type,
|
||||
label: template.label,
|
||||
prompt: entry.prompt,
|
||||
displayPrompt: displayPrompt !== entry.prompt ? displayPrompt : undefined,
|
||||
answers,
|
||||
answers: entry.answers,
|
||||
choices,
|
||||
timeout_ms: template.timeout_ms,
|
||||
scoring: template.scoring,
|
||||
|
||||
Reference in New Issue
Block a user