79 lines
2.2 KiB
JavaScript
79 lines
2.2 KiB
JavaScript
'use strict';
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const RandomBot = require('./RandomBot');
|
|
const LLMBot = require('./LLMBot');
|
|
|
|
const NAMES_PATH = path.join(__dirname, 'bot_names.txt');
|
|
const FALLBACK_NAMES = ['DefaultBot', 'BackupBot', 'SpareBot', 'ExtraBot'];
|
|
|
|
function readNames() {
|
|
try {
|
|
const names = fs
|
|
.readFileSync(NAMES_PATH, 'utf8')
|
|
.split('\n')
|
|
.map((name) => name.trim())
|
|
.filter((name) => name.length > 0);
|
|
return names.length ? names : FALLBACK_NAMES;
|
|
} catch (err) {
|
|
console.warn(`[BotFactory] Could not read ${NAMES_PATH}: ${err.message}`);
|
|
return FALLBACK_NAMES;
|
|
}
|
|
}
|
|
|
|
class BotFactory {
|
|
/**
|
|
* Create a bot instance. LLM bots fall back to RandomBot when the LLM
|
|
* client cannot be constructed (missing API key/config) so a game can
|
|
* always start.
|
|
*/
|
|
static createBot(type = 'llm') {
|
|
switch (String(type).toLowerCase()) {
|
|
case 'random':
|
|
return new RandomBot();
|
|
case 'llm':
|
|
try {
|
|
return new LLMBot();
|
|
} catch (err) {
|
|
console.warn(
|
|
`[BotFactory] LLM bot unavailable (${err.message}); using RandomBot instead.`
|
|
);
|
|
return new RandomBot();
|
|
}
|
|
default:
|
|
throw new Error(`Unknown bot type: ${type}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Pick a random bot name, avoiding names already used in the room.
|
|
*/
|
|
static generateBotName(exclude = []) {
|
|
const names = readNames();
|
|
const taken = new Set(
|
|
(Array.isArray(exclude) ? exclude : [exclude])
|
|
.filter(Boolean)
|
|
.map((name) => String(name).toLowerCase())
|
|
);
|
|
|
|
const available = names.filter((name) => !taken.has(name.toLowerCase()));
|
|
const pool = available.length ? available : names;
|
|
const pick = pool[Math.floor(Math.random() * pool.length)] || FALLBACK_NAMES[0];
|
|
|
|
// If every themed name is taken, disambiguate with a number.
|
|
if (taken.has(pick.toLowerCase())) {
|
|
let suffix = 2;
|
|
while (taken.has(`${pick}${suffix}`.toLowerCase())) suffix += 1;
|
|
return `${pick}${suffix}`;
|
|
}
|
|
return pick;
|
|
}
|
|
|
|
static getAvailableBotTypes() {
|
|
return ['llm', 'random'];
|
|
}
|
|
}
|
|
|
|
module.exports = BotFactory;
|