14
\$\begingroup\$

About Hangul

As I'm Korean, I'm really proud of Korean character, Hangul(한글).

Hangul is a syllabary invented by King Sejong the great, 4th king of Joseon dynasty, in 1443.

Because today (October 9th) is Hangul day in Korea, I'll give you a challenge: Make some Hangul

List of characters

So, To make ASCII art, you have to know every characters represent each syllables, right?

No. There are 11172 syllables in Korean character, so it's almost impossible to hardcode it. But, there are only 24 basic characters:

ㄱㄴㄷㄹㅁㅂㅅㅇㅈㅊㅋㅌㅍㅎㅏㅑㅓㅕㅗㅛㅜㅠㅡㅣ

And in Korean you compose these to make all those syllables.

How to compose

24 basic characters can be separated into two part: a consonant and a vowel.

The first 14 characters ㄱㄴㄷㄹㅁㅂㅅㅇㅈㅊㅋㅌㅍㅎ are consonants, and followingthe 10 characters ㅏㅑㅓㅕㅗㅛㅜㅠㅡㅣ are vowels.

There are roughly 3 parts to a Korean character: initial consonant, vowel, and a final consonant.

Initial consonant

The initial consonant (초성 in Korean) is simplest part. It is just consonant, only with ㄲㄸㅃㅆㅉ(double consonant). It placed in the top-left.

Vowel

The vowel (중성 or 모음 in Korean) is the hardest part. Here is list of the vowels: ㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣ

ㅏㅐㅏㅒㅓㅔㅕㅖㅣ go on the right side of initial consonant; ㅗㅛㅜㅠㅡ go at the bottom; ㅘㅙㅚㅝㅞㅟㅢ are both. For example: 가, 고, 과.

Final consonant

The final consonant (종성 in Korean) is at the bottom. Here is list of final consonants: ㄱㄲㄳㄴㄵㄶㄷㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅄㅅㅆㅇㅈㅊㅋㅌㅍㅎ, or blank.

Example characters using final consonant : 각, 갌, 갏

How to decompose Unicode

See this webpage for help.

Challenge

Input is in this format: (number) Korean char (number) Korean char ... Where (number) is optional. If a number is given, switch to a different style as specified below. 1 and 2 are ASCII only, and 3 is Unicode box-art.

Separate characters with 2 spaces. Note that not every character has the same width.

If the vowel is not ㅗㅛㅜㅠㅡ, the following final consonant must be indented with a space.

The default style is 1, so if first character doesn't have a number, style 1 is used.

An example input could be: 1한2글3날 or 한3글날.

Here is list of Korean ascii art(style 1 and 2).

Here is list of Korean unicode box-art(style 3).

List of ASCII art

Style 1

ㄱ
___
   |
   |

ㄴ
|
|
|__

ㄷ
 ___
|
|___

ㄹ
___
 __|
|___

ㅁ
 __
|  |
|__|

ㅂ
|  |
|__|
|__|

ㅅ
 /\
|  |
|  |

ㅇ
 __
/  \
\__/

ㅈ
____
 /\
/  \

ㅊ
 __ 
____
/  \

ㅋ
___
___|
   |

ㅌ
 ___
|___
|___

ㅍ
____
 ||
_;;_

ㅎ
 __
____
 ()

ㄲ
_ _
 | |
 | |

ㄸ
 _ _
| |
|_|_

