Obi Fortune

TypeScript ASCII Art!

Monday 8 January 2024

main image for TypeScript ASCII Art!

Typehero - advent of typescript solution for day 20!

My Solution

Day 20 of the typehero advent of code involved converting regular strings to ascii art.

The Problem

type test_0_actual = ToAsciiArt<" * : * Merry * : * \n Christmas ">;
type test_0_expected = [
"░░░░░#░░░█▄░▄█ █▀▀ █▀█ █▀█ █ █ ░░░#░░░░░",
"░░░#░░░#░█ ▀ █ █▀▀ ██▀ ██▀ ▀█▀ ░#░░░#░░░",
"░░░░░#░░░▀ ░░▀ ▀▀▀ ▀ ▀ ▀ ▀ ░▀ ░░░░#░░░░░",
"░░█▀▀ █ █ █▀█ █ █▀▀ ▀█▀ █▄░▄█ █▀█ █▀▀ ░░",
"░░█ ░░█▀█ ██▀ █ ▀▀█ ░█ ░█ ▀ █ █▀█ ▀▀█ ░░",
"░░▀▀▀ ▀ ▀ ▀ ▀ ▀ ▀▀▀ ░▀ ░▀ ░░▀ ▀ ▀ ▀▀▀ ░░",
];

Meaning you would need to convert test_0_actual to test_0_expected

the letters are already provided to you in a record with the type signature of Record<string, [string, string, string]> which has

  1. key - string to be converted
  2. value - top, middle and bottom of the ascii version of the key

The Idea

This is a complicated type that requires a few utility types to work

  1. Generate - accepts a string and uses it to create a tuple containing the corresponding Letters tuples
  2. GetIndex - accepts a a tuple of Letters tuples and gets a specific index in the tuple
  3. Join - accepts a tuple of Letters tuples and adds them to each other based on their index
  4. ToAsciiArt - the final type which wraps up all the other types and is used by the typehero challenge

Solution

type Letters = {
A: [
'█▀█ ',
'█▀█ ',
'▀ ▀ ',
],
B: [
'█▀▄ ',
'█▀▄ ',
'▀▀ '
],
C: [
'█▀▀ ',
'█ ░░',
'▀▀▀ '
],
E: [
'█▀▀ ',
'█▀▀ ',
'▀▀▀ '
],
H: [
'█ █ ',
'█▀█ ',
'▀ ▀ '
],
I: [
'█ ',
'█ ',
'▀ '
],
M: [
'█▄░▄█ ',
'█ ▀ █ ',
'▀ ░░▀ '
],
N: [
'█▄░█ ',
'█ ▀█ ',
'▀ ░▀ '
],
P: [
'█▀█ ',
'█▀▀ ',
'▀ ░░'
],
R: [
'█▀█ ',
'██▀ ',
'▀ ▀ '
],
S: [
'█▀▀ ',
'▀▀█ ',
'▀▀▀ '
],
T: [
'▀█▀ ',
'░█ ░',
'░▀ ░'
],
Y: [
'█ █ ',
'▀█▀ ',
'░▀ ░'
],
W: [
'█ ░░█ ',
'█▄▀▄█ ',
'▀ ░ ▀ '
],
' ': [
'░',
'░',
'░'
],
':': [
'#',
'░',
'#'
],
'*': [
'░',
'#',
'░'
],
};
type GetIndex<T, N extends number, R extends string = ""> = T extends [
infer F extends [string, string, string],
...infer L,
]
? GetIndex<L, N, `${R}${F[N]}`>
: R;
type Join<T extends any[], R extends any[] = []> = R["length"] extends 3
? R
: Join<T, [...R, GetIndex<T, R["length"]>]>;
type Generate<V extends string, R extends any[] = []> = Uppercase<V> extends `${infer F extends
keyof Letters}${infer L}`
? Generate<L, [...R, Letters[F]]>
: R;
type ToAsciiArt<T extends string, R extends any[] = []> = T extends `${infer F}\n${infer L}`
? ToAsciiArt<L, [...R, ...Join<Generate<F>>]>
: [...R, ...Join<Generate<T>>];