puzzle-lib 1.3.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +38 -39
  3. package/build/src/Braille/BrailleCharacter.d.ts +15 -15
  4. package/build/src/Braille/BrailleCharacter.js +38 -37
  5. package/build/src/Braille/BrailleCharacter.js.map +1 -1
  6. package/build/src/Braille/BrailleData.d.ts +6 -6
  7. package/build/src/Braille/BrailleData.js +65 -64
  8. package/build/src/Braille/BrailleData.js.map +1 -1
  9. package/build/src/Braille/BrailleDot.d.ts +9 -9
  10. package/build/src/Braille/BrailleDot.js +13 -12
  11. package/build/src/Braille/BrailleDot.js.map +1 -1
  12. package/build/src/Braille/BrailleEncoding.d.ts +54 -54
  13. package/build/src/Braille/BrailleEncoding.js +65 -64
  14. package/build/src/Braille/BrailleEncoding.js.map +1 -1
  15. package/build/src/Braille/BrailleStream.d.ts +18 -18
  16. package/build/src/Braille/BrailleStream.js +75 -74
  17. package/build/src/Braille/BrailleStream.js.map +1 -1
  18. package/build/src/Cipher/AutoKeyString.d.ts +4 -4
  19. package/build/src/Cipher/AutoKeyString.js +34 -33
  20. package/build/src/Cipher/AutoKeyString.js.map +1 -1
  21. package/build/src/Cipher/CaesarString.d.ts +8 -8
  22. package/build/src/Cipher/CaesarString.js +31 -30
  23. package/build/src/Cipher/CaesarString.js.map +1 -1
  24. package/build/src/Cipher/CaesarUtils.d.ts +13 -13
  25. package/build/src/Cipher/CaesarUtils.js +57 -56
  26. package/build/src/Cipher/CaesarUtils.js.map +1 -1
  27. package/build/src/Cipher/KeyedCipherStringBase.d.ts +12 -12
  28. package/build/src/Cipher/KeyedCipherStringBase.js +28 -27
  29. package/build/src/Cipher/KeyedCipherStringBase.js.map +1 -1
  30. package/build/src/Cipher/VigenereString.d.ts +4 -4
  31. package/build/src/Cipher/VigenereString.js +21 -20
  32. package/build/src/Cipher/VigenereString.js.map +1 -1
  33. package/build/src/Common/CharacterImage.d.ts +6 -6
  34. package/build/src/Common/CharacterImage.js +10 -9
  35. package/build/src/Common/CharacterImage.js.map +1 -1
  36. package/build/src/Common/EncodingCategory.d.ts +8 -8
  37. package/build/src/Common/EncodingCategory.js +12 -11
  38. package/build/src/Common/EncodingCategory.js.map +1 -1
  39. package/build/src/Common/EncodingCharacterBase.d.ts +23 -23
  40. package/build/src/Common/EncodingCharacterBase.js +52 -51
  41. package/build/src/Common/EncodingCharacterBase.js.map +1 -1
  42. package/build/src/Common/EncodingDataBase.d.ts +7 -7
  43. package/build/src/Common/EncodingDataBase.js +29 -28
  44. package/build/src/Common/EncodingDataBase.js.map +1 -1
  45. package/build/src/Common/EncodingEntry.d.ts +8 -8
  46. package/build/src/Common/EncodingEntry.js +14 -13
  47. package/build/src/Common/EncodingEntry.js.map +1 -1
  48. package/build/src/Common/EncodingLookupResult.d.ts +6 -6
  49. package/build/src/Common/EncodingLookupResult.js +13 -12
  50. package/build/src/Common/EncodingLookupResult.js.map +1 -1
  51. package/build/src/Common/Helpers.d.ts +4 -4
  52. package/build/src/Common/Helpers.js +16 -15
  53. package/build/src/Common/Helpers.js.map +1 -1
  54. package/build/src/Common/InlineSvg.d.ts +7 -7
  55. package/build/src/Common/InlineSvg.js +14 -13
  56. package/build/src/Common/InlineSvg.js.map +1 -1
  57. package/build/src/Conversion/CharacterAutoConvert.d.ts +10 -7
  58. package/build/src/Conversion/CharacterAutoConvert.js +88 -80
  59. package/build/src/Conversion/CharacterAutoConvert.js.map +1 -1
  60. package/build/src/Conversion/CharacterConversion.d.ts +8 -8
  61. package/build/src/Conversion/CharacterConversion.js +50 -49
  62. package/build/src/Conversion/CharacterConversion.js.map +1 -1
  63. package/build/src/Conversion/CharacterEncoding.d.ts +9 -8
  64. package/build/src/Conversion/CharacterEncoding.js +13 -11
  65. package/build/src/Conversion/CharacterEncoding.js.map +1 -1
  66. package/build/src/Conversion/CharacterTableEntry.d.ts +10 -10
  67. package/build/src/Conversion/CharacterTableEntry.js +19 -18
  68. package/build/src/Conversion/CharacterTableEntry.js.map +1 -1
  69. package/build/src/Conversion/SignificantFigures.d.ts +7 -7
  70. package/build/src/Conversion/SignificantFigures.js +50 -49
  71. package/build/src/Conversion/SignificantFigures.js.map +1 -1
  72. package/build/src/Conversion/StringAutoConvert.d.ts +6 -6
  73. package/build/src/Conversion/StringAutoConvert.js +46 -45
  74. package/build/src/Conversion/StringAutoConvert.js.map +1 -1
  75. package/build/src/Morse/MorseCharacter.d.ts +22 -22
  76. package/build/src/Morse/MorseCharacter.js +96 -95
  77. package/build/src/Morse/MorseCharacter.js.map +1 -1
  78. package/build/src/Morse/MorseData.d.ts +6 -6
  79. package/build/src/Morse/MorseData.js +70 -69
  80. package/build/src/Morse/MorseData.js.map +1 -1
  81. package/build/src/Morse/MorseEncoding.d.ts +59 -59
  82. package/build/src/Morse/MorseEncoding.js +94 -93
  83. package/build/src/Morse/MorseEncoding.js.map +1 -1
  84. package/build/src/Morse/MorseString.d.ts +10 -10
  85. package/build/src/Morse/MorseString.js +66 -65
  86. package/build/src/Morse/MorseString.js.map +1 -1
  87. package/build/src/Nato/NatoCharacter.d.ts +5 -5
  88. package/build/src/Nato/NatoCharacter.js +10 -9
  89. package/build/src/Nato/NatoCharacter.js.map +1 -1
  90. package/build/src/Nato/NatoData.d.ts +7 -7
  91. package/build/src/Nato/NatoData.js +51 -50
  92. package/build/src/Nato/NatoData.js.map +1 -1
  93. package/build/src/NavalFlags/NavalFlags.d.ts +7 -7
  94. package/build/src/NavalFlags/NavalFlags.js +52 -50
  95. package/build/src/NavalFlags/NavalFlags.js.map +1 -1
  96. package/build/src/Resistor/Resistor.d.ts +24 -24
  97. package/build/src/Resistor/Resistor.js +86 -85
  98. package/build/src/Resistor/Resistor.js.map +1 -1
  99. package/build/src/Resistor/ResistorColorEntry.d.ts +12 -12
  100. package/build/src/Resistor/ResistorColorEntry.js +31 -30
  101. package/build/src/Resistor/ResistorColorEntry.js.map +1 -1
  102. package/build/src/Semaphore/SemaphoreCharacter.d.ts +20 -20
  103. package/build/src/Semaphore/SemaphoreCharacter.js +75 -74
  104. package/build/src/Semaphore/SemaphoreCharacter.js.map +1 -1
  105. package/build/src/Semaphore/SemaphoreData.d.ts +6 -6
  106. package/build/src/Semaphore/SemaphoreData.js +53 -52
  107. package/build/src/Semaphore/SemaphoreData.js.map +1 -1
  108. package/build/src/Semaphore/SemaphoreDegrees.d.ts +5 -5
  109. package/build/src/Semaphore/SemaphoreDegrees.js +26 -25
  110. package/build/src/Semaphore/SemaphoreDegrees.js.map +1 -1
  111. package/build/src/Semaphore/SemaphoreDirection.d.ts +11 -11
  112. package/build/src/Semaphore/SemaphoreDirection.js +15 -14
  113. package/build/src/Semaphore/SemaphoreDirection.js.map +1 -1
  114. package/build/src/Semaphore/SemaphoreEncoding.d.ts +40 -40
  115. package/build/src/Semaphore/SemaphoreEncoding.js +47 -46
  116. package/build/src/Semaphore/SemaphoreEncoding.js.map +1 -1
  117. package/build/src/Semaphore/SemaphoreStream.d.ts +17 -17
  118. package/build/src/Semaphore/SemaphoreStream.js +72 -71
  119. package/build/src/Semaphore/SemaphoreStream.js.map +1 -1
  120. package/build/src/WordSearch/Point.d.ts +4 -4
  121. package/build/src/WordSearch/Point.js +2 -2
  122. package/build/src/WordSearch/Result.d.ts +6 -6
  123. package/build/src/WordSearch/Result.js +10 -9
  124. package/build/src/WordSearch/Result.js.map +1 -1
  125. package/build/src/WordSearch/WordSearchDirection.d.ts +6 -6
  126. package/build/src/WordSearch/WordSearchDirection.js +10 -9
  127. package/build/src/WordSearch/WordSearchDirection.js.map +1 -1
  128. package/build/src/WordSearch/WordSearchSolver.d.ts +27 -18
  129. package/build/src/WordSearch/WordSearchSolver.js +222 -171
  130. package/build/src/WordSearch/WordSearchSolver.js.map +1 -1
  131. package/build/src/index.d.ts +35 -35
  132. package/build/src/index.js +72 -70
  133. package/build/src/index.js.map +1 -1
  134. package/package.json +40 -39
  135. package/src/Braille/BrailleCharacter.ts +49 -0
  136. package/src/Braille/BrailleData.ts +131 -0
  137. package/src/Braille/BrailleDot.ts +9 -0
  138. package/src/Braille/BrailleEncoding.ts +144 -0
  139. package/src/Braille/BrailleStream.ts +87 -0
  140. package/src/Cipher/AutoKeyString.ts +35 -0
  141. package/src/Cipher/CaesarString.ts +38 -0
  142. package/src/Cipher/CaesarUtils.ts +69 -0
  143. package/src/Cipher/KeyedCipherStringBase.ts +35 -0
  144. package/src/Cipher/VigenereString.ts +21 -0
  145. package/src/Common/CharacterImage.ts +11 -0
  146. package/src/Common/EncodingCategory.ts +10 -0
  147. package/src/Common/EncodingCharacterBase.ts +72 -0
  148. package/src/Common/EncodingDataBase.ts +31 -0
  149. package/src/Common/EncodingEntry.ts +17 -0
  150. package/src/Common/EncodingLookupResult.ts +10 -0
  151. package/src/Common/Helpers.ts +13 -0
  152. package/src/Common/InlineSvg.ts +15 -0
  153. package/src/Conversion/CharacterAutoConvert.ts +108 -0
  154. package/src/Conversion/CharacterConversion.ts +89 -0
  155. package/src/Conversion/CharacterEncoding.ts +9 -0
  156. package/src/Conversion/CharacterTableEntry.ts +23 -0
  157. package/src/Conversion/SignificantFigures.ts +55 -0
  158. package/src/Conversion/StringAutoConvert.ts +56 -0
  159. package/src/Morse/MorseCharacter.ts +112 -0
  160. package/src/Morse/MorseData.ts +143 -0
  161. package/src/Morse/MorseEncoding.ts +98 -0
  162. package/src/Morse/MorseString.ts +106 -0
  163. package/src/Nato/NatoCharacter.ts +9 -0
  164. package/src/Nato/NatoData.ts +49 -0
  165. package/src/NavalFlags/LICENSE +7 -0
  166. package/src/NavalFlags/NavalFlags.ts +293 -0
  167. package/src/Resistor/Resistor.ts +135 -0
  168. package/src/Resistor/ResistorColorEntry.ts +43 -0
  169. package/src/Semaphore/SemaphoreCharacter.ts +107 -0
  170. package/src/Semaphore/SemaphoreData.ts +58 -0
  171. package/src/Semaphore/SemaphoreDegrees.ts +26 -0
  172. package/src/Semaphore/SemaphoreDirection.ts +11 -0
  173. package/src/Semaphore/SemaphoreEncoding.ts +48 -0
  174. package/src/Semaphore/SemaphoreStream.ts +89 -0
  175. package/src/WordSearch/Point.ts +4 -0
  176. package/src/WordSearch/Result.ts +10 -0
  177. package/src/WordSearch/WordSearchDirection.ts +6 -0
  178. package/src/WordSearch/WordSearchSolver.ts +271 -0
  179. package/src/index.ts +38 -0
  180. package/src/trie-prefix-tree.d.ts +70 -0