ㅃ
||||
[][]
""""

ㅆ
/|/|
||||
||||

ㅉ
____
/|/|
||||

ㅏ
    |
    |_
    |
    |

ㅐ
    | |
    |_|
    | |
    | |

ㅑ
    |
    |_
    |_
    |

ㅒ
    | |
    |_|
    |_|
    | |

ㅓ
     |
    _|
     |
     |

ㅔ
     ||
    _||
     ||
     ||

ㅕ
     |
    _|
    _|
     |

ㅖ
     ||
    _||
    _||
     ||

ㅗ



 |
_|__

ㅘ
    |
    |
    |_
 |  |
_|__|

ㅙ
    | |
    | |
    |_|
 |  | |
_|__| |

ㅚ
    |
    |
    |
 |  |
_|__|

ㅛ



 ||
_][_

ㅜ



____
 |

ㅝ
    |
    |
    |
____|
 |--|

ㅞ
    ||
    ||
    ||
____||
 |--||

ㅟ
    |
    |
    |
____|
 |  |

ㅠ



____
 ||

ㅡ



____

ㅢ
    |
    |
    |
    |
____|

ㅣ
    |
    |
    |
    |

ㄳ
_ /|
 |||
 |||

ㄵ
| __
| /|
|_||

ㄶ
| __
| __
|_()

ㄺ
_ _ 
 ] |
[_ |

ㄻ
_ ++
 ]||
[_""

ㄼ
_ ||
 ][]
[_""

ㄽ
_ /|
 ]||
[_||

ㄾ
_  _
 ]|_
[_|_

ㄿ
_ __
 ]][
[_""

ㅀ
_ __
 ]__
[_()

Style 2

ㄱ
---.
   :
   :

ㄴ
:
:
'---

ㄷ
.---
:
'---


ㄹ
---.
.--'
'---

ㅁ
.--.
:  :
'--'

ㅂ
:  :
:--:
'--'

ㅅ
 ,.
:  :
:  :

ㅇ
 ..
(  )
 ''

ㅈ
-.,-
 ;:
'  `

ㅊ
 -- 
-,.-
;  :

ㅋ
---.
---:
   :

ㅌ
.---
:---
'---

ㅍ
-..-
 ::
-''-

ㅎ
 --
----
 ()

ㄲ
-.-.
 : :
 : :

ㄸ
.-.-
: : 
'-'-

ㅃ
::::
[][]
''''

ㅆ
,:,:
::::
::::

ㅉ
----
,:,:
::::

ㅏ
    :
    :-
    :
    :

ㅐ
    : :
    :-:
    : :
    : :

ㅑ
    :
    :-
    :-
    :

ㅒ
    : :
    :-:
    :-:
    : :

ㅓ
     :
    -:
     :
     :

ㅔ
     ::
    -::
     ::
     ::

ㅕ
     :
    -:
    -:
     :

ㅖ
     ::
    -::
    -::
     ::

ㅗ


 :
-^--

ㅘ
    :
    :
    :-
 :  :
-^--:

ㅙ
    : :
    : :
    :-:
 :  : :
-^--: :

ㅚ
    :
    :
    :
 :  :
-^--:

ㅛ



 ::
-^^-

ㅜ
 
 
 
-v--
 :

ㅝ
    :
    :
    :
-v--:
 :--:

ㅞ
    ::
    ::
    ::
-v--::
 :--::

ㅟ
    :
    :
    :
-v--:
 :  :

ㅠ
 
 
 
-vv-
 ::

ㅡ



----

ㅢ
    :
    :
    :
    :
----:

ㅣ
    :
    :
    :
    :

ㄳ
-.,:
 :::
 :::

ㄵ
: --
: ,:
'-::

ㄶ
: --
: --
'-()

ㄺ
-.-.
.' :
'- :

ㄻ
-...
.'::
'-''

ㄼ
-.::
.'][
'-''

ㄽ
-.,:
.'::
'-::

ㄾ
-..-
.':-
'-'-

ㄿ
-...
.'][
'-''

ㅀ
-.--
.'--
'-()

Style 3

ㄱ
───┐
   │
   │

ㄴ
│
│
└──

ㄷ
┌───
│
└───

ㄹ
───┐
┌──┘
└───

ㅁ
┌──┐
│  │
└──┘

ㅂ
│  │
├──┤
└──┘

ㅅ
 ╱╲
│  │
│  │

ㅇ
╭──╮
│  │
╰──╯

ㅈ
────
 ╱╲
╱  ╲

ㅊ
 ── 
────
╱  ╲

ㅋ
───┐
───┤
   │

ㅌ
┌───
├───
└───

ㅍ
─┬┬─
 ││
─┴┴─

ㅎ
 ──
────
 ()

ㄲ
─┐─┐
 │ │
 │ │

ㄸ
┌─┌─
│ │
└─└─

ㅃ
││││
├┤├┤
└┘└┘

ㅆ
╱│╱│
││││
││││

ㅉ
────
╱│╱│
││││

ㅏ
    │
    ├─
    │
    │

ㅐ
    │ │
    ├─┤
    │ │
    │ │

ㅑ
    │
    ├─
    ├─
    │

ㅒ
    │ │
    ├─┤
    ├─┤
    │ │

ㅓ
     │
    ─┤
     │
     │

ㅔ
     ││
    ─┤│
     ││
     ││

ㅕ
     │
    ─┤
    ─┤
     │

ㅖ
     ││
    ─┤│
    ─┤│
     ││

ㅗ



 ╷
─┴──

ㅘ
    │
    │
    ├─
 ╷  │
─┴──│


ㅙ
    │ │
    │ │
    ├─┤
 ╷  │ │
─┴──│ │

ㅚ
    │
    │
    │
 ╷  │
─┴──│

ㅛ



 ╷╷
─┴┴─

ㅜ



─┬──
 ╵

ㅝ
    │
    │
    │
─┬──│
 ╵──┤

ㅞ
    ││
    ││
    ││
─┬──││
 ╵──┤│

ㅟ
    │
    │
    │
─┬──│
 ╵  │

ㅠ



─┬┬─
 ╵╵

ㅡ



────

ㅢ
    │
    │
    │
    │
────│

ㅣ
    │
    │
    │
    │

ㄳ
─┐╭╮
 │││
 │││

ㄵ
╷ ──
│ ╱│
└─╵╵

ㄶ
│ ──
│ ──
└─()

ㄺ
─┐─┐
┌┘ │
└─ ╵

ㄻ
─┐┌┐
┌┘││
└─└┘

ㄼ
─┐╷╷
┌┘├┤
└─└┘

ㄽ
─┐╭╮
┌┘││
└─╵╵

ㄾ
─┐┌─
┌┘├─
└─└─

ㄿ
─┐┬┬
┌┘││
└─┴┴

ㅀ
─┐──
┌┘──
└─()

Example input and output

1한2글3날

 __ |   ---.  │   │
____|_     :  │   ├─
 () |      :  └── │
    |   ----      │
 |      ---.   ───┐
 |      .--'   ┌──┘
 |__    '---   └───

뛟쀒3쫽

 _ _||  ||||||  ────│ │
| | ||  [][]||  ╱│╱││ │
|_|_||  """"||  ││││├─┤
____||  ____||   ╷  │ │
 |--||   |--||  ─┴──│ │
 _ __    _ __    ─┐─┐
  ]__     ]][    ┌┘ │
 [_()    [_""    └─ ╵

Scoring

This is , so the shortest code in bytes wins.

\$\endgroup\$
3
  • \$\begingroup\$ I was about to say something criticizing the three different styles, but come to think of if they could actually result in some very interesting compression techniques. \$\endgroup\$ – Unrelated String Oct 9 '19 at 1:00
  • 1
    \$\begingroup\$ Wow I am impressed with the language and thanks for explaining about the consonant/vowel system, interesting stuff. But this challenge still seems too complicated. :O \$\endgroup\$ – Mitch McMabers Oct 9 '19 at 16:09
  • \$\begingroup\$ Very cool challenge. I am going to try this on the weekend. Any entry, no matter how long, beats no entries! \$\endgroup\$ – Mahkoe Jan 22 at 23:22
8
\$\begingroup\$

C, 1832 bytes

Well, this is the first time I've ever golfed anything, and this is easily the ugliest code I have ever written:

(compiled with gcc 7.5.0)

#define C(x,y)case 0x##x:y;break;
#define c(x)case x:r=r<<6|getchar()&63;
#define F(x,n)for(x=0;x<n;x++)
#define M(n)"\e["#n"D\e[B"
#define m M(1)
#define U(n)"\e["#n"A"
#define l U(4)
char p[]={0,1,3,6,27,7,15,16,28,18,19,20,21,29,22,23,24,25,26},*H="---.-.-.-.,::   : --: --.------.-.-.-...-.::-.,:-..--...-.--.--.:  :::,: ,. ,:,: .. -.,- -- ---..----..- -- .-.-::::----   : : : ::::   : ,:: --:   .--'.' :.'::.'][.'::.':-.'][.'--:  ::--:[]:::  :::::(  ) ;: -,.----::--- :: ----: : [][],:,:   : : : :::'---'-::'-()'---'---'- :'-'''-'''-::'-'-'-'''-()'--''--''':::  ::::: '' '  `;  :   :'----''- () '-'-''''::::",*B=M(4),
#define P "    "U(3)
#define Q " :"M(2)"-^--"l
*U[]={P,P,P,P,P,P,P,P,Q,Q,Q,Q," ::"M(3)"-^^-"l,"-v--"M(4)" :  "l,"-v--"M(4)" :--"l,"-v--"M(4)" :--"l,"-v--"M(4)" :  "l,"-vv-"M(4)" :: "l,"----","    "M(4)"----"U(4),P},
#define X(x,y)x y x
#define Y(x,y)x y y
#define Z(x,y)x x y x 
#define R "\e[4B"M(4)
#define S Z(":"m,":"m)":"M(4)
*V[]={X(":"m,":-"M(2))":"M(4),X(": :"M(3),":-:"M(3))": :"M(6),Y(":"m,":-"M(2))":"M(4),Y(": :"M(3),":-:"M(3))": :"M(6),X(" :"M(2),"-:"M(2))" :"M(5),X(" ::"M(3),"-::"M(3))" ::"M(6),Y(" :"M(2),"-:"M(2))" :"M(5),Y(" ::"M(3),"-::"M(3))" ::"M(6),R,Z(":"m,":-"M(2))":"M(4),Z(": :"M(3),":-:"M(3))": :"M(6),S,R,R,S,Z("::"M(2),"::"M(2))"::"M(5),S,R,M(4),S,Z(":"m,":"m)"\e[3D"},
#define w(m,n)"\e["#m"C"U(n)
#define T w(7,7)
#define W w(8,7)
#define x w(6,8)
*A[]={T,W,T,W,T,W,T,W,x,w(7,8),w(7,8),x,x,x,x,w(7,8),x,x,x,x,x};
#define D(x) printf(x);
g(){int r=getchar(),n=~0;switch(r>>4){C(f,n=7)C(e,n=15)C(d,C(c,n=31))}r&=n;switch(n){c(7)c(15)c(31)}return r;}main(){D("\e[2J\e[H")int n,j,k,t,v,h;while(~(n=g())){if(n>>8){n-=44032;t=n%28;v=n/28%21;h=p[n/588];F(j,3){F(k,4)putchar(H[(j*30+h)*4+k]);D(B)}D(U[v])D(V[v])if(t--)F(j,3){F(k,4)putchar(H[(j*30+t)*4+k]);D(B)}else D("\e[3B")D(A[v])}}}

It only does style 2; the challenge was already difficult enough for me without needing to support all three styles! It's a shame though, because I'm really in love with the charming ASCII art the OP made (by the way, they forgot to provide art for the ㅃ jamo, so I made one myself).

You can see the project here: https://repl.it/@Mahkoe/hangul-ASCII-art

Brief hints for understanding the code

  • This makes heavy use of ANSI escape sequences for moving the cursor. The U(n) macro moves the cursor up by n characters, and the M(n) macro moves the cursor left by n characters then down by one. (U stands for "up", and M stands for "mot", which is French for "word").
  • Because U(4) appeared enough times, I defined l to U(4) (l doesn't stand for anything, it was just one of the few single-character identifiers left).
  • The g function reads stdin and parses out a UTF-8 sequence. It correctly returns EOF when it sees one.
  • The C and c macros are used to shorten the cases in the switch statements in the g function.
  • The H string contains all the tail consonants (copy-paste the string to a text file and break it into three 30-character wide lines to see it better). They are ordered according to increasing UTF-8 codepage addresses. (I originally called this string H because early on it only had head consonants, but the name stuck around even after I changed my mind and put in the tail consonants).
  • Some consonants are head-only consonants (ㄸ, ㅃ, and ㅉ), so I tacked these onto the "right-hand side" of H. The p array is a mapping from the head consonant number to the position in the H string. (I originally called this array p because I thought of it as a permutation, but the name stuck around after I realized it wasn't actually a permutation).
  • The vowels had so many special cases that I ended up splitting a vowel into three actions: the "underneath" (anything that would end up between the head and tail consonants), the rest of the vowel, and any adjustments needed to the cursor after drawing the tail consonant. These three quantities are stored in the U, V, and A strings, respectively.
  • If anything appeared often enough in the U, V, or A strings, I made a macro for it. This consists of the P, Q, R, S, T, W, w, and x macros (I started having name collisions, which is why the macro name pattern breaks after T).
  • All together, the main function eats characters from stdin until it gets an EOF. If it sees a Hangul character, it prints the head consonant, then the underneath, then the rest of the vowel, then the tail consonant, then the adjustment.

This challenge was delightful, and I'm really excited about having learned Hangul. Thanks!

\$\endgroup\$
4
  • 3
    \$\begingroup\$ Welcome to Code Golf! This is a seriously impressive first answer! \$\endgroup\$ – Redwolf Programs Jan 24 at 0:10
  • \$\begingroup\$ Nice first answer! I think you're eligible to claim this bounty. \$\endgroup\$ – Dingus Jan 24 at 0:12
  • \$\begingroup\$ Do also note what language it is (in this case it'd be # C, 1832 bytes) \$\endgroup\$ – bigyihsuan Jan 24 at 0:55
  • \$\begingroup\$ 1538 bytes \$\endgroup\$ – ceilingcat Feb 14 at 8:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.