1/** 2 * The yarrow-stalk procedure in Zhu Xi's ç®ä»ª, 忬卿æ¬ä¹, å·æ«ä¸. 3 * Source: https://zh.wikisource.org/wiki/忬卿æ¬ç¾©_(ååº«å ¨æ¸æ¬)/å·æ«ä¸ 4 * 5 * This is an explicit mathematical model of the text's remainder classes. 6 * For each change, the four possible LEFT remainders are equally likely. 7 * A second draw chooses uniformly among valid splits in that class. This 8 * produces a real, inspectable split while preserving the text's 3:1 first 9 * change and 1:1 later changes. Uniformly selecting all possible pile sizes 10 * would give slightly different probabilities, so we do not claim to do so. 11 * drawInt(bound) must return an unbiased integer in [0, bound). 12 */ 13 14export const YARROW_MODEL = Object.freeze({ 15 id: 'equiprobable-remainders-v1', 16 description: 'ä¾ãç®ä»ªãçåç§ä½æ°çå¯è½å»ºæ¨¡ï¼åå¨å¯¹åºä½æ°çåæ³åå ä¸çæ¦çéå䏿¬¡ï¼å¹¶éææåå 大å°çæ¦çã', 17 probabilities: Object.freeze({ 6: 1 / 16, 7: 5 / 16, 8: 7 / 16, 9: 3 / 16 }), 18}); 19 20function drawChecked(drawInt, bound) { 21 const value = drawInt(bound); 22 if (!Number.isInteger(value) || value < 0 || value >= bound) { 23 throw new RangeError(`éæºæºå¿ é¡»è¿å 0 è³ ${bound - 1} ä¹é´çæ´æ°ã`); 24 } 25 return value; 26} 27 28// A pile divisible by four leaves FOUR stalks, never zero. 29function remainder(pile) { 30 return ((pile - 1) % 4) + 1; 31} 32 33/** Create one line: three changes starting from 49 stalks. */ 34export function createLine(drawInt) { 35 if (typeof drawInt !== 'function') { 36 throw new TypeError('请æä¾ drawInt(maxExclusive) éæºæ´æ°å½æ°ã'); 37 } 38 let before = 49; 39 const steps = []; 40 41 for (let change = 0; change < 3; change += 1) { 42 const leftRemainder = drawChecked(drawInt, 4) + 1; 43 // Both piles must be nonempty after hanging one from the right. 44 const splitCount = Math.floor((before - 2 - leftRemainder) / 4) + 1; 45 const left = leftRemainder + 4 * drawChecked(drawInt, splitCount); 46 const right = before - left; 47 const hanging = 1; 48 const rightRemainder = remainder(right - hanging); 49 const removed = hanging + leftRemainder + rightRemainder; 50 const remaining = before - removed; 51 52 steps.push({ 53 before, 54 left, 55 right, 56 hanging, 57 leftRemainder, 58 rightRemainder, 59 removed, 60 remaining, 61 }); 62 before = remaining; 63 } 64 65 return { value: before / 4, steps }; 66} 67 68/** Six lines in construction order: bottom (åç») to top (ä¸ç»). */ 69export function createCast(drawInt) { 70 return { lines: Array.from({ length: 6 }, () => createLine(drawInt)) }; 71}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.