Words and universal macOS installer

This commit is contained in:
2026-02-06 00:37:08 +01:00
parent 3c518e4c5a
commit f1af4d2cdb
7 changed files with 232 additions and 2 deletions

View File

@@ -72,6 +72,8 @@ pub enum Op {
Cycle,
PCycle,
Choose,
Bounce,
WChoose,
ChanceExec,
ProbExec,
Coin,

View File

@@ -711,6 +711,61 @@ impl Forth {
drain_select_run(count, idx, stack, outputs, cmd)?;
}
Op::Bounce => {
let count = stack.pop().ok_or("stack underflow")?.as_int()? as usize;
if count == 0 {
return Err("bounce count must be > 0".into());
}
let idx = if count == 1 {
0
} else {
let period = 2 * (count - 1);
let raw = ctx.runs % period;
if raw < count { raw } else { period - raw }
};
drain_select_run(count, idx, stack, outputs, cmd)?;
}
Op::WChoose => {
let count = stack.pop().ok_or("stack underflow")?.as_int()? as usize;
if count == 0 {
return Err("wchoose count must be > 0".into());
}
let pairs_needed = count * 2;
if stack.len() < pairs_needed {
return Err("stack underflow".into());
}
let start = stack.len() - pairs_needed;
let mut values = Vec::with_capacity(count);
let mut weights = Vec::with_capacity(count);
for i in 0..count {
let val = stack[start + i * 2].clone();
let w = stack[start + i * 2 + 1].as_float()?;
if w < 0.0 {
return Err("wchoose: negative weight".into());
}
values.push(val);
weights.push(w);
}
stack.truncate(start);
let total: f64 = weights.iter().sum();
if total <= 0.0 {
return Err("wchoose: total weight must be > 0".into());
}
let threshold: f64 = self.rng.lock().gen::<f64>() * total;
let mut cumulative = 0.0;
let mut selected_idx = count - 1;
for (i, &w) in weights.iter().enumerate() {
cumulative += w;
if threshold < cumulative {
selected_idx = i;
break;
}
}
let selected = values.swap_remove(selected_idx);
select_and_run(selected, stack, outputs, cmd)?;
}
Op::ChanceExec | Op::ProbExec => {
let threshold = stack.pop().ok_or("stack underflow")?.as_float()?;
let quot = stack.pop().ok_or("stack underflow")?;

View File

@@ -66,6 +66,8 @@ pub(super) fn simple_op(name: &str) -> Option<Op> {
"cycle" => Op::Cycle,
"pcycle" => Op::PCycle,
"choose" => Op::Choose,
"bounce" => Op::Bounce,
"wchoose" => Op::WChoose,
"every" => Op::Every,
"chance" => Op::ChanceExec,
"prob" => Op::ProbExec,

View File

@@ -103,6 +103,26 @@ pub(super) const WORDS: &[Word] = &[
compile: Simple,
varargs: true,
},
Word {
name: "bounce",
aliases: &[],
category: "Probability",
stack: "(v1..vn n -- selected)",
desc: "Ping-pong cycle through n items by step runs",
example: "60 64 67 72 4 bounce",
compile: Simple,
varargs: true,
},
Word {
name: "wchoose",
aliases: &[],
category: "Probability",
stack: "(v1 w1 v2 w2 ... n -- selected)",
desc: "Weighted random pick from n value/weight pairs",
example: "60 0.6 64 0.3 67 0.1 3 wchoose",
compile: Simple,
varargs: true,
},
Word {
name: "always",
aliases: &[],