Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 14 additions & 10 deletions src/superopt.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ function search (p) {
for (const x of p.target) need[x]++
for (const x of p.targetAlt) need[x]++
const useAlt = p.startAlt.length > 0 || p.targetAlt.length > 0 || p.allowAlt
const targetKey = p.target.join(',') + '|' + p.targetAlt.join(',')
const constList = [...p.consts.entries()].map(([sym, buf]) => [sym, pushOp(buf)])
const have = new Int32Array(nsym)

Expand All @@ -92,25 +91,32 @@ function search (p) {
return Math.max(Math.ceil(missing / 3), Math.ceil(surplus / 2))
}

const same = (a, b) => {
if (a.length !== b.length) return false
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false
return true
}
const isGoal = st =>
(!p.touch || st.t) && (!p.touchAlt || st.ta) &&
st.main.length === p.target.length && st.alt.length === p.targetAlt.length &&
(st.main.join(',') + '|' + st.alt.join(',')) === targetKey
same(st.main, p.target) && same(st.alt, p.targetAlt)

const keyOf = st => st.main.join(',') + '|' + st.alt.join(',') + '|' + (st.t ? 1 : 0) + (st.ta ? 1 : 0)
// Each state carries its own key: it is built once, when the state is made,
// rather than again at every pop and every goal test.
const keyOf = (main, alt, t, ta) => main.join(',') + '|' + alt.join(',') + '|' + (t ? 1 : 0) + (ta ? 1 : 0)

const root = { main: p.start.slice(), alt: p.startAlt.slice(), t: p.start.length === 0, ta: p.startAlt.length === 0, g: 0, parent: null, op: null }
root.key = keyOf(root.main, root.alt, root.t, root.ta)
const best = new Map()
const q = new BucketQueue()
const h0 = h(root.main, root.alt)
if (h0 >= p.bound) return null
q.push(h0, root)
best.set(keyOf(root), 0)
best.set(root.key, 0)
let expanded = 0

while (q.size) {
const st = q.pop()
if (best.get(keyOf(st)) < st.g) continue
if (best.get(st.key) < st.g) continue
if (isGoal(st)) {
const ops = []
for (let n = st; n.parent; n = n.parent) ops.push(...n.op.slice().reverse())
Expand All @@ -124,13 +130,11 @@ function search (p) {
if (g >= p.bound || main.length > p.maxLen || alt.length > p.maxAlt) return
const hh = h(main, alt)
if (g + hh >= p.bound) return
// A move that produces a non-goal state still costs at least one more byte.
const child = { main, alt, t: touched, ta: touchedAlt, g, parent: st, op: ops }
const k = keyOf(child)
const k = keyOf(main, alt, touched, touchedAlt)
const prev = best.get(k)
if (prev !== undefined && prev <= g) return
best.set(k, g)
q.push(g + hh, child)
q.push(g + hh, { main, alt, t: touched, ta: touchedAlt, g, parent: st, op: ops, key: k })
}

for (const [code, k, fn] of FIXED) {
Expand Down
8 changes: 6 additions & 2 deletions src/windows.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,13 @@ function windowsRegion (ops, g, ga, cache, opts = {}) {
problem.maxExpand = maxExpand
// Pure stack shuffles with constants are left to the table unless effort
// allows open-ended search; folding and alt-stack windows always search.
problem.tableOnly = !opts.searchAll && (
// The A* search's cost grows with the stack it starts from, while its
// wins do not: on real scripts every replacement it finds starts from a
// stack of at most ~16 items, and the deeper searches only run out their
// budget. Past that depth the window is left to the table.
problem.tableOnly = problem.start.length > (opts.searchMaxDepth ?? 16) || (!opts.searchAll && (
(!win.some(o => !isPush(o) && !STACK_OPS.has(o.code)) && !problem.allowAlt && !!problem.consts.size) ||
problem.start.length > tableN)
problem.start.length > tableN))
// The window's bytes plus the facts that constrain its replacement
// determine the answer, so they make a compact, reusable key.
const key = encode(win).toString('hex') + '|' + (problem.touch ? 1 : 0) + (problem.touchAlt ? 1 : 0) +
Expand Down
Loading