From: Ian Jackson Date: Sat, 3 Oct 2020 19:32:33 +0000 (+0100) Subject: before try out bigfloat X-Git-Tag: otter-0.2.0~778 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=b1f6e009d0a5bb75d5b253be4ff1f5c4ee9651a8;p=otter.git before try out bigfloat Signed-off-by: Ian Jackson --- diff --git a/templates/script.ts b/templates/script.ts index 8793f0b7..49c8632e 100644 --- a/templates/script.ts +++ b/templates/script.ts @@ -295,7 +295,7 @@ function recompute_keybindings() { for (let celem = uos_node.firstElementChild; celem != null; celem = nextelem) { - var nextelem = celem.nextElementSibling + var nextelem = celem.nextElementSibling; let cid = celem.getAttribute("id"); if (cid == "uos-mid") mid_elem = celem; else if (celem.getAttribute("class") == 'uos-mid') { } @@ -330,7 +330,6 @@ function some_keydown(e: KeyboardEvent) { console.log('KEY UO', e, uo); if (uo.kind == 'Client' || uo.kind == 'ClientExtra') { let f = keyops_local[uo.opname]; - // xxx 'lower' f(uo); return; } @@ -349,6 +348,212 @@ function some_keydown(e: KeyboardEvent) { } } +keyops_local['lower'] = function (uo: UoRecord) { + // This is a bit subtle. We don't want to lower below pinned pieces + // (unless we are pinned too, or the user is wresting). But maybe + // the pinned pieces aren't already at the bottom. For now we will + // declare that all pinned pieces "should" be below all non-pinned + // ones. Not as an invariant, but as a thing we will do here to try + // to make a sensible result. We implement this as follows: if we + // find pinned pieces above non-pinned pieces, we move those pinned + // pieces to the bottom too, just below us, preserving their + // relative order. + // + // Disregarding pinned targets: + // + // Z + // Z + // topmost unpinned target * + // B ( + // B unpinned non-target + // B | unpinned target * + // B | pinned non-target, mis-stacked * + // B )* + // B + // bottommost unpinned non-target + // if that is below topmost unpinned target + // <- tomove_unpinned: insert targets from * here Q -> + // <- tomove_misstacked: insert non-targets from * here Q-> + // A + // A pinned things (nomove_pinned) + // <- tomove_pinned: insert all pinned targets here P -> + // + // When wresting, treat all targets as pinned. + + function target_treat_pinned(p: PieceInfo) => boolean { + wresting || p.pinned; + } + + type Todo = { + piece: PieceId, + p: PieceInfo, + pinned: boolean, + }; + let targets_todo = Object.create(null); + let n_targets_todo_unpinned = 0; + + for (let piece of uo.targets!) { + let p = pieces[piece]!; + let pinned = target_treat_pinned(p); + targets_todo[piece] = { p, piece, pinned, }; + if (!pinned) { n_targets_todo_unpinned++; } + } + + type Entry = { + piece: PieceId, + p: PieceInfo, + }; + // bottom of the stack order first + let tomove_unpinned = []; + let tomove_misstacked = []; + let nomove_pinned = []; + let tomove_pinned = []; + let bottommost_unpinned = null; + + let walk = pieces_marker; + for (;;) { // starting at the bottom of the stack order + if (Object.keys(targets_todo).length == 0) break; + walk = walk.nextElementSibling; if (walk == null) break; + let piece = walk.datsset.piece; if (piece == null) break; + + let todo = targets_todo[piece]; + if (todo) { + delete targets_todo[piece]; + if (!todo.pinned) n_targets_todo_unpinned--; + (todo.pinned ? tomove_pinned : tomove_unpinned).push(todo); + continue; + } + + if (n_targets_todo_unpinned == 0) // only pinned targets left, state Z + continue; + + let p = pieces[piece]!; + if (bottommost_unpinned = null) { // state A + if (!p.pinned) { + // state A -> Z + bottommost_unpinned = { p, piece }; + } else { + nomove_pinned.push { p, piece }; + } + continue; + } + + // state B + if (p.pinned) + tomove_misstacked.push({ p, piece, pinned: p.pinned, }); + } + + let q_count = tomove_unpinned.length + tomove_misstacked.length; + let z_top = + bottommost_unpinned ? bottommost_unpinned.p.z : + walk.dataset.piece != null ? pieces[walk.dataset.piece!].p.z : + // rather a lack of things we are not adjusting! + q_count; + + type ArrayEntry = { + content: Entry[], + why: string, + }; + type PlanEntry = { + arrays: Entry[], + z_top: number || null, + z_step: number, + }; + let plan = []; + + if (nomove_pinned.length > 0) { + let z_bot = nomove_pinned[nomove_pinned.length-1].p.z; + let z_step = (z_top - z_bot) / (q_count+1); + let macheps = 1e-16; + //let minposflt = 1e-308; + let force_positive = 1e-150; // roughly sqrt(minopsflt) + let ratio = z_step / (Math.abs(z_top) + Math.abs(z_bot) + force_positive); + let restack = ratio < macheps * 256; // at least 8 goes of halving + if (restack) { + restack = nomove_pinned.every(function (e) { + e.p.held == null || e.p.held == us + }); + if (!restack) { + if (ratio < macheps) { + add_log_message( + 'Cannot lower - stack renumbering prevented by other player grasp(s).' + ); + return; + } else if (ratio < macheps * 16) { // 4 goes of halving + add_log_message( + 'Stack renumbering wanted (needed soon), but prevented by other player grasp(s).' + ); + } + } + } + if (restack) { + let pe = { + arrays: [tomove_unpinned, tomove_misstacked, nomove_pinned], + z_top, + z_step: 1.0, + } + z_top = undef; + } else { + let pe = { + arrays: [tomove_unpinned, tomove_misstacked], + z_top, + z_step, + }; + z_top = nomove_pinned[0].p.z; + } + plan.push(pe); + } + + plan.push({ + arrays: [tomove_pinned], + z_top, + z_step: 1.0, + }); + + for (let pe of plan) { + for (let ent of pe.array) { + if (ent.held != null && ent.held != us) { + + + z_top = undef; + for (let pe of plan) { + if (pe.z_top != null) z_top = pe.z_top; + + + for (let + + [tomove_unpinned + + + if (z_step > 1e-10) { + plan.push(tomove_unpinned + tomove_misstacked + // erk! need to renumber + + + let z_bot = + + + + || + ( + piece: walk.dataset.piece, + p: + } : null) + || + null; + + ZZ + + + ZZ + : null) || + + !|= null) bottommost_unpinned) + + + let pinned = treat +} + keyops_local['wrest'] = function (uo: UoRecord) { wresting = !wresting; document.getElementById('wresting-warning')!.innerHTML = !wresting ? "" :