Add Gematria mode 10 (v1.3.0)

Port gematria logic from gematria.py: Hebrew/Arabic/English letter
values with --lang flag (hebrew|arabic|english|all). Added to both
bin/zitsbit and distributed zitsbit.js. Version bumped to 1.3.0.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
This commit is contained in:
z8tek
2026-07-16 15:20:10 +04:00
co-authored by CommandCodeBot
commit f1c2cc2a24
3 changed files with 495 additions and 0 deletions
Executable
+450
View File
@@ -0,0 +1,450 @@
#!/usr/bin/env node
// ── Zitsbit mapping (conditional on next digit) ───────────────────
const ZITSBIT_MAP = {
'1': nd => nd > 5 ? '7' : '4',
'2': () => '5', '3': () => '8',
'4': nd => nd > 5 ? '7' : '1',
'5': () => '2', '6': () => '9',
'7': nd => nd > 5 ? '1' : '4',
'8': () => '3', '9': () => '6',
'0': () => '0',
};
// ── Static mirror (no conditional) ───────────────────────────────
function mirrorDigit(d) {
const map = { '0':'0','1':'1','2':'5','3':'Ɛ','4':'4','5':'2','6':'9','7':'7','8':'8','9':'6' };
return map[d] || d;
}
function mirrorString(s) {
return s.split('').map(c => mirrorDigit(c)).reverse().join('');
}
// ── Glyph mapping (symbolic digit glyphs) ───────────────────────
const GLYPH_MAP = { '0':'Ø','1':'','2':'Ƨ','3':'Ɛ','4':'ᔭ','5':'Ƽ','6':'9','7':'ᒣ','8':'∞','9':'6' };
function applyGlyphs(s) {
return [...s].map(c => GLYPH_MAP[c] || c).join('');
}
// ── Zero rules (pair-based, matches z8tek.net) ───────────────────
function applyZeroTail(digits) {
if (digits.length < 2 || digits[digits.length-1] !== '0') return digits;
const pair = parseInt(digits[digits.length-2] + digits[digits.length-1], 10);
const result = (pair - 1).toString().padStart(2, '0');
const d = [...digits];
d[d.length-2] = result[0];
d[d.length-1] = result[1];
return d;
}
function applyZeroMiddle(digits) {
let result = [...digits];
let i = 0;
while (i < result.length) {
if (result[i] === '0' && i > 0) {
const pair = parseInt(result[i-1] + result[i], 10);
const pairStr = (pair - 1).toString().padStart(2, '0');
const swapped = pairStr[1] + pairStr[0];
result[i-1] = swapped[0];
result[i] = swapped[1];
result[i-1] = '';
result = result.filter(x => x !== '');
}
i++;
}
return result;
}
function processZeros(str) {
let digits = [...str];
digits = applyZeroTail(digits);
digits = applyZeroMiddle(digits);
return digits.join('');
}
// ── Zitsbit transform (passes letters through, maps digits) ─────
function zitsbitTransform(s) {
const chars = [...s];
// Find next digit for each position
const nextDigit = (i) => {
for (let j = i + 1; j < chars.length; j++) {
if (/\d/.test(chars[j])) return parseInt(chars[j], 10);
}
return 0;
};
return chars.map((c, i) => {
if (!/\d/.test(c)) return c;
if (c === '0') return '0';
return ZITSBIT_MAP[c](nextDigit(i));
}).join('');
}
// ── Solar cycle (digit phase mapping) ────────────────────────────
function solarCycle(input) {
const steps = [`Input: ${input}`];
const digits = [...input].filter(c => /\d/.test(c)).map(Number);
const phases = [];
for (const d of digits) {
const deg = (d / 9) * 202.5;
let label;
if (deg < 90) label = 'Growth (0-90°)';
else if (deg < 180) label = 'Mirror (90-180°)';
else if (deg < 270) label = 'Infinity (180-270°)';
else label = 'Unity/Return (270-360°)';
phases.push({ digit: d, degrees: deg.toFixed(1), phase: label });
steps.push(` ${d}${deg.toFixed(1)}° → ${label}`);
}
return { result: digits.map(d => ((d/9)*202.5).toFixed(0) + '°').join(' '), steps, phases };
}
// ── Retrograde (each digit -1) ───────────────────────────────────
function retrograde(input) {
const steps = [`Input: ${input}`];
const result = [...input].map(c => {
if (/\d/.test(c)) {
const r = (parseInt(c, 10) - 1 + 10) % 10;
steps.push(` ${c}${r}`);
return String(r);
}
if (/[a-z]/.test(c)) {
const r = String.fromCharCode(((c.charCodeAt(0) - 97 - 1 + 26) % 26) + 97);
steps.push(` ${c}${r}`);
return r;
}
if (/[A-Z]/.test(c)) {
const r = String.fromCharCode(((c.charCodeAt(0) - 65 - 1 + 26) % 26) + 65);
steps.push(` ${c}${r}`);
return r;
}
return c;
}).join('');
return { result, steps };
}
// ── Block Cycle (rotate-left N → static map → detect cycle) ─────
const BLOCK_MAP = { '0':'3','1':'3','2':'4','3':'2','4':'1','5':'5','6':'6','7':'7','8':'3','9':'6' };
function blockCycle(input, shift = 3, alignTo) {
const steps = [`Input: ${input}`, '', ' Step Value'];
const sep = ' ──── ─────────';
steps.push(sep);
const seen = {};
let state = String(input);
const block = [];
let iter = 1;
while (iter <= 21) {
if (state in seen) {
const first = seen[state];
const cycle = block.slice(first);
steps.push(` It${String(iter).padEnd(4)} ${state} ← cycle`);
steps.push('');
steps.push(` ✓ Cycle ${cycle.length} (starts at step ${first+1}):`);
steps.push(` ${cycle.join(' → ')}`);
return { result: cycle.join(' → '), steps, iterations: iter, cycleLen: cycle.length };
}
seen[state] = block.length;
block.push(state);
steps.push(` It${String(iter).padEnd(4)} ${state}`);
let rotated;
if (alignTo && iter === 1) {
const idx = state.indexOf(alignTo);
if (idx > 0) {
rotated = state[idx] + state[idx-1] + state.slice(0, idx-1) + state.slice(idx+1);
} else if (idx === 0) {
rotated = state;
} else {
rotated = state;
}
} else {
rotated = state.slice(shift) + state.slice(0, shift);
}
state = [...rotated].map(c => BLOCK_MAP[c] || c).join('');
iter++;
}
return { result: state, steps, iterations: iter-1 };
}
// ── Scenarios ────────────────────────────────────────────────────
function scenario1(input, maxIter = 21) {
const parts = input.split('.');
let left = parts[0], right = parts[1] || '';
const seen = { [input]: 0 }, steps = []; steps.push(`Input: ${input}`, '', ' Step Value');
const sep = ' ──── ─────────';
steps.push(sep);
let iter = 1;
let usedFallback = false;
while (iter <= maxIter) {
const revL = [...left].reverse().join(''),
revR = right ? [...right].reverse().join('') : '';
let out = zitsbitTransform(revL) + (right ? '.'+zitsbitTransform(revR) : '');
// Fallback once: if rev→zb is seen, try zb-direct to break out of 2-cycle
if ((out in seen) && !usedFallback) {
const direct = zitsbitTransform(left) + (right ? '.'+zitsbitTransform(right) : '');
if (!(direct in seen)) {
out = direct;
usedFallback = true;
}
}
steps.push(` It${String(iter).padEnd(4)} ${out}`);
if (out in seen) {
const cycleStart = seen[out];
const cycleLen = iter - cycleStart;
steps.push('');
steps.push(` ✓ Cycle ${cycleLen} (starts at step ${cycleStart+1}): ${out}`);
return { result: out, steps, iterations: iter, cycleStart, cycleLen };
}
seen[out] = iter;
left = out.split('.')[0]; right = out.includes('.') ? out.split('.')[1] : '';
iter++;
}
return { result: left + (right ? '.'+right : ''), steps, iterations: iter-1 };
}
function scenario2(input, maxIter = 20) {
const parts = input.split('.');
let left = parts[0], right = parts[1] || '';
const seen = [], steps = []; steps.push(`Input: ${input}`);
let iter = 1;
while (iter <= maxIter) {
const mirL = mirrorString(left),
mirR = right ? mirrorString(right) : '';
const zbL = zitsbitTransform(mirL),
zbR = right ? zitsbitTransform(mirR) : '';
const revL = [...zbL].reverse().join(''),
revR = right ? [...zbR].reverse().join('') : '';
const out = revL + (right ? '.'+revR : '');
steps.push(` It${iter}: mirror(${mirL}${right ? '/'+mirR : ''}) → zitsbit(${zbL}${right ? '/'+zbR : ''}) → reverse(${out})`);
if (seen.slice(-2).includes(out)) {
steps.push(` ✓ Stable/2-cycle at iteration ${iter}: ${out}`);
return { result: out, steps, iterations: iter };
}
seen.push(out);
left = out.split('.')[0];
right = out.includes('.') ? out.split('.')[1] : '';
iter++;
}
return { result: left + (right ? '.'+right : ''), steps, iterations: iter-1 };
}
function scenario3(input, _offset = 0) {
return solarCycle(input);
}
function scenario6(input) {
return retrograde(input);
}
function scenario7(input) {
const steps = [`Input: ${input}`];
const mir = mirrorString(input);
steps.push(`Mirror: ${mir}`);
return { result: mir, steps };
}
function scenario8(input) {
const steps = [`Input: ${input}`];
const rev = [...input].reverse().join('');
steps.push(`Reversed: ${rev}`);
const mir = mirrorString(rev);
steps.push(`Mirror: ${mir}`);
return { result: mir, steps };
}
function scenario9(input) {
const steps = [`Input: ${input}`];
const mir = mirrorString(input);
steps.push(`Mirror: ${mir}`);
const rev = [...mir].reverse().join('');
steps.push(`Reversed: ${rev}`);
return { result: rev, steps };
}
// ── Rotation digit mapping (perspective number rule) ────────────
// After orbit rotation, digits may need remapping based on their
// rotated readability. Same conditional pattern as zitsbit map.
const ROTATION_MAP = {
'0': () => '0',
'1': nd => nd > 5 ? '7' : '1',
'2': nd => nd > 5 ? '5' : '2',
'3': nd => nd > 5 ? '8' : '3',
'4': () => '4',
'5': nd => nd > 5 ? '2' : '5',
'6': () => '9',
'7': nd => nd > 5 ? '1' : '7',
'8': nd => nd > 5 ? '3' : '8',
'9': () => '6',
};
function applyRotationMap(str) {
const digits = [...str].filter(c => /\d/.test(c));
return digits.map((d, i) => {
const nd = i + 1 < digits.length ? parseInt(digits[i+1], 10) : 0;
return ROTATION_MAP[d](nd);
}).join('');
}
// ── Orbit rotation (position shift only) ─────────────────────────
// Then applies rotation digit mapping.
function orbitTransform(str, angle) {
if (!angle) return null; // no perspective, skip
const steps = (angle / 90) % str.length;
if (!steps) return str;
const out = new Array(str.length);
[...str].forEach((c, i) => { out[(i + steps) % str.length] = c; });
const shifted = out.join('');
return applyRotationMap(shifted);
}
// ── Reverse helper ───────────────────────────────────────────────
function reverse(s) { return [...s].reverse().join(''); }
// ── Gematria (letter → numeric value, multi-language) ──────────
const GEMATRIA_MAPS = {
hebrew: {
'א':1,'ב':2,'ג':3,'ד':4,'ה':5,'ו':6,'ז':7,'ח':8,'ט':9,
'י':10,'כ':20,'ך':20,'ל':30,'מ':40,'ם':40,'נ':50,'ן':50,
'ס':60,'ע':70,'פ':80,'ף':80,'צ':90,'ץ':90,'ק':100,'ר':200,
'ש':300,'ת':400,
},
arabic: {
'ا':1,'أ':1,'إ':1,'آ':1,'ب':2,'ج':3,'د':4,'ه':5,'ة':5,
'و':6,'ز':7,'ح':8,'ط':9,'ي':10,'ى':10,'ك':20,'ل':30,
'م':40,'ن':50,'س':60,'ع':70,'ف':80,'ص':90,'ق':100,
'ر':200,'ش':300,'ت':400,'ث':500,'خ':600,'ذ':700,'ض':800,
'ظ':900,'غ':1000,
},
english: (() => { const m = {}; const A = 'A'.charCodeAt(0); for (let i = 0; i < 26; i++) m[String.fromCharCode(A + i)] = i + 1; return m; })(),
};
function gematria(input, lang = 'all') {
const steps = [`Input: ${input}`, `Language: ${lang}`];
const langs = lang === 'all' ? Object.keys(GEMATRIA_MAPS) : [lang];
const results = {};
for (const L of langs) {
const map = GEMATRIA_MAPS[L];
let total = 0;
const breakdown = [];
for (const ch of [...input]) {
const uc = ch.toUpperCase();
const v = map[ch] ?? map[uc] ?? 0;
if (v) { breakdown.push(`${ch}=${v}`); total += v; }
}
results[L] = total;
steps.push(` ${L.toUpperCase()}: ${total}`);
if (breakdown.length) steps.push(` ${breakdown.join(' + ')}`);
else steps.push(` none`);
}
const summary = Object.entries(results).map(([k, v]) => `${k}:${v}`).join(' ');
return { result: summary, steps, totals: results };
}
// ── Transform dispatcher ─────────────────────────────────────────
function splitDecimal(s) {
const i = s.indexOf('.');
if (i === -1) return [s, null];
return [s.slice(0, i), s.slice(i+1)];
}
function joinDecimal(left, right) {
return right !== null ? left + '.' + right : left;
}
function preprocess(input) {
// Always apply zero + decimal rules before the mode transform
const [left, right] = splitDecimal(input);
const zL = processZeros(left);
const zR = right !== null ? processZeros(right) : null;
return joinDecimal(zL, zR);
}
function transform(input, mode, align, lang = 'all') {
input = preprocess(input);
switch (mode) {
case 1: return scenario1(input);
case 2: { const r = zitsbitTransform(input); return { result: r, steps: [`Input: ${input}`, `Zitsbit: ${r}`] }; }
case 3: return scenario3(input);
case 5: { const r = blockCycle(input, 3, align); return r; }
case 6: return scenario6(input);
case 7: return scenario7(input);
case 8: return scenario8(input);
case 9: return scenario9(input);
case 10: return gematria(input, lang);
default: return scenario1(input);
}
}
// ── CLI ──────────────────────────────────────────────────────────
const VERSION = '1.3.0';
const args = process.argv.slice(2);
if (args.includes('--version') || args.includes('-v')) {
console.log(`zitsbit v${VERSION}`); process.exit(0);
}
if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
console.log(`Usage: zitsbit [-m <n>] [-a <char>] [--glyph] [--perspective <angle>] <value>
Flags:
-m, --mode <n> Scenario mode (default: 1)
-a, --align <char> Align block cycle to start with this character (mode 5)
-g, --glyph Convert digits to symbolic glyphs
-p, --perspective <deg> Orbit rotation angle (0|90|180|270)
-l, --lang <lang> Gematria language: hebrew|arabic|english|all (mode 10)
-v, --version Show version
-h, --help Show help
Modes:
1 Reverse Cycle (rev → zitsbit, iterative with fallback) (default)
2 Direct Rule (zitsbit only, no reverse)
3 Solar Cycle (digit phase mapping)
5 Block Cycle (rotate-left 3 → static map → cycle detect)
6 Retrograde only (each digit -1)
7 Normal Mirror (reverse + static glyph map)
9 Mirror then Reverse (static glyph → reverse)
10 Gematria (letter → numeric value, hebrew/arabic/english)
Zero & decimal rules applied automatically.`);
process.exit(0);
}
let mode = 1, perspective = 0, glyph = false, align = '', lang = 'all', value;
const modeIdx = args.indexOf('--mode');
const modeShort = args.indexOf('-m');
const modeFinal = modeIdx !== -1 ? modeIdx : modeShort;
if (modeFinal !== -1 && modeFinal+1 < args.length) {
mode = parseInt(args[modeFinal+1], 10); args.splice(modeFinal, 2);
}
const glyphIdx = args.indexOf('--glyph');
if (glyphIdx !== -1) { glyph = true; args.splice(glyphIdx, 1); }
const gIdx = args.indexOf('-g');
if (gIdx !== -1) { glyph = true; args.splice(gIdx, 1); }
const alignIdx = args.indexOf('--align');
if (alignIdx !== -1 && alignIdx+1 < args.length) { align = args[alignIdx+1]; args.splice(alignIdx, 2); }
const aIdx = args.indexOf('-a');
if (aIdx !== -1 && aIdx+1 < args.length) { align = args[aIdx+1]; args.splice(aIdx, 2); }
const langIdx = args.indexOf('--lang');
const lIdx = args.indexOf('-l');
const li = langIdx !== -1 ? langIdx : lIdx;
if (li !== -1 && li+1 < args.length) { lang = args[li+1]; args.splice(li, 2); }
const perspIdx = args.indexOf('--perspective');
const pIdx = args.indexOf('-p');
const pi = perspIdx !== -1 ? perspIdx : pIdx;
if (pi !== -1 && pi+1 < args.length) {
perspective = parseInt(args[pi+1], 10); args.splice(pi, 2);
}
value = args.join(' ');
if (!value) { console.error('Error: no value provided.'); process.exit(1); }
// Perspective pre-processes, then mode runs on the rotated result
const orb = orbitTransform(value, perspective);
const input = orb !== null ? orb : value;
let output = transform(input, mode, align, lang);
let result = output.result;
if (glyph) result = applyGlyphs(result);
console.log(`\nResult: ${result}\n`);
console.log(output.steps.join('\n'));