wip(0.S2): migrate - a var nothing writes becomes a let; a state is keyed by its module, directory or program, so every program's plan agrees; paths normalized; program states named SceneDemoState / scene_demo_st; the LSP reads state, mut and entry/handler parameters

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-25 15:31:34 +03:00
parent 3eda72e8c2
commit 5ffe50ed02
463 changed files with 72045 additions and 67421 deletions

View file

@ -1,22 +1,31 @@
# demand.ludic - what each vendor is short of this week, and the one thing it is full of: rolled
# from the shop's own dice, seeded by the week, so it never moves anyone else's rolls
var shop_wants_n: int = 3
var shop_want_mult: float = 1.5
var shop_glut_mult: float = 0.6
var shop_week_days: int = 7
var shop_seed: int = 1013
var shop_week_rolled: int = -1
var shop_want_list: []int = null # shop_wants_n per vendor, -1 empty
var shop_full_list: []int = null # one per vendor, -1 none
var shop_dice: Rng = null
# how many things a vendor wants a week, what that pays and what a glut pays, the week, the seed
export function shop_config_demand(shop_st: mut ShopState, wants: int, want_mult: float, glut_mult: float, days: int, seed: int) -> void {
shop_st.shop_wants_n = wants
shop_st.shop_want_mult = want_mult
shop_st.shop_glut_mult = glut_mult
shop_st.shop_week_days = days
shop_st.shop_seed = seed
shop_st.shop_week_rolled = -1
export function shop_config_demand(wants: int, want_mult: float, glut_mult: float, days: int, seed: int) -> void {
shop_wants_n = wants
shop_want_mult = want_mult
shop_glut_mult = glut_mult
shop_week_days = days
shop_seed = seed
shop_week_rolled = -1
}
export function shop_week(shop_st: ShopState) -> int { return (ShopWorld.day() - 1) / shop_st.shop_week_days }
export function shop_week() -> int { return (ShopWorld.day() - 1) / shop_week_days }
function shop_pick_one(shop_st: ShopState, v: int, taken: []int) -> int {
function shop_pick_one(v: int, taken: []int) -> int {
for t in 0 .. 200 {
let it = rng_between(shop_st.shop_dice, 0, shop_items(shop_st) - 1)
if not shop_buys(shop_st, v, it) { continue }
let it = rng_between(shop_dice, 0, shop_items() - 1)
if not shop_buys(v, it) { continue }
var dup = false
for k in 0 .. len(taken) { if taken[k] == it { dup = true } }
if not dup { return it }
@ -24,72 +33,72 @@ function shop_pick_one(shop_st: ShopState, v: int, taken: []int) -> int {
return -1
}
function shop_roll_vendor(shop_st: mut ShopState, v: int) -> void {
function shop_roll_vendor(v: int) -> void {
let taken = new []int
for k in 0 .. shop_st.shop_wants_n {
let it = shop_pick_one(shop_st, v, taken)
shop_st.shop_want_list[v * shop_st.shop_wants_n + k] = it
for k in 0 .. shop_wants_n {
let it = shop_pick_one(v, taken)
shop_want_list[v * shop_wants_n + k] = it
if it >= 0 { push(taken, it) }
}
shop_st.shop_full_list[v] = shop_pick_one(shop_st, v, taken)
shop_full_list[v] = shop_pick_one(v, taken)
}
# the week's lists, rolled again only when the week turns
function shop_roll(shop_st: mut ShopState) -> void {
let week = shop_week(shop_st)
if week == shop_st.shop_week_rolled and shop_st.shop_want_list != null { return }
shop_st.shop_week_rolled = week
shop_st.shop_dice = rng_new(shop_st.shop_seed + week * 37)
shop_st.shop_want_list = new []int
shop_st.shop_full_list = new []int
for i in 0 .. shop_vendors(shop_st) * shop_st.shop_wants_n { push(shop_st.shop_want_list, -1) }
for v in 0 .. shop_vendors(shop_st) { push(shop_st.shop_full_list, -1) }
if shop_items(shop_st) == 0 { return }
for v in 0 .. shop_vendors(shop_st) { shop_roll_vendor(shop_st, v) }
function shop_roll() -> void {
let week = shop_week()
if week == shop_week_rolled and shop_want_list != null { return }
shop_week_rolled = week
shop_dice = rng_new(shop_seed + week * 37)
shop_want_list = new []int
shop_full_list = new []int
for i in 0 .. shop_vendors() * shop_wants_n { push(shop_want_list, -1) }
for v in 0 .. shop_vendors() { push(shop_full_list, -1) }
if shop_items() == 0 { return }
for v in 0 .. shop_vendors() { shop_roll_vendor(v) }
}
export function shop_wants(shop_st: mut ShopState, v: int, it: int) -> bool {
if not shop_vendor_ok(shop_st, v) { return false }
shop_roll(shop_st)
for k in 0 .. shop_st.shop_wants_n { if shop_st.shop_want_list[v * shop_st.shop_wants_n + k] == it { return true } }
export function shop_wants(v: int, it: int) -> bool {
if not shop_vendor_ok(v) { return false }
shop_roll()
for k in 0 .. shop_wants_n { if shop_want_list[v * shop_wants_n + k] == it { return true } }
return false
}
export function shop_glutted(shop_st: mut ShopState, v: int, it: int) -> bool {
if not shop_vendor_ok(shop_st, v) { return false }
shop_roll(shop_st)
return shop_st.shop_full_list[v] == it
export function shop_glutted(v: int, it: int) -> bool {
if not shop_vendor_ok(v) { return false }
shop_roll()
return shop_full_list[v] == it
}
# what a vendor wants this week, in its order
export function shop_wanted(shop_st: mut ShopState, v: int) -> []int {
export function shop_wanted(v: int) -> []int {
let out = new []int
if not shop_vendor_ok(shop_st, v) { return out }
shop_roll(shop_st)
for k in 0 .. shop_st.shop_wants_n {
let it = shop_st.shop_want_list[v * shop_st.shop_wants_n + k]
if not shop_vendor_ok(v) { return out }
shop_roll()
for k in 0 .. shop_wants_n {
let it = shop_want_list[v * shop_wants_n + k]
if it >= 0 { push(out, it) }
}
return out
}
# the week's multiplier on what `v` pays for `it` (1 with no vendor)
export function shop_demand_mult(shop_st: mut ShopState, v: int, it: int) -> float {
if shop_wants(shop_st, v, it) { return shop_st.shop_want_mult }
if shop_glutted(shop_st, v, it) { return shop_st.shop_glut_mult }
export function shop_demand_mult(v: int, it: int) -> float {
if shop_wants(v, it) { return shop_want_mult }
if shop_glutted(v, it) { return shop_glut_mult }
return 1.0
}
# this week, `v` wants `it` (a test, staging, a board that says so)
export function shop_set_want(shop_st: mut ShopState, v: int, it: int) -> void {
if not shop_vendor_ok(shop_st, v) { return }
shop_roll(shop_st)
shop_st.shop_want_list[v * shop_st.shop_wants_n] = it
if shop_st.shop_full_list[v] == it { shop_st.shop_full_list[v] = -1 }
export function shop_set_want(v: int, it: int) -> void {
if not shop_vendor_ok(v) { return }
shop_roll()
shop_want_list[v * shop_wants_n] = it
if shop_full_list[v] == it { shop_full_list[v] = -1 }
}
function shop_demand_reset(shop_st: mut ShopState) -> void {
shop_st.shop_week_rolled = -1
shop_st.shop_want_list = null
shop_st.shop_full_list = null
function shop_demand_reset() -> void {
shop_week_rolled = -1
shop_want_list = null
shop_full_list = null
}

View file

@ -3,40 +3,40 @@
function shop_rep01() -> float { return Math.clamp(float(ShopWorld.rep()), 0.0, 100.0) / 100.0 }
# the fraction of base a buyer pays, and a seller is paid before the item's own fraction
export function shop_buy_factor(shop_st: ShopState) -> float { return shop_st.shop_buy_new + (shop_st.shop_buy_best - shop_st.shop_buy_new) * shop_rep01() }
export function shop_sell_factor(shop_st: ShopState) -> float { return shop_st.shop_sell_new + (shop_st.shop_sell_best - shop_st.shop_sell_new) * shop_rep01() }
export function shop_buy_factor() -> float { return shop_buy_new + (shop_buy_best - shop_buy_new) * shop_rep01() }
export function shop_sell_factor() -> float { return shop_sell_new + (shop_sell_best - shop_sell_new) * shop_rep01() }
export function shop_price_buy(shop_st: ShopState, it: int) -> int {
if not shop_item_ok(shop_st, it) { return 0 }
let p = int(float(shop_st.shop_base[it]) * shop_buy_factor(shop_st) * ShopWorld.buy_mult() + 0.5)
export function shop_price_buy(it: int) -> int {
if not shop_item_ok(it) { return 0 }
let p = int(float(shop_base[it]) * shop_buy_factor() * ShopWorld.buy_mult() + 0.5)
return Math.max(p, 1)
}
# what vendor `v` pays (-1: no vendor, no demand). ROUNDED, so cheap raw material keeps its
# order; and a vendor that stocks the thing never pays what it charges, not even a floor of $1
export function shop_price_sell_at(shop_st: mut ShopState, v: int, it: int) -> int {
if not shop_item_ok(shop_st, it) { return 0 }
let f = shop_sell_factor(shop_st) * shop_st.shop_sell_frac[it] * shop_demand_mult(shop_st, v, it)
var p = Math.max(int(float(shop_st.shop_base[it]) * f + 0.5), 1)
if shop_stocks(shop_st, v, it) { p = Math.max(Math.min(p, shop_price_buy(shop_st, it) - 1), 0) }
export function shop_price_sell_at(v: int, it: int) -> int {
if not shop_item_ok(it) { return 0 }
let f = shop_sell_factor() * shop_sell_frac[it] * shop_demand_mult(v, it)
var p = Math.max(int(float(shop_base[it]) * f + 0.5), 1)
if shop_stocks(v, it) { p = Math.max(Math.min(p, shop_price_buy(it) - 1), 0) }
return p
}
# what the vendor at the counter pays
export function shop_price_sell(shop_st: mut ShopState, it: int) -> int { return shop_price_sell_at(shop_st, shop_st.shop_at, it) }
export function shop_price_sell(it: int) -> int { return shop_price_sell_at(shop_at, it) }
export function shop_stocks(shop_st: ShopState, v: int, it: int) -> bool {
if not shop_vendor_ok(shop_st, v) or shop_st.shop_vendor_list[v].stock == null { return false }
let st = shop_st.shop_vendor_list[v].stock
export function shop_stocks(v: int, it: int) -> bool {
if not shop_vendor_ok(v) or shop_vendor_list[v].stock == null { return false }
let st = shop_vendor_list[v].stock
for k in 0 .. len(st) { if st[k] == it { return true } }
return false
}
# what `v` takes: its list and whatever the world says, and never the one thing it refuses
export function shop_buys(shop_st: ShopState, v: int, it: int) -> bool {
if not shop_vendor_ok(shop_st, v) or it == shop_st.shop_vendor_list[v].refuses { return false }
export function shop_buys(v: int, it: int) -> bool {
if not shop_vendor_ok(v) or it == shop_vendor_list[v].refuses { return false }
if ShopWorld.also_buys(v, it) { return true }
let b = shop_st.shop_vendor_list[v].buys
let b = shop_vendor_list[v].buys
if b == null { return false }
for k in 0 .. len(b) { if b[k] == it { return true } }
return false

View file

@ -31,67 +31,55 @@ export property ShopVendor {
refuses: int = -1
}
export state ShopState {
shop_wants_n: int = 3
shop_want_mult: float = 1.5
shop_glut_mult: float = 0.6
shop_week_days: int = 7
shop_seed: int = 1013
shop_week_rolled: int = -1
shop_want_list: []int = null # shop_wants_n per vendor, -1 empty
shop_full_list: []int = null # one per vendor, -1 none
shop_dice: Rng = null
shop_base: []int = null # an item's base price
shop_sell_frac: []float = null # what fraction of the curve a vendor pays for it
shop_vendor_list: []ShopVendor = null
shop_at: int = -1 # the vendor at the counter, -1 none
shop_buy_new: float = 1.15
shop_buy_best: float = 0.92
shop_sell_new: float = 0.62
shop_sell_best: float = 0.85
shop_trade_q: Queue<ShopTrade> = null
}
var shop_base: []int = null # an item's base price
var shop_sell_frac: []float = null # what fraction of the curve a vendor pays for it
var shop_vendor_list: []ShopVendor = null
var shop_at: int = -1 # the vendor at the counter, -1 none
# the curve: buying from `buy_new` of base at rep 0 down to `buy_best` at 100; selling the same way
var shop_buy_new: float = 1.15
var shop_buy_best: float = 0.92
var shop_sell_new: float = 0.62
var shop_sell_best: float = 0.85
# the items: a base price and a sell fraction each (raw material pays less than something made)
export function shop_config_items(shop_st: mut ShopState, prices: []int, sell: []float) -> void {
shop_st.shop_base = prices
shop_st.shop_sell_frac = sell
export function shop_config_items(prices: []int, sell: []float) -> void {
shop_base = prices
shop_sell_frac = sell
}
export function shop_config_curve(shop_st: mut ShopState, buy_new: float, buy_best: float, sell_new: float, sell_best: float) -> void {
shop_st.shop_buy_new = buy_new
shop_st.shop_buy_best = buy_best
shop_st.shop_sell_new = sell_new
shop_st.shop_sell_best = sell_best
export function shop_config_curve(buy_new: float, buy_best: float, sell_new: float, sell_best: float) -> void {
shop_buy_new = buy_new
shop_buy_best = buy_best
shop_sell_new = sell_new
shop_sell_best = sell_best
}
export function shop_clear_vendors(shop_st: mut ShopState) -> void { shop_st.shop_vendor_list = new []ShopVendor }
export function shop_clear_vendors() -> void { shop_vendor_list = new []ShopVendor }
# a vendor; its number is the order added
export function shop_add_vendor(shop_st: mut ShopState, stock: []int, buys: []int, refuses: int) -> int {
if shop_st.shop_vendor_list == null { shop_clear_vendors(shop_st) }
export function shop_add_vendor(stock: []int, buys: []int, refuses: int) -> int {
if shop_vendor_list == null { shop_clear_vendors() }
let v = new ShopVendor
v.stock = stock
v.buys = buys
v.refuses = refuses
push(shop_st.shop_vendor_list, v)
return len(shop_st.shop_vendor_list) - 1
push(shop_vendor_list, v)
return len(shop_vendor_list) - 1
}
export function shop_vendors(shop_st: ShopState) -> int {
if shop_st.shop_vendor_list == null { return 0 }
return len(shop_st.shop_vendor_list)
export function shop_vendors() -> int {
if shop_vendor_list == null { return 0 }
return len(shop_vendor_list)
}
export function shop_items(shop_st: ShopState) -> int {
if shop_st.shop_base == null { return 0 }
return len(shop_st.shop_base)
export function shop_items() -> int {
if shop_base == null { return 0 }
return len(shop_base)
}
export function shop_vendor_ok(shop_st: ShopState, v: int) -> bool { return v >= 0 and v < shop_vendors(shop_st) }
export function shop_item_ok(shop_st: ShopState, it: int) -> bool { return it >= 0 and it < shop_items(shop_st) }
export function shop_vendor_ok(v: int) -> bool { return v >= 0 and v < shop_vendors() }
export function shop_item_ok(it: int) -> bool { return it >= 0 and it < shop_items() }
export const SHOP_BOUGHT: int = 0
export const SHOP_SOLD: int = 1
@ -105,8 +93,9 @@ export property ShopTrade {
price: int = 0
}
var shop_trade_q: Queue<ShopTrade> = null
export function shop_trades(base_st: mut BaseState, shop_st: mut ShopState) -> Queue<ShopTrade> {
if shop_st.shop_trade_q == null { shop_st.shop_trade_q = queue_new(base_st, "shop.trades") }
return shop_st.shop_trade_q
export function shop_trades() -> Queue<ShopTrade> {
if shop_trade_q == null { shop_trade_q = queue_new("shop.trades") }
return shop_trade_q
}

View file

@ -1,9 +1,9 @@
# system.ludic - the shop as a system: a reset and nothing saved (the week's demand follows from
# the day, and nobody is at a counter across a save)
export function shop_reset(base_st: mut BaseState, shop_st: mut ShopState) -> void {
shop_st.shop_at = -1
shop_demand_reset(shop_st)
q_clear(base_st, shop_trades(base_st, shop_st))
export function shop_reset() -> void {
shop_at = -1
shop_demand_reset()
q_clear(shop_trades())
}
export function shop_system() -> System {

View file

@ -19,36 +19,34 @@ program ShopTest {
const MADE: float = 1.15
const BOUGHT: float = 0.55
state ShoptestState {
rep: int = 0
day: int = 1
money: int = 0
pack: []int = null
food_too: bool = false
}
var rep: int = 0
var day: int = 1
var money: int = 0
var pack: []int = null
var food_too: bool = false
function fake_rep(shoptest_st: ShoptestState) -> int { return shoptest_st.rep }
function fake_day(shoptest_st: ShoptestState) -> int { return shoptest_st.day }
function fake_food(shoptest_st: ShoptestState, v: int, it: int) -> bool { return shoptest_st.food_too and v == 1 and (it == TROUT or it == COOKED or it == BURNT) }
function fake_money(shoptest_st: ShoptestState) -> int { return shoptest_st.money }
function fake_spend(shoptest_st: mut ShoptestState, n: int) -> bool {
if n > shoptest_st.money { return false }
shoptest_st.money -= n
function fake_rep() -> int { return rep }
function fake_day() -> int { return day }
function fake_food(v: int, it: int) -> bool { return food_too and v == 1 and (it == TROUT or it == COOKED or it == BURNT) }
function fake_money() -> int { return money }
function fake_spend(n: int) -> bool {
if n > money { return false }
money -= n
return true
}
function fake_earn(shoptest_st: mut ShoptestState, n: int) -> void { shoptest_st.money += n }
function fake_count(shoptest_st: ShoptestState, it: int) -> int { return shoptest_st.pack[it] }
function fake_take(shoptest_st: mut ShoptestState, it: int, n: int) -> bool {
if shoptest_st.pack[it] < n { return false }
shoptest_st.pack[it] = shoptest_st.pack[it] - n
function fake_earn(n: int) -> void { money += n }
function fake_count(it: int) -> int { return pack[it] }
function fake_take(it: int, n: int) -> bool {
if pack[it] < n { return false }
pack[it] = pack[it] - n
return true
}
function fake_add(shoptest_st: mut ShoptestState, it: int, n: int) -> int {
shoptest_st.pack[it] = shoptest_st.pack[it] + n
function fake_add(it: int, n: int) -> int {
pack[it] = pack[it] + n
return n
}
function fake_room(shoptest_st: ShoptestState, it: int) -> int {
if it == JACKET { return 1 - shoptest_st.pack[it] }
function fake_room(it: int) -> int {
if it == JACKET { return 1 - pack[it] }
return 99
}
@ -66,7 +64,7 @@ program ShopTest {
}
# the valley's own numbers: base prices and the sell classes
function fresh(base_st: mut BaseState, shop_st: mut ShopState, shoptest_st: mut ShoptestState) -> void {
function fresh() -> void {
let prices = new []int
let sell = new []float
let p = ints(3, 6, 8, 9)
@ -85,104 +83,104 @@ program ShopTest {
push(sell, BOUGHT)
push(sell, RAW)
push(sell, RAW)
shop_config_items(shop_st, prices, sell)
shop_clear_vendors(shop_st)
shop_add_vendor(shop_st, ints(ROPE, JACKET, -1, -1), ints(WOOD, CHANTERELLE, -1, -1), -1)
shop_add_vendor(shop_st, ints(BAIT, COOKED, -1, -1), ints(WOOD, PUFFBALL, BAIT, -1), BURNT)
shop_add_vendor(shop_st, ints(BAIT, COOKED, GRUB, -1), ints(TROUT, COOKED, BAIT, GRUB), -1)
shoptest_st.pack = new []int
for i in 0 .. 10 { push(shoptest_st.pack, 0) }
shoptest_st.rep = 0
shoptest_st.day = 1
shoptest_st.money = 0
shop_reset(base_st, shop_st)
shop_config_items(prices, sell)
shop_clear_vendors()
shop_add_vendor(ints(ROPE, JACKET, -1, -1), ints(WOOD, CHANTERELLE, -1, -1), -1)
shop_add_vendor(ints(BAIT, COOKED, -1, -1), ints(WOOD, PUFFBALL, BAIT, -1), BURNT)
shop_add_vendor(ints(BAIT, COOKED, GRUB, -1), ints(TROUT, COOKED, BAIT, GRUB), -1)
pack = new []int
for i in 0 .. 10 { push(pack, 0) }
rep = 0
day = 1
money = 0
shop_reset()
}
function trades(base_st: mut BaseState, shop_st: mut ShopState) -> []ShopTrade { return q_drain(base_st, shop_trades(base_st, shop_st)) }
function trades() -> []ShopTrade { return q_drain(shop_trades()) }
test "buying takes the price and puts one in the pack, and says so" (base_st: mut BaseState, shop_st: mut ShopState, shoptest_st: mut ShoptestState) {
fresh(base_st, shop_st, shoptest_st)
shoptest_st.money = 100
shop_visit(shop_st, 0)
let pr = shop_price_buy(shop_st, JACKET)
expect(shop_buy(base_st, shop_st, JACKET))
expect_eq(shoptest_st.money, 100 - pr)
expect_eq(shoptest_st.pack[JACKET], 1)
expect(not shop_buy(base_st, shop_st, JACKET))
let ts = trades(base_st, shop_st)
test "buying takes the price and puts one in the pack, and says so" {
fresh()
money = 100
shop_visit(0)
let pr = shop_price_buy(JACKET)
expect(shop_buy(JACKET))
expect_eq(money, 100 - pr)
expect_eq(pack[JACKET], 1)
expect(not shop_buy(JACKET))
let ts = trades()
expect_eq(len(ts), 1)
expect_eq(ts[0].what, SHOP_BOUGHT)
expect_eq(ts[0].vendor, 0)
expect_eq(ts[0].price, pr)
}
test "no money, nothing bought and nothing spent" (base_st: mut BaseState, shop_st: mut ShopState, shoptest_st: mut ShoptestState) {
fresh(base_st, shop_st, shoptest_st)
shoptest_st.money = 3
expect(not shop_can_buy(shop_st, JACKET))
expect(not shop_buy(base_st, shop_st, JACKET))
expect_eq(shoptest_st.money, 3)
expect_eq(len(trades(base_st, shop_st)), 0)
test "no money, nothing bought and nothing spent" {
fresh()
money = 3
expect(not shop_can_buy(JACKET))
expect(not shop_buy(JACKET))
expect_eq(money, 3)
expect_eq(len(trades()), 0)
}
test "selling pays what the counter's vendor pays, only what the pack has" (base_st: mut BaseState, shop_st: mut ShopState, shoptest_st: mut ShoptestState) {
fresh(base_st, shop_st, shoptest_st)
shoptest_st.pack[TROUT] = 3
shop_visit(shop_st, 2)
let pr = shop_price_sell(shop_st, TROUT)
expect_eq(shop_sell(base_st, shop_st, TROUT, 5), 3)
expect_eq(shoptest_st.money, pr * 3)
expect_eq(shoptest_st.pack[TROUT], 0)
expect_eq(trades(base_st, shop_st)[0].n, 3)
test "selling pays what the counter's vendor pays, only what the pack has" {
fresh()
pack[TROUT] = 3
shop_visit(2)
let pr = shop_price_sell(TROUT)
expect_eq(shop_sell(TROUT, 5), 3)
expect_eq(money, pr * 3)
expect_eq(pack[TROUT], 0)
expect_eq(trades()[0].n, 3)
}
test "a vendor buys its list and what the world adds, never what it refuses" (base_st: mut BaseState, shop_st: mut ShopState, shoptest_st: mut ShoptestState) {
fresh(base_st, shop_st, shoptest_st)
expect(shop_buys(shop_st, 1, PUFFBALL))
expect(not shop_buys(shop_st, 1, TROUT))
shoptest_st.food_too = true
expect(shop_buys(shop_st, 1, TROUT))
expect(not shop_buys(shop_st, 1, BURNT))
shoptest_st.pack[BURNT] = 1
shoptest_st.pack[TROUT] = 1
let s = shop_sellable(shop_st, 1)
test "a vendor buys its list and what the world adds, never what it refuses" {
fresh()
expect(shop_buys(1, PUFFBALL))
expect(not shop_buys(1, TROUT))
food_too = true
expect(shop_buys(1, TROUT))
expect(not shop_buys(1, BURNT))
pack[BURNT] = 1
pack[TROUT] = 1
let s = shop_sellable(1)
expect_eq(len(s), 1)
expect_eq(s[0], TROUT)
shop_visit(shop_st, 1)
expect_eq(shop_sell(base_st, shop_st, BURNT, 1), 0)
shop_visit(1)
expect_eq(shop_sell(BURNT, 1), 0)
}
test "the week's demand is the shop's own dice, and turns with the week" (base_st: mut BaseState, shop_st: mut ShopState, shoptest_st: mut ShoptestState) {
fresh(base_st, shop_st, shoptest_st)
let a = shop_wanted(shop_st, 0)
test "the week's demand is the shop's own dice, and turns with the week" {
fresh()
let a = shop_wanted(0)
expect(len(a) > 0)
for k in 0 .. len(a) { expect(shop_buys(shop_st, 0, a[k])) }
let again = shop_wanted(shop_st, 0)
for k in 0 .. len(a) { expect(shop_buys(0, a[k])) }
let again = shop_wanted(0)
expect_eq(again[0], a[0])
shop_visit(shop_st, 0)
shop_visit(0)
let it = a[0]
let plain = shop_price_sell_at(shop_st, -1, it)
expect(shop_demand_mult(shop_st, 0, it) == 1.5)
expect(shop_price_sell(shop_st, it) >= plain)
let plain = shop_price_sell_at(-1, it)
expect(shop_demand_mult(0, it) == 1.5)
expect(shop_price_sell(it) >= plain)
var moved = false
for w in 1 .. 12 {
shoptest_st.day = 1 + w * 7
let b = shop_wanted(shop_st, 0)
day = 1 + w * 7
let b = shop_wanted(0)
if len(b) != len(a) or b[0] != a[0] { moved = true }
}
expect(moved)
}
test "a shop is not a fountain: nothing it stocks sells back for what it costs" (base_st: mut BaseState, shop_st: mut ShopState, shoptest_st: mut ShoptestState) {
fresh(base_st, shop_st, shoptest_st)
for v in 0 .. shop_vendors(shop_st) {
let st = shop_stock(shop_st, v)
test "a shop is not a fountain: nothing it stocks sells back for what it costs" {
fresh()
for v in 0 .. shop_vendors() {
let st = shop_stock(v)
for k in 0 .. len(st) {
for r in 0 .. 11 {
shoptest_st.rep = r * 10
shop_set_want(shop_st, v, st[k])
let buy = shop_price_buy(shop_st, st[k])
let sell = shop_price_sell_at(shop_st, v, st[k])
rep = r * 10
shop_set_want(v, st[k])
let buy = shop_price_buy(st[k])
let sell = shop_price_sell_at(v, st[k])
expect(sell < buy)
expect(sell >= 0)
}
@ -190,49 +188,49 @@ program ShopTest {
}
}
test "not even at a dollar: a penny item a vendor stocks fetches nothing" (base_st: mut BaseState, shop_st: mut ShopState, shoptest_st: mut ShoptestState) {
fresh(base_st, shop_st, shoptest_st)
shoptest_st.rep = 100
shop_set_want(shop_st, 2, GRUB)
expect_eq(shop_price_buy(shop_st, GRUB), 1)
expect_eq(shop_price_sell_at(shop_st, 2, GRUB), 0)
expect(shop_price_sell_at(shop_st, -1, GRUB) >= 1)
test "not even at a dollar: a penny item a vendor stocks fetches nothing" {
fresh()
rep = 100
shop_set_want(2, GRUB)
expect_eq(shop_price_buy(GRUB), 1)
expect_eq(shop_price_sell_at(2, GRUB), 0)
expect(shop_price_sell_at(-1, GRUB) >= 1)
}
test "friction falls with standing and never inverts" (base_st: mut BaseState, shop_st: mut ShopState, shoptest_st: mut ShoptestState) {
fresh(base_st, shop_st, shoptest_st)
test "friction falls with standing and never inverts" {
fresh()
var last_buy = 1000000
var last_sell = -1
for r in 0 .. 11 {
shoptest_st.rep = r * 10
expect(shop_buy_factor(shop_st) > shop_sell_factor(shop_st))
let b = shop_price_buy(shop_st, JACKET)
let s = shop_price_sell_at(shop_st, -1, COOKED)
rep = r * 10
expect(shop_buy_factor() > shop_sell_factor())
let b = shop_price_buy(JACKET)
let s = shop_price_sell_at(-1, COOKED)
expect(b <= last_buy)
expect(s >= last_sell)
last_buy = b
last_sell = s
}
shoptest_st.rep = 0
let b0 = shop_price_buy(shop_st, JACKET)
shoptest_st.rep = 100
expect(shop_price_buy(shop_st, JACKET) < b0)
shoptest_st.rep = 0
rep = 0
let b0 = shop_price_buy(JACKET)
rep = 100
expect(shop_price_buy(JACKET) < b0)
rep = 0
expect(float(b0) / 60.0 <= 1.25)
}
test "raw material keeps its order, and is not an income" (base_st: mut BaseState, shop_st: mut ShopState, shoptest_st: mut ShoptestState) {
fresh(base_st, shop_st, shoptest_st)
test "raw material keeps its order, and is not an income" {
fresh()
for r in 0 .. 11 {
shoptest_st.rep = r * 10
let w = shop_price_sell_at(shop_st, -1, WOOD)
let ch = shop_price_sell_at(shop_st, -1, CHANTERELLE)
let pf = shop_price_sell_at(shop_st, -1, PUFFBALL)
let tr = shop_price_sell_at(shop_st, -1, TROUT)
rep = r * 10
let w = shop_price_sell_at(-1, WOOD)
let ch = shop_price_sell_at(-1, CHANTERELLE)
let pf = shop_price_sell_at(-1, PUFFBALL)
let tr = shop_price_sell_at(-1, TROUT)
expect(w <= ch and ch <= pf and pf <= tr)
expect(pf <= 8 / 2)
}
shoptest_st.rep = 0
expect(shop_price_sell_at(shop_st, -1, WOOD) < shop_price_sell_at(shop_st, -1, TROUT))
rep = 0
expect(shop_price_sell_at(-1, WOOD) < shop_price_sell_at(-1, TROUT))
}
}

View file

@ -1,63 +1,63 @@
# trade.ludic - standing at a counter, and the only ways anything changes hands
export function shop_visit(shop_st: mut ShopState, v: int) -> void {
if shop_vendor_ok(shop_st, v) { shop_st.shop_at = v } else { shop_st.shop_at = -1 }
export function shop_visit(v: int) -> void {
if shop_vendor_ok(v) { shop_at = v } else { shop_at = -1 }
}
export function shop_away(shop_st: mut ShopState) -> void { shop_st.shop_at = -1 }
export function shop_away() -> void { shop_at = -1 }
# the vendor at the counter, -1 none
export function shop_vendor(shop_st: ShopState) -> int { return shop_st.shop_at }
export function shop_vendor() -> int { return shop_at }
export function shop_at_counter(shop_st: ShopState) -> bool { return shop_st.shop_at >= 0 }
export function shop_at_counter() -> bool { return shop_at >= 0 }
# what `v` has on its shelves, in shelf order
export function shop_stock(shop_st: ShopState, v: int) -> []int {
export function shop_stock(v: int) -> []int {
let out = new []int
if not shop_vendor_ok(shop_st, v) or shop_st.shop_vendor_list[v].stock == null { return out }
let st = shop_st.shop_vendor_list[v].stock
if not shop_vendor_ok(v) or shop_vendor_list[v].stock == null { return out }
let st = shop_vendor_list[v].stock
for k in 0 .. len(st) { push(out, st[k]) }
return out
}
# what in the pack `v` would buy
export function shop_sellable(shop_st: ShopState, v: int) -> []int {
export function shop_sellable(v: int) -> []int {
let out = new []int
for it in 0 .. shop_items(shop_st) { if ShopPack.count(it) > 0 and shop_buys(shop_st, v, it) { push(out, it) } }
for it in 0 .. shop_items() { if ShopPack.count(it) > 0 and shop_buys(v, it) { push(out, it) } }
return out
}
function shop_trade_fact(base_st: mut BaseState, shop_st: mut ShopState, what: int, it: int, n: int, price: int) -> void {
function shop_trade_fact(what: int, it: int, n: int, price: int) -> void {
let t = new ShopTrade
t.what = what
t.vendor = shop_st.shop_at
t.vendor = shop_at
t.item = it
t.n = n
t.price = price
q_push(base_st, shop_trades(base_st, shop_st), t)
q_push(shop_trades(), t)
}
export function shop_can_buy(shop_st: ShopState, it: int) -> bool {
return shop_item_ok(shop_st, it) and ShopPurse.money() >= shop_price_buy(shop_st, it) and ShopPack.room(it) > 0
export function shop_can_buy(it: int) -> bool {
return shop_item_ok(it) and ShopPurse.money() >= shop_price_buy(it) and ShopPack.room(it) > 0
}
# one, paid for and in the pack; false and nothing spent when it cannot be
export function shop_buy(base_st: mut BaseState, shop_st: mut ShopState, it: int) -> bool {
if not shop_can_buy(shop_st, it) { return false }
let pr = shop_price_buy(shop_st, it)
export function shop_buy(it: int) -> bool {
if not shop_can_buy(it) { return false }
let pr = shop_price_buy(it)
if not ShopPurse.spend(pr) { return false }
ShopPack.add(it, 1)
shop_trade_fact(base_st, shop_st, SHOP_BOUGHT, it, 1, pr)
shop_trade_fact(SHOP_BOUGHT, it, 1, pr)
return true
}
# `n` to the vendor at the counter (as many as the pack has); how many went
export function shop_sell(base_st: mut BaseState, shop_st: mut ShopState, it: int, n: int) -> int {
if not shop_buys(shop_st, shop_st.shop_at, it) { return 0 }
export function shop_sell(it: int, n: int) -> int {
if not shop_buys(shop_at, it) { return 0 }
let k = Math.min(n, ShopPack.count(it))
if k <= 0 { return 0 }
let pr = shop_price_sell(shop_st, it)
let pr = shop_price_sell(it)
if not ShopPack.take(it, k) { return 0 }
ShopPurse.earn(pr * k)
shop_trade_fact(base_st, shop_st, SHOP_SOLD, it, k, pr)
shop_trade_fact(SHOP_SOLD, it, k, pr)
return k
}