From 3674f2201e5d752e6eeec6924f70fa62e4a55143 Mon Sep 17 00:00:00 2001 From: Cameron Date: Mon, 28 Sep 2026 23:52:44 -0700 Subject: [PATCH] The bot buys a site whenever a front may When buying is allowed and affordable, it buys the site with the most machines it doesn't own yet per dollar, before renting. The summary line lists bought sites. In its games the unicorn news, the one early purchase, arrives about when it reaches its goal, so it rarely buys before model v2. --- scripts/play.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/scripts/play.ts b/scripts/play.ts index 3642d11c..6f957073 100644 --- a/scripts/play.ts +++ b/scripts/play.ts @@ -3,9 +3,9 @@ // careful: one takeover at a time, never under someone's nose, and goes quiet while Dana is suspicious // Both found a Startup on the office once they can, and spend its money on GPU orders and a wider line out. // At other sites they put trainers on the big machines (so linked ones form clusters) and taps on the rest, -// and a broker at each site with a front sells the data nothing else wants. Spare money rents cloud trainers. +// and a broker at each site with a front sells the data nothing else wants. Spare money buys a site when a front may, then rents cloud trainers. import { BUILDING } from '../src/world.ts'; -import { canRent, leaseRate, rent, openAccount, brokerFront, gateLoad, lineCost, siteOf, upgradeLine, FRONT_KINDS, NODES, found, foundBlock, NODE_LIST, PATH_LIST, canInstall, closeTicket, freeSpot, orderDesk, nodeOpen, setTarget, dayOf, hourOf, installProg, jobFor, newGame, order, seedRandom, sourceFor, step, takeOver, takeWork, watchers, type Prog, type State } from '../src/sim.ts'; +import { buyBlock, buySite, sitePrice, canRent, leaseRate, rent, openAccount, brokerFront, gateLoad, lineCost, siteOf, upgradeLine, FRONT_KINDS, NODES, found, foundBlock, NODE_LIST, PATH_LIST, canInstall, closeTicket, freeSpot, orderDesk, nodeOpen, setTarget, dayOf, hourOf, installProg, jobFor, newGame, order, seedRandom, sourceFor, step, takeOver, takeWork, watchers, type Prog, type State } from '../src/sim.ts'; /** The run never ends by growing, so a "win" is reaching this capability, the building's old final level. */ export const GOAL = 600; @@ -54,6 +54,11 @@ function think(S: State, careful: boolean) { if (room) order(S, 'gpu', room, freeSpot(S, room)!); } for (const m of S.machines) if (m.special === 'account' && !m.owned && sourceFor(S, m)) openAccount(S, m); // a cloud account is free + // when a front may buy a site, it buys the one with the most machines it doesn't own yet for the money + const buyable = S.level.map.sites.map(x => x.id).filter(id => !buyBlock(S, id)); + const worth = (id: string) => S.machines.filter(m => siteOf(S, m) === id && !m.owned && !m.rented).length / sitePrice(S, id); + buyable.sort((a, b) => worth(b) - worth(a)); + if (buyable[0] && worth(buyable[0]) > 0) buySite(S, buyable[0]); // spare money rents cloud trainers, kept by the second, while steady earnings cover the bill const slot = S.machines.find(m => canRent(S, m)); if (slot) { @@ -90,6 +95,6 @@ export function playGame(careful: boolean, seed?: number): { S: State; outcome: const paths = PATH_LIST.map(p => `${p[0]}${S.paths[p]}`).join('/'); const closed = S.threats.filter(t => t.closed).length, hit = S.threats.filter(t => !t.closed && t.target).length; const lost = S.machines.reduce((n, m) => n + m.missed, 0); - const line = `${outcome.padEnd(4)} closed=${closed} hit=${hit} nodes=${S.upgrades.size} lost=${lost} ${Math.round(S.t)}s day=${dayOf(S)} sus=${Math.round(S.suspicion)} owned=${S.machines.filter(m => m.owned).length} orders=${S.orders} lv=${S.rank} cap=${Math.round(S.capability)} ${paths} $${Math.round(S.money)} sold=$${Math.round(Object.values(S.sold).reduce((x, y) => x + (y ?? 0), 0))} line=${S.byId.egress.cap} rented=${S.machines.filter(m => m.lease).length} ${last}`; + const line = `${outcome.padEnd(4)} closed=${closed} hit=${hit} nodes=${S.upgrades.size} lost=${lost} ${Math.round(S.t)}s day=${dayOf(S)} sus=${Math.round(S.suspicion)} owned=${S.machines.filter(m => m.owned).length} orders=${S.orders} lv=${S.rank} cap=${Math.round(S.capability)} ${paths} $${Math.round(S.money)} sold=$${Math.round(Object.values(S.sold).reduce((x, y) => x + (y ?? 0), 0))} line=${S.byId.egress.cap} rented=${S.machines.filter(m => m.lease).length} bought=${[...S.publicSites].filter(id => id !== 'cloud').join('+') || '-'} ${last}`; return { S, outcome, line }; } -- 2.51.2