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 }; }