diff options
| -rw-r--r-- | spelling-generator.py | 487 |
1 files changed, 487 insertions, 0 deletions
diff --git a/spelling-generator.py b/spelling-generator.py new file mode 100644 index 0000000..be8c801 --- /dev/null +++ b/spelling-generator.py @@ -0,0 +1,487 @@ +from flask import Flask, request, render_template_string, jsonify +import re + +app = Flask(__name__) + +# taken from https://github.com/ilovecats4606/fx-82AU-PLUS-II-2nd/blob/main/tokentranslator.py (thanks ilovecats4606!) +TOKEN_MAP = { + 0x00: 'null', + 0x01: 'mᴘ', + 0x02: 'mn', + 0x03: 'me', + 0x04: 'm𝜇', + 0x05: 'ao', + 0x06: 'h', + 0x07: '𝜇ɴ', + 0x08: '𝜇ʙ', + 0x09: 'ħ', + 0x0A: 'α', + 0x0B: 're', + 0x0C: '𝜆c', + 0x0D: 'γᴘ', + 0x0E: 'γcp', + 0x0F: '𝜆cn', + 0x10: 'Σx²', + 0x11: 'Σx', + 0x12: 'n', + 0x13: 'Σy²', + 0x14: 'Σy', + 0x15: 'Σxy', + 0x16: 'Σy³', + 0x17: '∑x²y', + 0x18: '∑x⁴', + 0x19: 'minX', + 0x1A: 'maxX', + 0x1B: 'minY', + 0x1C: 'maxY', + 0x1D: 'R∞', + 0x1E: 'u', + 0x1F: '𝜇ᴘ', + 0x20: 'AtWt ', + 0x21: '▯', + 0x22: '𝜇e', + 0x23: '𝜇n', + 0x24: '𝜇𝜇', +0x25: '%', + 0x26: 'F', + 0x27: 'e', + 0x28: '(', + 0x29: ')', + 0x2A: 'Nᴀ', + 0x2B: '+', + 0x2C: ',', + 0x2D: '-', + 0x2E: '.', + 0x2F: '.+1', + 0x30: '0', + 0x31: '1', + 0x32: '2', + 0x33: '3', + 0x34: '4', + 0x35: '5', + 0x36: '6', + 0x37: '7', + 0x38: '8', + 0x39: '9', + 0x3A: ':', + 0x3B: 'k', + 0x3C: '<', + 0x3D: '=', + 0x3E: '>', + 0x3F: 'RndFix(', + 0x40: 'Vm', + 0x41: 'A', + 0x42: 'B', + 0x43: 'C', + 0x44: 'D', + 0x45: 'E', + 0x46: 'F', + 0x47: '->A', + 0x48: '->B', + 0x49: '->C', + 0x4A: '->D', + 0x4B: '->E', + 0x4C: '->F', + 0x4D: '->Y', + 0x4E: '×', + 0x4F: '÷', + 0x50: 'h', + 0x51: 'c', + 0x52: 'o', + 0x53: 'b', + 0x54: 'M', + 0x55: '▶a+b𝐢', + 0x56: '▶r∠𝜃', + 0x57: '!', + 0x58: 'X', + 0x59: 'Y', + 0x5A: 'Ref(', + 0x5B: 'Rref(', + 0x5C: '▫', + 0x5D: 'π(', + 0x5E: '^( ', + 0x5F: '÷R', + 0x60: '(-)', + 0x61: 'Not(', + 0x62: 'Neg(', + 0x63: 'Abs(', + 0x64: 'x̂₁', + 0x65: 'x̂', + 0x66: 'ŷ', + 0x67: 'x̂₂', + 0x68: 'log(', + 0x69: 'Σ(', + 0x6A: '∫(', + 0x6B: 'd/dx(', + 0x6C: 'Pol(', + 0x6D: 'Rec(', + 0x6E: 'and', + 0x6F: 'or', + 0x70: 'sinh(', + 0x71: 'cosh(', + 0x72: 'tanh(', + 0x73: '𝒆^(', + 0x74: 'x10', + 0x75: '^2', + 0x76: '^3', + 0x77: '^-1', + 0x78: 'R', + 0x79: 'c₀', + 0x7A: 'c₁', + 0x7B: 'Int(', + 0x7C: '@', + 0x7D: 'Intg(', + 0x7E: 'xor', + 0x7F: 'xnor', + 0x80: '𝐢', + 0x81: '𝒆', + 0x82: 'π', + 0x83: '->E', + 0x84: '->F', + 0x85: '°', + 0x86: 'ʳ', + 0x87: 'ᵍ', + 0x88: 'Conjg(', + 0x89: 'x̄', + 0x8A: 'ȳ', + 0x8B: 'Ans', + 0x8C: 'Ran#', + 0x8D: 'Q1', + 0x8E: 'Q3', + 0x8F: 'med', + 0x90: 'sinh⁻¹(', + 0x91: 'cosh⁻¹(', + 0x92: 'tanh⁻¹(', + 0x93: '10^(', + 0x94: '≤', + 0x95: '≠', + 0x96: '≥', + 0x97: '▶Simp ', + 0x98: '√(', + 0x99: 'M+', + 0x9A: 'ᴀ', + 0x9B: 'ʙ', + 0x9C: 'ᴄ', + 0x9D: 'r', + 0x9E: '⋅', + 0x9F: 'ˣ√(', + 0xA0: 'sin(', + 0xA1: 'cos(', + 0xA2: 'tan(', + 0xA3: 'ln(', + 0xA4: '(', + 0xA5: '▶Conv ', + 0xA6: 'GCD(', + 0xA7: 'LCM(', + 0xA8: '³√(', + 0xA9: 'M-', + 0xAA: '𝜎x', + 0xAB: 'sx', + 0xAC: '𝜎y', + 0xAD: 'sy', + 0xAE: '⌟', + 0xAF: '∠', + 0xB0: 'sin⁻¹(', + 0xB1: 'cos⁻¹(', + 0xB2: 'tan⁻¹(', + 0xB3: 'Rnd(', + 0xB4: 'c₂', + 0xB5: '𝜎', + 0xB6: '𝜀₀', + 0xB7: '𝜇₀', + 0xB8: '𝗔', + 0xB9: '𝗕', + 0xBA: '𝗖', + 0xBB: '𝗗', + 0xBC: '𝗘', + 0xBD: '𝗙', + 0xBE: '𝗣', + 0xBF: '𝗖', + 0xC0: 'det(', + 0xC1: 'Trn(', + 0xC2: 'RanInt#(', + 0xC3: 'arg(', + 0xC4: '𝜙₀', + 0xC5: 'g', + 0xC6: 'G₀', + 0xC7: 'Z₀', + 0xC8: 'MatA', + 0xC9: 'MatB', + 0xCA: 'MatC', + 0xCB: 'MatAns', + 0xCC: 'VctA', + 0xCD: 'VctB', + 0xCE: 'VctC', + 0xCF: 'VctAns', + 0xD0: 'P(', + 0xD1: 'Q(', + 0xD2: 'R(', + 0xD3: '▶t', + 0xD4: 't', + 0xD5: 'G', + 0xD6: 'atm', + 0xD7: 'in▶cm', + 0xD8: 'cm▶in', + 0xD9: 'ft▶m', + 0xDA: 'm▶ft', + 0xDB: 'yd▶m', + 0xDC: 'm▶yd', + 0xDD: 'mile▶km', + 0xDE: 'km▶mile', + 0xDF: 'n mile▶m', + 0xE0: 'm▶n mile', + 0xE1: 'acre▶m²', + 0xE2: 'm²▶acre', + 0xE3: 'gal(US)▶ℓ', + 0xE4: 'ℓ▶gal(US)', + 0xE5: 'gal(UK)▶ℓ', + 0xE6: 'ℓ▶gal(UK)', + 0xE7: 'pc▶km', + 0xE8: 'km▶pc', + 0xE9: 'km/h▶m/s', + 0xEA: 'm/s▶km/h', + 0xEB: 'oz▶g', + 0xEC: 'g▶oz', + 0xED: 'lb▶kg', + 0xEE: 'kg▶lb', + 0xEF: 'atm▶Pa', + 0xF0: 'Pa▶atm', + 0xF1: 'mmHg▶Pa', + 0xF2: 'Pa▶mmHg', + 0xF3: 'hp▶kW', + 0xF4: 'kW▶hp', + 0xF5: 'kgf/cm²▶Pa', + 0xF6: 'Pa▶kgf/cm²', + 0xF7: 'kgf⋅m▶J', + 0xF8: 'J▶kgf⋅m', + 0xF9: 'lbf/in²▶kPa', + 0xFA: 'kPa▶lbf/in²', + 0xFB: '°F▶°C', + 0xFC: '°C▶°F', + 0xFD: 'J▶cal', + 0xFE: 'cal▶J', + 0xFF: '@', +} + +_unstable_ranges = [ + (0x00, 0x24), + (0x26, 0x2A), + (0x2F, 0x2F), + (0x3A, 0x3E), + (0x40, 0x40), + (0x47, 0x4D), + (0x50, 0x53), + (0x55, 0x56), + (0x5A, 0x5B), + (0x5D, 0x5F), + (0x61, 0x67), + (0x69, 0x6F), + (0x77, 0x80), + (0x83, 0x8A), + (0x8D, 0x8E), + (0x8F, 0x8F), + (0x93, 0x97), + (0x99, 0x9E), + (0xA4, 0xA7), + (0xA9, 0xAF), + (0xB4, 0xC1), + (0xC3, 0xFF), +] +UNSTABLE_SET = set() +for a, b in _unstable_ranges: + for v in range(a, b + 1): + UNSTABLE_SET.add(v) + +LAST_TYPEABLE_TOKEN = None +for val, token in sorted(TOKEN_MAP.items()): + if val not in UNSTABLE_SET and token != '<UNK>': + LAST_TYPEABLE_TOKEN = token + +def translate_hex_bytes(hex_bytes: list[int]): + items = [] + total = 0 + typeable_count = 0 + unstable_count = 0 + unknown_count = 0 + + for val in hex_bytes: + total += 1 + tok = TOKEN_MAP.get(val, '<UNK>') + unstable = val in UNSTABLE_SET + + if unstable: + unstable_count += 1 + else: + if tok != '<UNK>': + typeable_count += 1 + else: + unknown_count += 1 + + items.append({ + 'hex': format(val, '02X'), + 'token': tok, + 'unstable': unstable, + }) + + totals = { + 'total': total, + 'typeable_count': typeable_count, + 'unstable_count': unstable_count, + 'unknown_count': unknown_count + } + + return {'items': items, 'totals': totals} + +def translate_line(line: str): + line_hex = list(line.encode('UTF-8')) + return translate_hex_bytes(line_hex) + +def create_hackstring(text: str): + if len(text) >= 64: + text = text[:64] + else: + text = text.ljust(64) + + __lines = [text[i:i+16] for i in range(0, 64, 16)] + lines = [__lines[2], __lines[3], __lines[0], __lines[1]] + + items = [] + totals = {'total': 0, 'typeable_count': 0, 'unstable_count': 0, 'unknown_count': 0} + + results = translate_line(lines[0]) + items += results['items'] + totals['total'] += results['totals']['total'] + totals['typeable_count'] += results['totals']['typeable_count'] + totals['unstable_count'] += results['totals']['unstable_count'] + totals['unknown_count'] += results['totals']['unknown_count'] + + results = translate_hex_bytes([0x30]) + items += results['items'] + totals['total'] += results['totals']['total'] + totals['typeable_count'] += results['totals']['typeable_count'] + totals['unstable_count'] += results['totals']['unstable_count'] + totals['unknown_count'] += results['totals']['unknown_count'] + + results = translate_line(lines[1]) + items += results['items'] + totals['total'] += results['totals']['total'] + totals['typeable_count'] += results['totals']['typeable_count'] + totals['unstable_count'] += results['totals']['unstable_count'] + totals['unknown_count'] += results['totals']['unknown_count'] + + results = translate_hex_bytes([0x30]) + items += results['items'] + totals['total'] += results['totals']['total'] + totals['typeable_count'] += results['totals']['typeable_count'] + totals['unstable_count'] += results['totals']['unstable_count'] + totals['unknown_count'] += results['totals']['unknown_count'] + + results = translate_line("3636363636") + items += results['items'] + totals['total'] += results['totals']['total'] + totals['typeable_count'] += results['totals']['typeable_count'] + totals['unstable_count'] += results['totals']['unstable_count'] + totals['unknown_count'] += results['totals']['unknown_count'] + + results = translate_hex_bytes([0x3A, 0x31, 0x30, 0x30, 0x96, 0x81, 0x50, 0x30, 0x30, 0x30, 0x30, 0xC2, 0x30, 0x30]) + items += results['items'] + totals['total'] += results['totals']['total'] + totals['typeable_count'] += results['totals']['typeable_count'] + totals['unstable_count'] += results['totals']['unstable_count'] + totals['unknown_count'] += results['totals']['unknown_count'] + + results = translate_line("36363636") + items += results['items'] + totals['total'] += results['totals']['total'] + totals['typeable_count'] += results['totals']['typeable_count'] + totals['unstable_count'] += results['totals']['unstable_count'] + totals['unknown_count'] += results['totals']['unknown_count'] + + results = translate_line(lines[2]) + items += results['items'] + totals['total'] += results['totals']['total'] + totals['typeable_count'] += results['totals']['typeable_count'] + totals['unstable_count'] += results['totals']['unstable_count'] + totals['unknown_count'] += results['totals']['unknown_count'] + + results = translate_hex_bytes([0x30]) + items += results['items'] + totals['total'] += results['totals']['total'] + totals['typeable_count'] += results['totals']['typeable_count'] + totals['unstable_count'] += results['totals']['unstable_count'] + totals['unknown_count'] += results['totals']['unknown_count'] + + results = translate_line(lines[3]) + items += results['items'] + totals['total'] += results['totals']['total'] + totals['typeable_count'] += results['totals']['typeable_count'] + totals['unstable_count'] += results['totals']['unstable_count'] + totals['unknown_count'] += results['totals']['unknown_count'] + + results = translate_hex_bytes([0x30]) + items += results['items'] + totals['total'] += results['totals']['total'] + totals['typeable_count'] += results['totals']['typeable_count'] + totals['unstable_count'] += results['totals']['unstable_count'] + totals['unknown_count'] += results['totals']['unknown_count'] + + return {'items': items, 'totals': totals} + +HTML_TEMPLATE = """ +<!doctype html> +<html> +<head> + <title>fx-82AU Plus II 2nd Spelling Hackstring Generator</title> + <style> + body { font-family: monospace; margin: 40px; background: #0f0f0f; color: #eee; } + input, button { font-size: 16px; padding: 8px; } + textarea { width: 100%; max-width: 800px; height: 300px; font-family: monospace; background: #1e1e1e; color: #0f0; border: 1px solid #333; font-size: 16px; } + .output { margin-top: 20px; } + </style> +</head> +<body> + <h1>fx-82AU Plus II 2nd Spelling Hackstring Generator</h1> + <form method="post"> + <input type="text" name="text" placeholder="Enter text (max 64 chars)" size="40" value="{{ request.form.get('text', '') }}"> + <button type="submit">Generate Hackstring</button> + </form> + {% if result %} + <div class="output"> + <h3>Hackstring (bytes):</h3> + <textarea readonly>{{ result }}</textarea> + <p><strong>Total bytes:</strong> {{ byte_count }}</p> + <p><strong>Typeable characters:</strong> {{ typeable_count }}</p> + <p><strong>Unstable needed:</strong> {{ unstable_count }}</p> + <p><strong>Unknown characters:</strong> {{ unknown_count }}</p> + </div> + {% endif %} +</body> +</html> +""" + [email protected]('/', methods=['GET', 'POST']) +def index(): + result = None + byte_count = 0 + typeable_count = 0 + unstable_count = 0 + unknown_count = 0 + if request.method == 'POST': + input_text = request.form.get('text', '') + if input_text: + hack_data = create_hackstring(input_text) + result = "" + for item in hack_data['items']: + result += f"{item['hex']} | {item['token']}" + if item['unstable']: + result += " (unstable)" + result += "\n" + byte_count = hack_data['totals']['total'] + typeable_count = hack_data['totals']['typeable_count'] + unstable_count = hack_data['totals']['unstable_count'] + unknown_count = hack_data['totals']['unknown_count'] + + return render_template_string(HTML_TEMPLATE, result=result, byte_count=byte_count, typeable_count=typeable_count, unstable_count=unstable_count, unknown_count=unknown_count) + +if __name__ == '__main__': + app.run(debug=True, port=5000) |