@@ -0,0 +1,23 @@
1
+ export class CharacterTableEntry {
2
+ private static getValue(value: number, base: number, maxValue: number) {
3
+ return value
4
+ .toString(base)
5
+ .padStart(Math.ceil(Math.log(maxValue) / Math.log(base)), '0');
6
+ }
7
+
8
+ readonly character: string;
9
+ readonly binary: string;
10
+ readonly ternary: string;
11
+ readonly octal: string;
12
+ readonly decimal: string;
13
+ readonly hexadecimal: string;
14
+
15
+ constructor(character: string, value: number, maxValue: number) {
16
+ this.character = character;
17
+ this.binary = CharacterTableEntry.getValue(value, 2, maxValue);
18
+ this.ternary = CharacterTableEntry.getValue(value, 3, maxValue);
19
+ this.octal = CharacterTableEntry.getValue(value, 8, maxValue);
20
+ this.decimal = CharacterTableEntry.getValue(value, 10, maxValue);
21
+ this.hexadecimal = CharacterTableEntry.getValue(value, 16, maxValue);
22
+ }
23
+ }
@@ -0,0 +1,55 @@
1
+ export class SignificantFigures {
2
+ static ceil(num: number, sigFigs: number) {
3
+ return this.roundInternal(Math.ceil, num, sigFigs);
4
+ }
5
+
6
+ static floor(num: number, sigFigs: number) {
7
+ return this.roundInternal(Math.floor, num, sigFigs);
8
+ }
9
+
10
+ static round(num: number, sigFigs: number) {
11
+ return this.roundInternal(Math.round, num, sigFigs);
12
+ }
13
+
14
+ private static roundInternal(
15
+ func: (num: number) => number,
16
+ num: number,
17
+ sigFigs: number
18
+ ) {
19
+ if (num === 0) {
20
+ return num;
21
+ }
22
+
23
+ if (sigFigs <= 0) {
24
+ throw new RangeError('sigFigs value must be positive');
25
+ }
26
+
27
+ const factor = this.getFactor(num, sigFigs);
28
+
29
+ if (factor > 0) {
30
+ return func(num / factor) * factor;
31
+ } else if (factor < 0) {
32
+ const absFactor = Math.abs(factor);
33
+ return func(num * absFactor) / absFactor;
34
+ } else {
35
+ return num;
36
+ }
37
+ }
38
+
39
+ private static getFactor(num: number, sigFigs: number) {
40
+ const absNum = Math.abs(num);
41
+ let digits = 0;
42
+
43
+ if (absNum < 1) {
44
+ digits = -sigFigs;
45
+ } else {
46
+ digits = Math.ceil(Math.log(absNum) / Math.log(10)) - sigFigs;
47
+ }
48
+
49
+ if (digits < 0) {
50
+ return -Math.pow(10, Math.abs(digits));
51
+ } else {
52
+ return Math.pow(10, digits);
53
+ }
54
+ }
55
+ }
@@ -0,0 +1,56 @@
1
+ import {CharacterAutoConvert} from './CharacterAutoConvert';
2
+ import {CharacterEncoding} from './CharacterEncoding';
3
+
4
+ export class StringAutoConvert {
5
+ static convertString(input: string, homogeneous: boolean) {
6
+ const split = this.splitString(input);
7
+
8
+ if (homogeneous) {
9
+ const encoding = this.determineStringEncoding(input);
10
+ return split.reduce(
11
+ (result, letter) =>
12
+ result + CharacterAutoConvert.convertCharacter(letter, encoding),
13
+ ''
14
+ );
15
+ } else {
16
+ return split.reduce(
17
+ (result, letter) =>
18
+ result + CharacterAutoConvert.convertCharacter(letter),
19
+ ''
20
+ );
21
+ }
22
+ }
23
+
24
+ static determineStringEncoding(input: string): CharacterEncoding {
25
+ const encodingCount: {[index: number]: number} = {};
26
+ const parsed = this.splitString(input);
27
+ const encodingKeys: number[] = [];
28
+
29
+ for (const letter of parsed) {
30
+ const charEncoding =
31
+ CharacterAutoConvert.determineCharacterEncoding(letter);
32
+ if (!encodingCount[charEncoding]) {
33
+ encodingCount[charEncoding] = 1;
34
+ encodingKeys.push(charEncoding);
35
+ } else {
36
+ encodingCount[charEncoding] = encodingCount[charEncoding] + 1;
37
+ }
38
+ }
39
+
40
+ let maxCount = 0;
41
+ let maxEncoding: number;
42
+ maxEncoding = CharacterEncoding.None;
43
+
44
+ for (const encoding of encodingKeys) {
45
+ if (encodingCount[encoding] > maxCount) {
46
+ maxCount = encodingCount[encoding];
47
+ maxEncoding = encoding;
48
+ }
49
+ }
50
+ return maxEncoding;
51
+ }
52
+
53
+ static splitString(input: string): string[] {
54
+ return input.split(' ').filter(item => item !== '');
55
+ }
56
+ }
@@ -0,0 +1,112 @@
1
+ import {EncodingCategory} from '../Common/EncodingCategory';
2
+ import {EncodingCharacterBase} from '../Common/EncodingCharacterBase';
3
+ import {Helpers} from '../Common/Helpers';
4
+ import {MorseData} from './MorseData';
5
+ import {MorseEncoding} from './MorseEncoding';
6
+
7
+ const MORSE_BITMASK = MorseEncoding.Dot | MorseEncoding.Dash;
8
+
9
+ export class MorseCharacter extends EncodingCharacterBase<MorseEncoding> {
10
+ static readonly DOT: string = '.';
11
+ static readonly DASH: string = '-';
12
+ // Character which may not appear in morse and is reserved for use by this class
13
+ static readonly RESERVED_DIVIDER: string = 'A';
14
+
15
+ static toMorseString(encoding: MorseEncoding) {
16
+ let morseChars = '';
17
+
18
+ while (encoding !== MorseEncoding.None) {
19
+ if ((encoding & MORSE_BITMASK) === MorseEncoding.Dot) {
20
+ morseChars += MorseCharacter.DOT;
21
+ } else if ((encoding & MORSE_BITMASK) === MorseEncoding.Dash) {
22
+ morseChars += MorseCharacter.DASH;
23
+ } else {
24
+ throw new Error('Invalid morse bits');
25
+ }
26
+
27
+ encoding >>>= 2;
28
+ }
29
+
30
+ return morseChars;
31
+ }
32
+
33
+ static parseMorseString(morse: string): MorseEncoding {
34
+ let bits = MorseEncoding.None;
35
+
36
+ for (let i = morse.length - 1; i >= 0; i--) {
37
+ const ch = morse[i];
38
+ if (ch === MorseCharacter.DOT) {
39
+ bits |= MorseEncoding.Dot;
40
+ } else if (ch === MorseCharacter.DASH) {
41
+ bits |= MorseEncoding.Dash;
42
+ } else {
43
+ throw new Error('Invalid morse character');
44
+ }
45
+
46
+ bits <<= 2;
47
+ }
48
+
49
+ bits >>>= 2;
50
+ return bits;
51
+ }
52
+
53
+ private _morse: string;
54
+
55
+ constructor(str = '', category: EncodingCategory = EncodingCategory.All) {
56
+ super(MorseData.instance, category);
57
+
58
+ this._morse = str;
59
+ }
60
+
61
+ get morseString() {
62
+ return this._morse;
63
+ }
64
+
65
+ set morseString(value: string) {
66
+ this._morse = value;
67
+ this.invalidateLookup();
68
+ }
69
+
70
+ backspace() {
71
+ if (this._morse.length > 0) {
72
+ this._morse = this._morse.substring(0, this._morse.length - 1);
73
+ this.invalidateLookup();
74
+ }
75
+ }
76
+
77
+ dot() {
78
+ this._morse += MorseCharacter.DOT;
79
+ this.invalidateLookup();
80
+ }
81
+
82
+ dash() {
83
+ this._morse += MorseCharacter.DASH;
84
+ this.invalidateLookup();
85
+ }
86
+
87
+ invertDotsAndDashes() {
88
+ // Replace dots with a placeholder, dashes with dots, then placeholders with dashes
89
+ Helpers.assert(this._morse.indexOf(MorseCharacter.RESERVED_DIVIDER) < 0);
90
+ this._morse = this._morse
91
+ .replace(/\./g, 'A')
92
+ .replace(/-/g, MorseCharacter.DOT)
93
+ .replace(/A/g, MorseCharacter.DASH);
94
+ }
95
+
96
+ reverse() {
97
+ this._morse = this._morse.split('').reverse().join('');
98
+ }
99
+
100
+ protected onClear() {
101
+ this._morse = '';
102
+ this.invalidateLookup();
103
+ }
104
+
105
+ protected onEmpty() {
106
+ return this._morse.length === 0;
107
+ }
108
+
109
+ protected getEncoding() {
110
+ return MorseCharacter.parseMorseString(this._morse);
111
+ }
112
+ }
@@ -0,0 +1,143 @@
1
+ import {EncodingCategory} from '../Common/EncodingCategory';
2
+ import {EncodingDataBase} from '../Common/EncodingDataBase';
3
+ import {MorseEncoding} from './MorseEncoding';
4
+
5
+ export class MorseData extends EncodingDataBase<MorseEncoding> {
6
+ static readonly instance: MorseData = new MorseData();
7
+
8
+ constructor() {
9
+ super();
10
+
11
+ // Letters
12
+ this.addToList(MorseEncoding.LetterA, EncodingCategory.Letter, 'A');
13
+ this.addToList(MorseEncoding.LetterB, EncodingCategory.Letter, 'B');
14
+ this.addToList(MorseEncoding.LetterC, EncodingCategory.Letter, 'C');
15
+ this.addToList(MorseEncoding.LetterD, EncodingCategory.Letter, 'D');
16
+ this.addToList(MorseEncoding.LetterE, EncodingCategory.Letter, 'E');
17
+ this.addToList(MorseEncoding.LetterF, EncodingCategory.Letter, 'F');
18
+ this.addToList(MorseEncoding.LetterG, EncodingCategory.Letter, 'G');
19
+ this.addToList(MorseEncoding.LetterH, EncodingCategory.Letter, 'H');
20
+ this.addToList(MorseEncoding.LetterI, EncodingCategory.Letter, 'I');
21
+ this.addToList(MorseEncoding.LetterJ, EncodingCategory.Letter, 'J');
22
+ this.addToList(MorseEncoding.LetterK, EncodingCategory.Letter, 'K');
23
+ this.addToList(MorseEncoding.LetterL, EncodingCategory.Letter, 'L');
24
+ this.addToList(MorseEncoding.LetterM, EncodingCategory.Letter, 'M');
25
+ this.addToList(MorseEncoding.LetterN, EncodingCategory.Letter, 'N');
26
+ this.addToList(MorseEncoding.LetterO, EncodingCategory.Letter, 'O');
27
+ this.addToList(MorseEncoding.LetterP, EncodingCategory.Letter, 'P');
28
+ this.addToList(MorseEncoding.LetterQ, EncodingCategory.Letter, 'Q');
29
+ this.addToList(MorseEncoding.LetterR, EncodingCategory.Letter, 'R');
30
+ this.addToList(MorseEncoding.LetterS, EncodingCategory.Letter, 'S');
31
+ this.addToList(MorseEncoding.LetterT, EncodingCategory.Letter, 'T');
32
+ this.addToList(MorseEncoding.LetterU, EncodingCategory.Letter, 'U');
33
+ this.addToList(MorseEncoding.LetterV, EncodingCategory.Letter, 'V');
34
+ this.addToList(MorseEncoding.LetterW, EncodingCategory.Letter, 'W');
35
+ this.addToList(MorseEncoding.LetterX, EncodingCategory.Letter, 'X');
36
+ this.addToList(MorseEncoding.LetterY, EncodingCategory.Letter, 'Y');
37
+ this.addToList(MorseEncoding.LetterZ, EncodingCategory.Letter, 'Z');
38
+
39
+ // Numbers
40
+ this.addToList(MorseEncoding.Number0, EncodingCategory.Number, '0');
41
+ this.addToList(MorseEncoding.Number1, EncodingCategory.Number, '1');
42
+ this.addToList(MorseEncoding.Number2, EncodingCategory.Number, '2');
43
+ this.addToList(MorseEncoding.Number3, EncodingCategory.Number, '3');
44
+ this.addToList(MorseEncoding.Number4, EncodingCategory.Number, '4');
45
+ this.addToList(MorseEncoding.Number5, EncodingCategory.Number, '5');
46
+ this.addToList(MorseEncoding.Number6, EncodingCategory.Number, '6');
47
+ this.addToList(MorseEncoding.Number7, EncodingCategory.Number, '7');
48
+ this.addToList(MorseEncoding.Number8, EncodingCategory.Number, '8');
49
+ this.addToList(MorseEncoding.Number9, EncodingCategory.Number, '9');
50
+
51
+ // Punctuation
52
+ this.addToList(
53
+ MorseEncoding.PunctuationPeriod,
54
+ EncodingCategory.Punctuation,
55
+ '.'
56
+ );
57
+ this.addToList(
58
+ MorseEncoding.PunctuationComma,
59
+ EncodingCategory.Punctuation,
60
+ ','
61
+ );
62
+ this.addToList(
63
+ MorseEncoding.PunctuationQuestionMark,
64
+ EncodingCategory.Punctuation,
65
+ '?'
66
+ );
67
+ this.addToList(
68
+ MorseEncoding.PunctuationApostrophe,
69
+ EncodingCategory.Punctuation,
70
+ "'"
71
+ );
72
+ this.addToList(
73
+ MorseEncoding.PunctuationExclamationPoint,
74
+ EncodingCategory.Punctuation,
75
+ '!'
76
+ );
77
+ this.addToList(
78
+ MorseEncoding.PunctuationForwardSlash,
79
+ EncodingCategory.Punctuation,
80
+ '/'
81
+ );
82
+ this.addToList(
83
+ MorseEncoding.PunctuationOpenParenthesis,
84
+ EncodingCategory.Punctuation,
85
+ '('
86
+ );
87
+ this.addToList(
88
+ MorseEncoding.PunctuationCloseParenthesis,
89
+ EncodingCategory.Punctuation,
90
+ ')'
91
+ );
92
+ this.addToList(
93
+ MorseEncoding.PunctuationAmpersand,
94
+ EncodingCategory.Punctuation,
95
+ '&'
96
+ );
97
+ this.addToList(
98
+ MorseEncoding.PunctuationColon,
99
+ EncodingCategory.Punctuation,
100
+ ':'
101
+ );
102
+ this.addToList(
103
+ MorseEncoding.PunctuationSemicolon,
104
+ EncodingCategory.Punctuation,
105
+ ';'
106
+ );
107
+ this.addToList(
108
+ MorseEncoding.PunctuationDoubleDash,
109
+ EncodingCategory.Punctuation,
110
+ '='
111
+ );
112
+ this.addToList(
113
+ MorseEncoding.PunctuationPlusSign,
114
+ EncodingCategory.Punctuation,
115
+ '+'
116
+ );
117
+ this.addToList(
118
+ MorseEncoding.PunctuationHyphen,
119
+ EncodingCategory.Punctuation,
120
+ '-'
121
+ );
122
+ this.addToList(
123
+ MorseEncoding.PunctuationUnderscore,
124
+ EncodingCategory.Punctuation,
125
+ '_'
126
+ );
127
+ this.addToList(
128
+ MorseEncoding.PunctuationQuotationMark,
129
+ EncodingCategory.Punctuation,
130
+ '"'
131
+ );
132
+ this.addToList(
133
+ MorseEncoding.PunctuationDollarSign,
134
+ EncodingCategory.Punctuation,
135
+ '$'
136
+ );
137
+ this.addToList(
138
+ MorseEncoding.PunctuationAtSign,
139
+ EncodingCategory.Punctuation,
140
+ '@'
141
+ );
142
+ }
143
+ }
@@ -0,0 +1,98 @@
1
+ // The encoding for morse is much less straightforward than the others. The dots
2
+ // and dashes each use two bits of the integer starting with the least-
3
+ // significant bit.
4
+ //
5
+ // Example:
6
+ //
7
+ // 'F' -> ..-.
8
+ //
9
+ // Which encodes as:
10
+ //
11
+ // 01 01 10 01
12
+ // . . - .
13
+ //
14
+ // Since it's packed starting with the LSB, the resulting number is reversed:
15
+ //
16
+ // 01100101 -> 0x65
17
+ //
18
+
19
+ function packMorse(...args: MorseEncoding[]) {
20
+ let value = MorseEncoding.None;
21
+ let shift = 0;
22
+
23
+ for (let arg of args) {
24
+ arg <<= shift;
25
+ value |= arg;
26
+ shift += 2;
27
+ }
28
+
29
+ return value;
30
+ }
31
+
32
+ export enum MorseEncoding {
33
+ None = 0,
34
+
35
+ // Primitives
36
+ Dot = 0x1,
37
+ Dash = 0x2,
38
+
39
+ // Letters
40
+ LetterA = packMorse(Dot, Dash),
41
+ LetterB = packMorse(Dash, Dot, Dot, Dot),
42
+ LetterC = packMorse(Dash, Dot, Dash, Dot),
43
+ LetterD = packMorse(Dash, Dot, Dot),
44
+ LetterE = packMorse(Dot),
45
+ LetterF = packMorse(Dot, Dot, Dash, Dot),
46
+ LetterG = packMorse(Dash, Dash, Dot),
47
+ LetterH = packMorse(Dot, Dot, Dot, Dot),
48
+ LetterI = packMorse(Dot, Dot),
49
+ LetterJ = packMorse(Dot, Dash, Dash, Dash),
50
+ LetterK = packMorse(Dash, Dot, Dash),
51
+ LetterL = packMorse(Dot, Dash, Dot, Dot),
52
+ LetterM = packMorse(Dash, Dash),
53
+ LetterN = packMorse(Dash, Dot),
54
+ LetterO = packMorse(Dash, Dash, Dash),
55
+ LetterP = packMorse(Dot, Dash, Dash, Dot),
56
+ LetterQ = packMorse(Dash, Dash, Dot, Dash),
57
+ LetterR = packMorse(Dot, Dash, Dot),
58
+ LetterS = packMorse(Dot, Dot, Dot),
59
+ LetterT = packMorse(Dash),
60
+ LetterU = packMorse(Dot, Dot, Dash),
61
+ LetterV = packMorse(Dot, Dot, Dot, Dash),
62
+ LetterW = packMorse(Dot, Dash, Dash),
63
+ LetterX = packMorse(Dash, Dot, Dot, Dash),
64
+ LetterY = packMorse(Dash, Dot, Dash, Dash),
65
+ LetterZ = packMorse(Dash, Dash, Dot, Dot),
66
+
67
+ // Numbers
68
+ Number0 = packMorse(Dash, Dash, Dash, Dash, Dash),
69
+ Number1 = packMorse(Dot, Dash, Dash, Dash, Dash),
70
+ Number2 = packMorse(Dot, Dot, Dash, Dash, Dash),
71
+ Number3 = packMorse(Dot, Dot, Dot, Dash, Dash),
72
+ Number4 = packMorse(Dot, Dot, Dot, Dot, Dash),
73
+ Number5 = packMorse(Dot, Dot, Dot, Dot, Dot),
74
+ Number6 = packMorse(Dash, Dot, Dot, Dot, Dot),
75
+ Number7 = packMorse(Dash, Dash, Dot, Dot, Dot),
76
+ Number8 = packMorse(Dash, Dash, Dash, Dot, Dot),
77
+ Number9 = packMorse(Dash, Dash, Dash, Dash, Dot),
78
+
79
+ // Punctuation
80
+ PunctuationPeriod = packMorse(Dot, Dash, Dot, Dash, Dot, Dash),
81
+ PunctuationComma = packMorse(Dash, Dash, Dot, Dot, Dash, Dash),
82
+ PunctuationQuestionMark = packMorse(Dot, Dot, Dash, Dash, Dot, Dot),
83
+ PunctuationApostrophe = packMorse(Dot, Dash, Dash, Dash, Dash, Dot),
84
+ PunctuationExclamationPoint = packMorse(Dash, Dot, Dash, Dot, Dash, Dash),
85
+ PunctuationForwardSlash = packMorse(Dash, Dot, Dot, Dash, Dot),
86
+ PunctuationOpenParenthesis = packMorse(Dash, Dot, Dash, Dash, Dot),
87
+ PunctuationCloseParenthesis = packMorse(Dash, Dot, Dash, Dash, Dot, Dash),
88
+ PunctuationAmpersand = packMorse(Dot, Dash, Dot, Dot, Dot),
89
+ PunctuationColon = packMorse(Dash, Dash, Dash, Dot, Dot, Dot),
90
+ PunctuationSemicolon = packMorse(Dash, Dot, Dash, Dot, Dash, Dot),
91
+ PunctuationDoubleDash = packMorse(Dash, Dot, Dot, Dot, Dash),
92
+ PunctuationPlusSign = packMorse(Dot, Dash, Dot, Dash, Dot),
93
+ PunctuationHyphen = packMorse(Dash, Dot, Dot, Dot, Dot, Dash),
94
+ PunctuationUnderscore = packMorse(Dot, Dot, Dash, Dash, Dot, Dash),
95
+ PunctuationQuotationMark = packMorse(Dot, Dash, Dot, Dot, Dash, Dot),
96
+ PunctuationDollarSign = packMorse(Dot, Dot, Dot, Dash, Dot, Dot, Dash),
97
+ PunctuationAtSign = packMorse(Dot, Dash, Dash, Dot, Dash, Dot),
98
+ }
@@ -0,0 +1,106 @@
1
+ import {Helpers} from '../Common/Helpers';
2
+ import {MorseCharacter} from './MorseCharacter';
3
+
4
+ // MorseString represents a string of multiple morse characters. It allows for a longer representation
5
+ // to be converted to a single string and allows for sentence-level transforms such as reversing
6
+ // the order of tokens.
7
+ export class MorseString {
8
+ static readonly CHARACTER_DIVIDER: string = '/';
9
+ static readonly WORD_DIVIDER = ' ';
10
+
11
+ constructor(
12
+ morse = '',
13
+ characterDivider = MorseString.CHARACTER_DIVIDER,
14
+ wordDivider = MorseString.WORD_DIVIDER
15
+ ) {
16
+ // The dividers should be single characters which don't clash with the other string content
17
+ Helpers.assertMsg(
18
+ characterDivider.length === 1,
19
+ 'Divider must be a single character'
20
+ );
21
+ Helpers.assertMsg(
22
+ wordDivider.length === 1,
23
+ 'Divider must be a single character'
24
+ );
25
+ Helpers.assertMsg(
26
+ characterDivider !== wordDivider,
27
+ 'Dividers must be different from each other'
28
+ );
29
+ Helpers.assertMsg(
30
+ characterDivider !== MorseCharacter.DASH,
31
+ 'Character divider must not be a reserved value'
32
+ );
33
+ Helpers.assertMsg(
34
+ characterDivider !== MorseCharacter.DOT,
35
+ 'Character divider must not be a reserved value'
36
+ );
37
+ Helpers.assertMsg(
38
+ characterDivider !== MorseCharacter.RESERVED_DIVIDER,
39
+ 'Character divider must not be a reserved value'
40
+ );
41
+ Helpers.assertMsg(
42
+ wordDivider !== MorseCharacter.DASH,
43
+ 'Word divider must not be a reserved value'
44
+ );
45
+ Helpers.assertMsg(
46
+ wordDivider !== MorseCharacter.DOT,
47
+ 'Word divider must not be a reserved value'
48
+ );
49
+ Helpers.assertMsg(
50
+ wordDivider !== MorseCharacter.RESERVED_DIVIDER,
51
+ 'Word divider must not be a reserved value'
52
+ );
53
+
54
+ const words = morse.split(wordDivider).filter(w => w.length > 0);
55
+ // Discard any empty characters (caused by trailing separator)
56
+ const wordCharacters = words.map(w =>
57
+ w.split(characterDivider).filter(wc => wc.length > 0)
58
+ );
59
+ this._words = wordCharacters.map(subarray =>
60
+ subarray.map(wc => new MorseCharacter(wc))
61
+ );
62
+ }
63
+
64
+ // reverse reverses the order of all tokens in the string (including separators), such as would be
65
+ // the case if you were reading the data for a puzzle backwards.
66
+ reverse(): MorseString {
67
+ for (let i = 0; i < this._words.length; i++) {
68
+ for (const c of this._words[i]) {
69
+ // Reverse the dots/dashes in each letter
70
+ c.reverse();
71
+ }
72
+ // Reverse the letters in each word
73
+ this._words[i] = this._words[i].reverse();
74
+ }
75
+
76
+ // Reverse the order of the words
77
+ this._words = this._words.reverse();
78
+ return this;
79
+ }
80
+
81
+ // invertDotsAndDashes switches all dots and dashes in the input, such as would be the case if
82
+ // you had two ambiguous symbols for dot/dash and selected the wrong mapping.
83
+ invertDotsAndDashes(): MorseString {
84
+ for (const word of this._words) {
85
+ for (const c of word) {
86
+ c.invertDotsAndDashes();
87
+ }
88
+ }
89
+ return this;
90
+ }
91
+
92
+ toString(): string {
93
+ let s = '';
94
+ for (let i = 0; i < this._words.length; i++) {
95
+ if (i > 0) {
96
+ s += ' '; // This is a new word
97
+ }
98
+ for (const c of this._words[i]) {
99
+ s += c.toString() || '?';
100
+ }
101
+ }
102
+ return s;
103
+ }
104
+
105
+ protected _words: MorseCharacter[][];
106
+ }
@@ -0,0 +1,9 @@
1
+ export class NatoCharacter {
2
+ readonly character: string;
3
+ readonly word: string;
4
+
5
+ constructor(character: string, word: string) {
6
+ this.character = character;
7
+ this.word = word;
8
+ }
9
+ }
@@ -0,0 +1,49 @@
1
+ import {NatoCharacter} from './NatoCharacter';
2
+
3
+ // There's no concept of a 'partial match' for a NATO letter, so there's no
4
+ // reason to derive from EncodingDataBase.
5
+ export class NatoData {
6
+ static readonly instance: NatoData = new NatoData();
7
+
8
+ private readonly _entries: NatoCharacter[] = [
9
+ new NatoCharacter('A', 'Alfa'),
10
+ new NatoCharacter('B', 'Bravo'),
11
+ new NatoCharacter('C', 'Charlie'),
12
+ new NatoCharacter('D', 'Delta'),
13
+ new NatoCharacter('E', 'Echo'),
14
+ new NatoCharacter('F', 'Foxtrot'),
15
+ new NatoCharacter('G', 'Golf'),
16
+ new NatoCharacter('H', 'Hotel'),
17
+ new NatoCharacter('I', 'India'),
18
+ new NatoCharacter('J', 'Juliet'),
19
+ new NatoCharacter('K', 'Kilo'),
20
+ new NatoCharacter('L', 'Lima'),
21
+ new NatoCharacter('M', 'Mike'),
22
+ new NatoCharacter('N', 'November'),
23
+ new NatoCharacter('O', 'Oscar'),
24
+ new NatoCharacter('P', 'Papa'),
25
+ new NatoCharacter('Q', 'Quebec'),
26
+ new NatoCharacter('R', 'Romeo'),
27
+ new NatoCharacter('S', 'Sierra'),
28
+ new NatoCharacter('T', 'Tango'),
29
+ new NatoCharacter('U', 'Uniform'),
30
+ new NatoCharacter('V', 'Victor'),
31
+ new NatoCharacter('W', 'Whiskey'),
32
+ new NatoCharacter('X', 'X-ray'),
33
+ new NatoCharacter('Y', 'Yankee'),
34
+ new NatoCharacter('Z', 'Zulu'),
35
+ ];
36
+
37
+ get entries(): NatoCharacter[] {
38
+ return this._entries;
39
+ }
40
+
41
+ lookup(letter: string): NatoCharacter | null {
42
+ for (const ch of this._entries) {
43
+ if (ch.character.toUpperCase() === letter.toUpperCase()) {
44
+ return ch;
45
+ }
46
+ }
47
+ return null;
48
+ }
49
+ }
@@ -0,0 +1,7 @@
1
+ The SVG images used in this directory are of simple geometry is ineligible for copyright
2
+ and therefore in the public domain, because it consists entirely of information that is
3
+ common property and contains no original authorship. With the exception of the image
4
+ for 'U'/'Uniform', they were obtained from the Wikimedia Commons project at
5
+ https://commons.wikimedia.org/wiki/Category:SVG_signal_flags on 2018-10-17. The SVG
6
+ for Uniform is also ineligible for copyright and in the public domain, but did not come
7
+ from Wikimedia.