src / index.ts
//index.ts
import { createConfigSchematics } from "@lmstudio/sdk";
import { type PluginContext } from "@lmstudio/sdk";
import { tool } from "@lmstudio/sdk";
import fs from 'fs';
import path from 'path';
import { z } from "zod";
export const globalConfigSchematics = createConfigSchematics().build();
// --- MAIN ---
export async function main(context: PluginContext) {
//----------------------
// BC - solver
const bcTurn = tool({
name: "bc_solver",
description: "The Bull-Cow-game makes turn on a history basis. Input JSON data. Output is a turn candidate.",
parameters: {
gameHistory: z.array(z.object({ move: z.array(z.number()), resultBulls: z.number(), resultCows: z.number() })).describe("History input JSON")
},
implementation: async (input: any) => {
if (!input || !input.gameHistory) {
return `Empty data. New game assumed.`;
}
/**
* (Brute Force Bulls-and-Cows). Example.
*/
//const gameHistory = [
// { move: [1, 2, 3, 4], resultBulls: 0, resultCows: 3 }, // M1
// { move: [1, 2, 5, 6], resultBulls: 0, resultCows: 2 }, // M2
// { move: [2, 3, 5, 7], resultBulls: 1, resultCows: 0 }, // M3
// { move: [2, 1, 5, 7], resultBulls: 1, resultCows: 1 }, // M4
// { move: [3, 4, 7, 8], resultBulls: 1, resultCows: 0 }, // M5
//];
/**
* @param {number[]} guess - Candidate [d1, d2, d3, d4]
* @param {number[]} secret - Turn from history [s1, s2, s3, s4]
* @returns {{bulls: number, cows: number}} = Object with bulls/cows.
*/
function calculateBullsAndCows(guess, secret) {
let bulls = 0;
let totalMatches = 0;
for (let i = 0; i < 4; i++) {
if (guess[i] === secret[i]) { bulls++; }
if (secret.includes(guess[i])) { totalMatches++; }
}
const cows = totalMatches - bulls;
return { bulls: bulls, cows: cows };
}
/**
* Main Solver
*/
function solveBullsAndCows(history) {
// P(10, 4) = 5040
let centerOrder = [4, 5, 3, 6, 2, 7, 1, 8, 0, 9]; // waves from center
for (const d1 of centerOrder) { //(let d1 = 0; d1 <= 9; d1++) {
for (const d2 of centerOrder) { //(let d2 = 0; d2 <= 9; d2++) {
if (d2 === d1) continue;
for (const d3 of centerOrder) { //(let d3 = 0; d3 <= 9; d3++) {
if (d3 === d1 || d3 === d2) continue;
for (const d4 of centerOrder) { //(let d4 = 0; d4 <= 9; d4++) {
if (d4 === d1 || d4 === d2 || d4 === d3) continue; // skip
const candidateGuess = [d1, d2, d3, d4];
let isConsistent = true;
for (const game of history) {
const testMove = game.move;
let { bulls: calculatedBulls, cows: calculatedCows } = calculateBullsAndCows(candidateGuess, testMove);
const requiredResultBulls = game.resultBulls;
const requiredResultCows = game.resultCows;
// DEBUG: console.log(`guess:[${candidateGuess}] ${calculatedBulls}, ${calculatedCows} === move:[${testMove}]`, requiredResultBulls, requiredResultCows);
if (calculatedBulls !== requiredResultBulls || calculatedCows !== requiredResultCows) {
isConsistent = false;
break;
}
}
if (isConsistent) {
console.log(`Candidate: ${candidateGuess.join('')}`);
return candidateGuess;
}
}
}
}
}
// if No answer after all
console.log("\n--- GameOver ---");
return {result: `Contradiction in the input data. The brute force search ended without result.`}; //null;
}
// MAIN START: Вызываем решатель с нашей историей
const solution = solveBullsAndCows(input.gameHistory);
if (solution) {
console.log("Решение найдено и проверено!");
} else {
console.error("Не удалось найти решение в заданной истории.");
}
return solution;
}
});
//---
context.withToolsProvider(async () => {
return [bcTurn];
});
console.log("--- game BC version 1.0 ---");
}
//end.