From 7dac9b0237717d80cbba70d4caf169bf038da055 Mon Sep 17 00:00:00 2001 From: Willem Date: Mon, 23 Dec 2024 23:36:48 +0100 Subject: [PATCH] Added first version of CDC1604DashP6 for computer numbers and BASIC --- .../main/java/org/x4o/o2o/CDC1604DashP6.java | 270 ++++++++++++++++++ .../java/org/x4o/o2o/CDC1604DashP6Test.java | 100 +++++++ 2 files changed, 370 insertions(+) create mode 100644 nx01-x4o-o2o/src/main/java/org/x4o/o2o/CDC1604DashP6.java create mode 100644 nx01-x4o-o2o/src/test/java/org/x4o/o2o/CDC1604DashP6Test.java diff --git a/nx01-x4o-o2o/src/main/java/org/x4o/o2o/CDC1604DashP6.java b/nx01-x4o-o2o/src/main/java/org/x4o/o2o/CDC1604DashP6.java new file mode 100644 index 0000000..8b70aba --- /dev/null +++ b/nx01-x4o-o2o/src/main/java/org/x4o/o2o/CDC1604DashP6.java @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2004-2014, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.x4o.o2o; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.PrimitiveIterator; + +/** + * CDC1604DashP6 has 27 pie slice number systems and BASIC letters in a six bit encoding. + * + * This is used as the first 64 word numbers of the china four corner method, and acts like ascii glue for adult 18 bit computers. + * + * @author Willem Cazander + * @version 1.0 Dec 22, 2024 + */ +public enum CDC1604DashP6 { + // [NUL][WN][WG][WL] [WS]^?! {[(< }])> + // ~+-* ,.:; '"`′ =#$% + // |_\/ @ABC DEFG HIJK + // LMNO PQRS TUVW XYZ& + + /// NUL for termination. + _NUL('\u0000'), + /// Select packed number encoding. + /// A = 1, first P6 is terminator select, than next P6 _A++ select pie part 1-27, until other P6 stops it. + /// Example ascii "012" is + /// 0 = _WORD_NUMBER _A _A (WN T001 PART_1 = 0) + /// 12 = _WORD_NUMBER _I _A _B (WN T009 PART_1+2 = 1+2) + _WORD_NUMBER('\u0001'), + /// Word glue to flag for automatic casing or separator in renderer. + _WORD_GLUE('\u0002'), + _WORD_LINE('\n'), + _WORD_SPACE(' '), + _CARET('^'), + _QUESTION_MARK('?'), + _EXCLAMATION_MARK('!'), + _CURLY_BRACKET_LEFT('{'), + _SQUARE_BRACKET_LEFT('['), + _ROUND_BRACKET_LEFT('('), + _LESSER_THAN_SIGN('<'), + _CURLY_BRACKET_RIGHT('}'), + _SQUARE_BRACKET_RIGHT(']'), + _ROUND_BRACKET_RIGHT(')'), + _GREATER_THAN_SIGN('>'), + + _TILDE_SIGN('~'), + _PLUS_SIGN('+'), + _MINUS_SIGN('-'), + _ASTERISK('*'), + _COMMA(','), + _FULL_POINT('.'), + _COLON(':'), + _SEMICOLON(';'), + _APOSTROPHE('\''), + _QUOTATION_MARK('\"'), + _BACKTICK_MARK('`'), + _PRIME_SIGN('′'), + _EQUALS_SIGN('='), + _NUMBER_SIGN('#'), + _DOLLAR_SIGN('$'), + _PERCENT_SIGN('%'), + + _VERTICAL_BAR('|'), + _UNDERSCORE('_'), + _BACKSLASH('\\'), + _SLASH('/'), + _AT_SIGN('@'), + _A('A', "Æ æ Å å Ǻ ǻ Ḁ ḁ ẚ Ă ă Ặ ặ Ắ ắ Ằ ằ Ẳ ẳ Ẵ ẵ Ȃ ȃ Â â Ậ ậ Ấ ấ Ầ ầ Ẫ ẫ Ẩ ẩ Ả ả Ǎ ǎ Ⱥ ⱥ Ȧ ȧ Ǡ ǡ Ạ ạ Ä ä Ǟ ǟ À à Ȁ ȁ Á á Ā ā Ā̀ ā̀ Ã ã Ą ą Ą́ ą́ Ą̃ ą̃ A̲ a̲ ᶏ"), + _B('B', "Ƀ ƀ Ḃ ḃ Ḅ ḅ Ḇ ḇ Ɓ ɓ ᵬ ᶀ"), + _C('C', "Ć ć Ĉ ĉ Č č Ċ ċ Ḉ ḉ Ƈ ƈ C̈ c̈ Ȼ ȼ Ç ç Ꞔ ꞔ Ꞓ ꞓ"), + _D('D', "Đ đ Ꟈ ꟈ Ɗ ɗ Ḋ ḋ Ḍ ḍ Ḑ ḑ Ḓ ḓ Ď ď Ḏ ḏ"), + _E('E', "Ĕ ĕ Ḝ ḝ Ȇ ȇ Ê ê Ê̄ ê̄ Ê̌ ê̌ Ề ề Ế ế Ể ể Ễ ễ Ệ ệ Ẻ ẻ Ḙ ḙ Ě ě Ɇ ɇ Ė ė Ė́ ė́ Ė̃ ė̃ Ẹ ẹ Ë ë È è È̩ è̩ Ȅ ȅ É é É̩ Ē ē Ḕ ḕ Ḗ ḗ Ẽ ẽ Ḛ ḛ Ę ę Ę́ ę́ Ę̃ ę̃ Ȩ ȩ E̩ e̩ ᶒ"), + _F('F', "Ƒ ƒ Ḟ ḟ ᵮ ᶂ Ꞙ ꞙ"), + _G('G', "Ǵ ǵ Ǥ ǥ Ĝ ĝ Ǧ ǧ Ğ ğ Ģ ģ Ɠ ɠ Ġ ġ Ḡ ḡ Ꞡ ꞡ ᶃ"), + _H('H', "Ĥ ĥ Ȟ ȟ Ħ ħ Ḩ ḩ Ⱨ ⱨ ẖ ẖ Ḥ ḥ Ḣ ḣ Ḧ ḧ Ḫ ḫ ꞕ Ꜧ ꜧ"), + _I('I', "Ị ị Ĭ ĭ Î î Ǐ ǐ Ɨ ɨ Ï ï Ḯ ḯ Í í Ì ì Ȉ ȉ Į į Į́ Į̃ Ī ī Ī̀ ī̀ ᶖ Ỉ ỉ Ȋ ȋ Ĩ ĩ Ḭ ḭ ᶤ"), + _J('J', "J́ j́ Ĵ ĵ J̌ ǰ Ɉ ɉ J̃ j̇̃"), + _K('K', "Ƙ ƙ Ꝁ ꝁ Ḱ ḱ Ǩ ǩ Ḳ ḳ Ķ ķ ᶄ Ⱪ ⱪ Ḵ ḵ"), + _L('L', "Ĺ ĺ Ł ł Ľ ľ Ḹ ḹ L̃ l̃ Ļ ļ Ŀ ŀ Ḷ ḷ Ḻ ḻ Ḽ ḽ Ƚ ƚ Ⱡ ⱡ"), + + _M('M', "Ḿ ḿ Ṁ ṁ Ṃ ṃ M̃ m̃ ᵯ"), + _N('N', "Ń ń Ñ ñ Ň ň Ǹ ǹ Ṅ ṅ Ṇ ṇ Ņ ņ Ṉ ṉ Ṋ ṋ Ꞥ ꞥ ᵰ ᶇ"), + _O('O', "Ø ø Ǿ ǿ Ö ö Ȫ ȫ Ó ó Ò ò Ô ô Ố ố Ồ ồ Ổ ổ Ỗ ỗ Ộ ộ Ǒ ǒ Ő ő Ŏ ŏ Ȏ ȏ Ȯ ȯ Ȱ ȱ Ọ ọ Ɵ ɵ ᶱ Ơ ơ Ớ ớ Ờ ờ Ỡ ỡ Ợ ợ Ở ở Ỏ ỏ Ō ō Ṓ ṓ Ṑ ṑ Õ õ Ȭ ȭ Ṍ ṍ Ṏ ṏ Ǫ ǫ Ȍ ȍ O̩ o̩ Ó̩ ó̩ Ò̩ ò̩ Ǭ ǭ O͍ o͍"), + _P('P', "Ṕ ṕ Ṗ ṗ Ᵽ ᵽ Ƥ ƥ ᵱ ᶈ"), + _Q('Q', "ʠ Ɋ ɋ q̃"), + _R('R', "Ŕ ŕ Ɍ ɍ Ř ř Ŗ ŗ Ṙ ṙ Ȑ ȑ Ȓ ȓ Ṛ ṛ Ṝ ṝ Ṟ ṟ Ꞧ ꞧ Ɽ ɽ R̃ r̃ ᵲ ꭨ ᵳ ᶉ"), + _S('S', "Ś ś Ṡ ṡ ẛ Ṩ ṩ Ṥ ṥ Ṣ ṣ S̩ s̩ Ꞩ ꞩ Ꟊ ꟊ Ꟍ ꟍ Ŝ ŝ Ṧ ṧ Š š Ş ş Ș ș S̈ s̈ ᶊ Ȿ ȿ ᵴ ᶳ"), + _T('T', "Ť ť Ṫ ṫ ẗ Ţ ţ Ṭ ṭ Ʈ ʈ Ț ț ƫ Ṱ ṱ Ṯ ṯ Ŧ ŧ Ⱦ ⱦ Ƭ ƭ ᵵ ᶵ"), + _U('U', "Ŭ ŭ Ʉ ʉ ᵾ ᶶ Ꞹ ꞹ Ụ ụ Ü ü Ǜ ǜ Ǘ ǘ Ǚ ǚ Ǖ ǖ Ṳ ṳ Ú ú Ù ù Û û Ṷ ṷ Ǔ ǔ Ȗ ȗ Ű ű Ŭ ŭ Ư ư Ứ ứ Ừ ừ Ử ử Ự ự Ữ Ữ Ủ ủ Ū ū Ū̀ ū̀ Ū́ ū́ Ṻ ṻ Ū̃ ū̃ Ũ ũ Ṹ ṹ Ṵ ṵ ᶙ Ų ų Ų́ ų́ Ų̃ ų̃ Ȕ ȕ Ů ů"), + _V('V', "Ṽ ṽ Ṿ ṿ Ʋ ʋ ᶌ"), + _W('W', "Ẃ ẃ Ẁ ẁ Ŵ ŵ Ẅ ẅ Ẇ ẇ Ẉ ẉ ẘ"), + _X('X', "Ẍ ẍ Ẋ ẋ X̂ x̂ ᶍ"), + _Y('Y', "Ý ý Ỳ ỳ Ŷ ŷ Ÿ ÿ Ỹ ỹ Ẏ ẏ Ỵ ỵ ẙ Ỷ ỷ Ȳ ȳ Ɏ ɏ Ƴ ƴ"), + _Z('Z', "Ź ź Ẑ ẑ Ž ž Ż ż Ẓ ẓ Ẕ ẕ Ƶ ƶ ᵶ Ᶎ ᶎ Ⱬ ⱬ"), + /// The 27th letter is at the end of the old english alphabet. + _AMPERSAND('&'), + ; + + private final char codePoint; + private final char codePointLower; + private final String aliases; + + private CDC1604DashP6(char codePoint) { + this(codePoint, null); + } + + private CDC1604DashP6(char codePoint, String aliases) { + this.codePoint = codePoint; + this.codePointLower = Character.toLowerCase(codePoint); + this.aliases = aliases; + } + + public byte cdcByte() { + return (byte) ordinal(); + } + + public byte asciiByte() { + return (byte) codePoint; + } + + public char asciiChar() { + return codePoint; + } + + static public List convertFromUnicode(String text) { + return convertFromUnicode(text, false); + } + + static public List convertFromUnicode(String text, boolean strict) { + PrimitiveIterator.OfInt i = text.codePoints().iterator(); + List result = new ArrayList<>(text.length()); + CDC1604DashP6[] cdcChars = values(); + CDC1604DashP6 cdcNumberTerminator = null; + while (i.hasNext()) { + int codePoint = i.next(); + boolean found = false; + for (CDC1604DashP6 v : cdcChars) { + if (v.codePoint == codePoint) { + result.add(v); + found = true; + cdcNumberTerminator = null; + break; + } + if (v.codePointLower == codePoint) { + result.add(v); + found = true; + cdcNumberTerminator = null; + break; + } + if ('0' == codePoint) { + if (!CDC1604DashP6._A.equals(cdcNumberTerminator)) { + result.add(CDC1604DashP6._WORD_NUMBER); + result.add(CDC1604DashP6._A); + cdcNumberTerminator = CDC1604DashP6._A; + } + result.add(CDC1604DashP6._A); + found = true; + break; + } + if (codePoint >= '1' && codePoint <= '9') { + if (!CDC1604DashP6._I.equals(cdcNumberTerminator)) { + result.add(CDC1604DashP6._WORD_NUMBER); + result.add(CDC1604DashP6._I); + cdcNumberTerminator = CDC1604DashP6._I; + } + int cdcNumberOff = codePoint - '1'; // 0 = 1 + int cdcNumber = CDC1604DashP6._A.ordinal() + cdcNumberOff; + result.add(CDC1604DashP6.values()[cdcNumber]); + found = true; + break; + } + } + if (!found && !strict) { + String codePointStr = Character.toString(codePoint); + for (CDC1604DashP6 v : cdcChars) { + if (v.aliases == null) { + continue; + } + if (v.aliases.contains(codePointStr)) { + result.add(v); + found = true; + cdcNumberTerminator = null; + break; + } + } + } + if (!found) { + throw new IllegalArgumentException("Unsupported char: '" + ((char)codePoint) + "' 0x" + Integer.toHexString(codePoint)); + } + } + return result; + } + + static public String convertToUnicode(List cdcChars) { + StringBuilder buf = new StringBuilder(); + Iterator cdc = cdcChars.iterator(); + CDC1604DashP6 numberMode = null; + while (cdc.hasNext()) { + CDC1604DashP6 cdcPoint = cdc.next(); + if (_WORD_GLUE.equals(cdcPoint)) { + continue; + } + if (_WORD_NUMBER.equals(cdcPoint)) { + if (!cdc.hasNext()) { + break; + } + numberMode = cdc.next(); + continue; + } + + if (numberMode != null) { + if (cdcPoint.ordinal() < CDC1604DashP6._A.ordinal()) { + numberMode = null; + } + } + if (numberMode == null) { + buf.appendCodePoint(cdcPoint.asciiByte()); + } else { + int terminatorNum = numberMode.ordinal() - CDC1604DashP6._A.ordinal() + 1; + int valueNumber = cdcPoint.ordinal() - CDC1604DashP6._A.ordinal(); + appendTerminatorNumber(buf, terminatorNum, valueNumber); + } + } + return buf.toString(); + } + + static private void appendTerminatorNumber(StringBuilder buf, int terminator, int value) { + switch (terminator) { + case 1: + buf.appendCodePoint('0'); // T001 is zero for all 27 gematria number systems. + return; + case 2: + if (value == 0) { + buf.append("true"); // FIXME: T002ᖟGunPunchedHoles would be better, as it supports two-way conversion + } else { + buf.append("false"); + } + return; + //case 3: + // return; // TODO: after nether DB, generate add all terminator up to 27 from "number system" gun bullets. + case 9: + buf.appendCodePoint(('1' + value)); // 0 = 1 + return; // NOTE: Latin decimals are not decimals as zero is not a part of the pie. + default: + throw new IllegalArgumentException("Unsupported terminator index: " + terminator); + } + } +} diff --git a/nx01-x4o-o2o/src/test/java/org/x4o/o2o/CDC1604DashP6Test.java b/nx01-x4o-o2o/src/test/java/org/x4o/o2o/CDC1604DashP6Test.java new file mode 100644 index 0000000..ddbc8e5 --- /dev/null +++ b/nx01-x4o-o2o/src/test/java/org/x4o/o2o/CDC1604DashP6Test.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2004-2014, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.x4o.o2o; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * Tests CDC1604DashP6 encoding. + * + * @author Willem Cazander + * @version 1.0 Dec 23, 2024 + */ +public class CDC1604DashP6Test { + + @Test + public void testValues() throws Exception { + Assertions.assertEquals(64, CDC1604DashP6.values().length); + boolean duplicate = false; + Map global = new HashMap<>(); + for (CDC1604DashP6 v : CDC1604DashP6.values()) { + Assertions.assertNotNull(v); + if (global.containsKey(v.asciiByte())) { + duplicate = true; + break; + } + global.put(v.asciiByte(), v); + } + Assertions.assertTrue(global.size() > 1); + Assertions.assertFalse(duplicate, "Duplicate ascii core value detected"); + } + + @Test + public void testAsciiSimple() throws Exception { + List cdc = CDC1604DashP6.convertFromUnicode("foobar"); + Assertions.assertNotNull(cdc); + Assertions.assertFalse(cdc.isEmpty()); + Assertions.assertEquals(6, cdc.size()); + Assertions.assertEquals(CDC1604DashP6._F, cdc.get(0)); + Assertions.assertEquals(CDC1604DashP6._O, cdc.get(1)); + Assertions.assertEquals(CDC1604DashP6._O, cdc.get(2)); + Assertions.assertEquals(CDC1604DashP6._B, cdc.get(3)); + Assertions.assertEquals(CDC1604DashP6._A, cdc.get(4)); + Assertions.assertEquals(CDC1604DashP6._R, cdc.get(5)); + + String out = CDC1604DashP6.convertToUnicode(cdc); + Assertions.assertEquals("FOOBAR", out); + } + + @Test + public void testNumber012() throws Exception { + List cdc = CDC1604DashP6.convertFromUnicode("01201337"); + Assertions.assertNotNull(cdc); + Assertions.assertFalse(cdc.isEmpty()); + Assertions.assertEquals(16, cdc.size()); + Assertions.assertEquals(CDC1604DashP6._WORD_NUMBER, cdc.get(0)); + Assertions.assertEquals(CDC1604DashP6._A, cdc.get(1)); + Assertions.assertEquals(CDC1604DashP6._A, cdc.get(2)); // 0 + Assertions.assertEquals(CDC1604DashP6._WORD_NUMBER, cdc.get(3)); + Assertions.assertEquals(CDC1604DashP6._I, cdc.get(4)); + Assertions.assertEquals(CDC1604DashP6._A, cdc.get(5)); // 1 + Assertions.assertEquals(CDC1604DashP6._B, cdc.get(6)); // 2 + Assertions.assertEquals(CDC1604DashP6._WORD_NUMBER, cdc.get(7)); + Assertions.assertEquals(CDC1604DashP6._A, cdc.get(8)); + Assertions.assertEquals(CDC1604DashP6._A, cdc.get(9)); // 0 + Assertions.assertEquals(CDC1604DashP6._WORD_NUMBER, cdc.get(10)); + Assertions.assertEquals(CDC1604DashP6._I, cdc.get(11)); + Assertions.assertEquals(CDC1604DashP6._A, cdc.get(12)); // 1 + Assertions.assertEquals(CDC1604DashP6._C, cdc.get(13)); // 3 + Assertions.assertEquals(CDC1604DashP6._C, cdc.get(14)); // 3 + Assertions.assertEquals(CDC1604DashP6._G, cdc.get(15)); // 7 + + String out = CDC1604DashP6.convertToUnicode(cdc); + Assertions.assertEquals("01201337", out); + } +}