# Biggest katlani noun dictionary in 400 bytes

Katlani is a constructed language being designed in chat. In this challenge, your goal is to print the largest dictionary of katlani nouns possible in 400 bytes or less.

In 400 bytes or less, your program should print a list of katlani nouns. You can choose to output them as a list/array in your language, or as a string with any (not necessarily consistent) non-alphabetical separator, such as newlines or commas. The capitalization and sorting of the words does not matter. Words not in the list are not allowed in the output, but duplicates are.

The list of nouns you may choose from are:

abail
abikis
ak
akniton
alfabit
atirsin
atom
ats
aypal
baka
baklait
banl
bgil
bianto
bit
bo
boraky
borsh
bot
br
brbrno
byt
daosik
diga
digiz
dogo
dolmuk
dongso
douv
drarkak
fa
fafasok
fasmao
fidr
floria
fridka
friv
fully
fylo
fyrus
gilmaf
gogu
gogzo
gongul
gorlb
gosio
gratbt
gutka
hisi
horrib
hurigo
inglish
iomshuksor
isa
ispikar
isplo
ita
iushb
izlash
kaikina
kat
katisas
katlani
kfaso
khalling
kisongso
kivsk
klingt
kod
koik
kolbat
komy
konma
korova
koss
kotsh
kris
kromir
ksik
ksuz
ktaf
ktomish
ktomizo
la
lan
lgra
lyly
mak
makanto
makav
makina
marinolus
marta
matiks
mim
mimhis
mingso
mitsh
molo
mosdob
motif
motkop
movogal
muratsh
mutka
naita
ngoirfo
nidriok
nilo
nin
nini
ninibr
nirus
noguna
nolif
nors
o
ogig
omkop
onion
opru
orilha
orni
ozon
papin
paslo
pasrus
pirishy
pluban
polr
posodo
pouk
produty
rak
raznitsa
rigiks
rilifior
riomr
rno
ronta
rus
ryby
sabbia
sai
sakar
saman
sandvitsh
sasa
sfiny
shatris
shidoso
shilan
shimshoom
shor
shotiya
shuan
shubhu
shuksor
shuriok
shutis
shutrak
shyba
sibas
sibin
simriomr
sod
sokit
spamra
spamt
sutka
taika
tipstor
tizingso
tksu
tobl
tokvod
tomp
tonfa
toto
totobr
tshans
tshimiso
tshomp
tura
tuvung
uboiak
umub
vaf
vintz
voda
vodl
vontark
y
yntsh
zimdo
zivod
zombit
zorliplak


## Scoring

The winner (per language) is the answer that can print the largest number of unique words from the dictionary. Ties are broken by byte count, so if two answers manage to print all 200, the shorter of the two will win.

• I think you should allow duplicate words in the output, but simply not count any word more than once. It could allow for some interesting approaches with looser requirements. Jan 21 at 16:05
• @cairdcoinheringaahing Duplicates are now allowed Jan 21 at 16:08
• 400B is small enough that I strongly suspect you'll find that the best answer is to just use the best compression algorithm in the language's stdlib.
– TLW
Jan 22 at 0:43
• @TLW And those would be boring answers (I'd add a built-in ban if I weren't strongly opposed to those). But, at least for JS (the only practical language here so far), my answer with custom compression code is doing better than the zlib one. And anything more than 400 bytes wouldn't make inbuilt compression weaker, it would just make it so that more answers could fit the whole dictionary. Jan 22 at 4:04
• @taRadvylfsriksushilani - the main reason the custom decompressor is doing marginally better currently is because the zlib one is using base64 (which is a relatively inefficient encoding). Perhaps I should say (400B, 200w) is too small. (The main issue is that a zlib decoder a) is a half-decent solution and b) is (generally?) >400B, but is callable in far less than that. So custom solutions start at a major disadvantage...)
– TLW
Jan 23 at 19:16

# JavaScript (ES6), 400 bytes, 104 words

_=>oï�ño�÷�
��¯�¯�¯9�:�@¯p_�O��S_ÀOÅoË��?
hñ���WñÓÖÛò9?F4ôhïF�ôÃ�I4÷Ü�~~øgoSvõ5?VÉöÓßlSüáï��ù&Ï¤�úa¦¦ú¼�¸±ð�7ñl�ýlqýi6ýº@ó¹!ôe�ôj�ø� ø:�øº@õ� õ<¹öSeü6�üe ù��ù��ù+�ù.�ù1    ù15ùd:ùº@ú�@þZ�ð�C���¦ñl�ï��VýeÛÜ
�òlÃ�+ÃÖôs]¯Fq
ôÆ�Ï�CPø


Almost certainly going to get mangled due to all the weird Unicode, but this uses a string of bytes, which if represented with an extended ASCII code page (like the one HTML defaults to) would be exactly 290 bytes. The other 110 are a decoder, which split each byte into 4-bit nibbles, and map them to one of 15 letters or a comma.

The problem is, this is exactly 400 bytes, leaving no room for backslashes in the string. JS is pretty good at ignoring control characters and stuff in strings, so all I need to worry about is \0 (NUL), \r (which is mangled by newline conversion), , and \.

I could sacrifice a few words, and escape these with \, but that seemed like a bit of a waste. The solution I came up with was figuring out the representation of these four characters as nibbles (00, 0d, 5c, and 60), and all of the pairs of letters in the words that never appeared beside each other. Then, I could map those letter pairs to the bytes I didn't want to appear. I ended up with a for 0, g for d, n for 5, r for c, and o for a. since aa, ag, nr, and oa never appear in the list of 104 words I chose.

• Can you add a TIO link? (for copy-and-pasting) Jan 21 at 18:37
• @emanresuA Not for the next few hours, but I will when I get home Jan 21 at 18:37

# JavaScript (Node.js), 399 bytes, 96 words

Simple zlib compression with base-64 encoding. Returns a single string of words separated with _.

_=>require('zlib').inflateRawSync(Buffer("HY+BCgQhCEQ/dTBiOylz0TrY/fqbDppnipYjHbLciESRLsQcKE0JXSjOE/khmQTKs1C1Cao3J2bLE/YXl+DSGrhCK59hYG2P8eB6hhOxE83bPnidjFHIVN734sjHI7RAU6ibM7oEXRa6V0o7YQ8xjXUP/56QSSxu2EN5zdOW+0VfcmEIz8RoITDpVPBNU6POjDm/MV/db9h/iamsTJ1H+gddTx96kZFweNMGtzPiU33C79jwYLu/TG8fQeyO4I+hboGYjuM/RakuQRoXS6HZpHFil89meAorWoTNtJ23GHc/YWHRGJaXQdhNLP+DG9KMzMS2XfD1KgcDD1616iTTHw","base64"))+''


Try it online!

### How?

This is the result of a random search where each iteration keeps a word $$\W\$$ of length $$\L\$$ if a random value $$\k\in[0\dots1]\$$ satisfies:

$$k>\frac{(L-1)^2}{30}$$

This is really just a guesstimate that keeps all one-letter words, discards all words of more than 6 characters and uses probabilities between 17% and 97% in between.

• Question says you can choose any non-alphabetical separator, which saves 11 bytes and probably allows a few more words Jan 21 at 18:42
• @emanresuA Thanks for the notification! Updated. Jan 21 at 18:55

# Charcoal, 400 bytes, 139 words

Try it online! Link is to verbose version of code. Just a compressed string based on @ovs's Bubblegum word list, except deciding which nine words to drop was interesting to say the least, as deleting some words actually increases the byte count!

# Bubblegum, 147148 149 words, 400 bytes

00000000: 15cc 810a c520 0885 e157 3dc6 5893 4a87  ..... ...W=.X.J.
00000010: d685 f6f4 f704 f9fd cd41 b25f e990 227a  .........A._.."z
00000020: d4a6 0999 3e08 2f0d 459a 10eb 2855 898a  ....>./.E...(U..
00000030: 4d67 260a e321 6d9f e443 b9db 9ce0 2961  Mg&..!m..C....)a
00000040: 8e4b ab7e 47c1 e5d5 89d5 3c59 3fdc c293  .K.~G.....<Y?...
00000050: 431c 77e8 d5e4 845b bd02 f7ea 7de3 dedd  C.w....[....}...
00000060: 49ac 44f5 ba0e 9f53 abab 33d1 0b4d e56a  I.D....S..3..M.j
00000070: cd26 7834 158f 4768 814e 81e6 99b7 3b74  .&x4..Gh.N....;t
00000080: e5c3 ddd7 251f 3499 685d ad32 7e71 b491  ....%.4.h].2~q..
00000090: b149 2f32 99f0 9f30 368e 331f 9a89 163e  .I/2...06.3....>
000000a0: 3418 e53d b591 f5a1 4db9 d185 c7d0 6bf0  4..=....M.....k.
000000b0: b2fb c690 7646 7e47 3561 6252 1d8f e609  ....vF~G5abR....
000000c0: c76a 3a73 de1f de9d e4e5 8599 cddf 13bd  .j:s............
000000d0: 31d6 6c02 139d 54bb 133b a338 9460 6225  1.l...T..;.8.b%
000000e0: cceb 3261 bade 3412 0eaf 5ae1 e3bc e5a6  ..2a..4...Z.....
000000f0: 6ef0 3716 3cb4 3fc2 98c2 3f6e 5f79 f598  n.7.<.?...?n_y..
00000100: e79d b7af 22fc f2f4 cb99 1e64 3584 70b4  ...."......d5.p.
00000110: 6a4b c647 20cc 116e 5310 8bbb 5d36 524a  jK.G ..nS...]6RJ
00000120: 5161 94d3 24e8 10a3 c9e5 adb6 918f 7631  Qa..$.........v1 00000130: c683 2cb1 6379 d6c9 d464 7611 a416 c9a3 ..,.cy...dv..... 00000140: 1ad2 9b4e 7a21 5f19 2138 e122 3484 bb35 ...Nz!_.!8."4..5 00000150: 9b60 8a1e 5b2e 4c2f 9db4 9f5f cc78 89dd ...[.L/..._.x.. 00000160: 42a7 e350 0233 1fb1 3cf1 f37f 8590 dfb2 B..P.3..<....... 00000170: 8a55 5ca5 618d 55f0 931b 3fb5 f981 4fc9 .U\.a.U...?...O. 00000180: a163 63db cc07 9f8e cb29 97f8 7c14 9d7f .cc......)..|...  Try it online! General compression algorithm baseline. Prints all words of length up to 4, most of length 5 and some of length 6. The words are separated by . The actual words of length 5 and 6 are found with a very basic random search, but the quantities of each length are just guesses. The order of the words is mostly alphabetic, but I moved some words around by hand. I can't really tell why moving some words yields an improvement, but I was able to save 1 or 2 bytes by experimentation. I'm sure a better result could be achieved by a more systematic and automatic search. The list is compressed with zopfli -c --deflate --i300000 words.txt. # Nibbles, 161 words, 400 bytes. .=\\<159\D 6+~"o y"D 21*"sh"%!|;@#$4+~:/@5<+$~;@=" "$$45f31d2e733373ab092b79e7b544370bc7a0e362d8beeb825fe11e496df679b92e76991f03d6bc7f4389125c5b3648e326c221e31340945b6a79d28e6cbafaf177dccffd45c3e0e544365a8c973aed312eb485f57c8d861d18c62044842f41b7db23a106ede98d24c314c9d979ba388abeed82b04e848d8a9b6e44aafbb4bc0a7eae60687b13ecba3c0c240b05f7a0b2910a1843ca0af8f46849d9a565d695255ae19b2c954869ba9662723e903f422af11ef182dc00343885921657571bd40757f46ba10eda6a60e78c37ba913f26c93db1c2e1b9714d6c2601f504eba9cb0fff65d060cf08156986b079ae1046cd3dc1415a1daad9d57a79d13a271c9bc788631440d1ee118a40099517ce55c1389854cf0afa17ad73765d017de916abb93abfa49ff8d2d77382ab8f89db95a4ff8ce929bccd1435a1c98f9af7e67fe1847e6cdb348fad50d8c2c7ed5efd26bf7b838a985bc0bffe0a5168fcad28060f974b40c7dcf00b562ed1cbc3937ce387e71f  That's 64 nibbles of code and 736 hex digits of data at half a byte for each. Nibbles isn't on TIO yet, but run it like this: nibbles words.nbl < /dev/null  Ungolfed version:  .=\ \ <159 \D 6 + ~"o y" D 21 \c unused dat *"sh"%! |fstLine # 4 #" abdfghiklmnoprstuvyz" +~:/c 5 sets m <+m~ dat sets w = " " w  (hex data is the same) The method is essentially to encode each letter in base 21 data, but with 1 key trick. Notice these two inefficiencies with that trivial encoding. • If the list is sorted then the next first letter is the same or 1 more. • Spaces are by far the most common With the trick, a space and the next first letter combined can be encoded with a single base 6 digit! That's a savings of 125 bytes of data. First sort the words alphabetically by first character and length as the tie breaker. Now compute difference in length of words, with 6 added if they differ in starting letter. These numbers now encode what the next words length and starting letters are. So if the last word was "ats" and the digit is 2, it means the next word also starts with 'a' but has length 5. Now if the next digit is 2, it means the next word starts with 'b' and is length 3. That is because there are no 7+ letter words and no 1 letter words encoded (o and y are handled specially for this reason). One problem I ran into is there are only 160 words < 7 in length. But if we handle even one 7 letter word the above method would need base 7 digits which would add about 5 bytes of data. To get around this I encode all "sh" as spaces, which effectively makes words with sh in them shorter. That's the most common letter combo (used 23 times in the words used), but this trick doesn't really save much because it increases the base that the letters are encoded as and requires code to convert back. Each use saves one base 21 digit (-12.5 bytes), but requires base 21 instead of 20 (+5 bytes), and the decoding code is *"sh"% WORD_GOES_HERE " " which is 5 bytes. The next most common combo (15ish occurrences) isn't common enough to save anything unless the decoding process becomes more efficient. The way the base 21 list and base 6 list are encoded is using nibbles data feature which lets you encode a single number after your program with no terminators possible (normal numbers would use 1 bit of every 4 to terminate or not). This is a pure number not a list, but can be extracted to a desired base using D <base>. But since the data needs to be used for both lists, we reverse it for one of them and truncate it. The non truncated list will have garbage data at the end, but this will never be consumed the way the program is written. There's another useful trick that saves about 8 bytes which is how the alphabet is encoded which is: " abdfghiklmnoprstuvyz" Rather than encode this directly, we use luck. The Nibbles hash function # also uses data as salt, so if we have enough degrees of freedom in our encoding then we can create a hash that will deterministically map: " abcdefghijklmnopqrstuvwxyz" to "111010111101111110111110011" so that after filtering it, it becomes " ab d fghi klmnop rstuv yz" (without the spaces)  The probability that this mapping occurs is (1/4)**7*(3/4)**20 if we take the hash value mod 4 and use 0 as false and 1 2 3 as true. This is about 1 in 5 million. Notice that we can permute sets of words that have the same starting letter and length. This will change the encoded data, but will still give a correct output. There are also multiple 6 letter words that aren't used (now that sh is 1 letter), so that is another degree of freedom. Luckily this only takes about 1 hour to find with brute force search on random permutations of the starting words. Here's the code to find it:  # removed o y let uwords |.%"abail abikis ak akniton alfabit atirsin atom ats aypal baka baklait banl bgil bianto bit bo boraky borsh bot br brbrno byt daosik diga digiz dogo dolmuk dongso douv drarkak fa fafasok fasmao fidr floria fridka friv fully fylo fyrus gilmaf gogu gogzo gongul gorlb gosio gratbt gutka hisi horrib hurigo inglish iomshuksor isa ispikar isplo ita iushb izlash kaikina kat katisas katlani kfaso khalling kisongso kivsk klingt kod koik kolbat komy konma korova koss kotsh kris kromir ksik ksuz ktaf ktomish ktomizo la lan lgra loshad lyly mak makanto makav makina marinolus marta matiks mim mimhis mingso mitsh molo mosdob motif motkop movogal muratsh mutka naita ngoirfo nidriok nilo nin nini ninibr nirus noguna nolif nors ogig omkop onion opru orilha orni ozon papin paslo pasrus pirishy pluban polr posodo pouk produty rak raznitsa rigiks rilifior riomr rno ronta rus ryby sabbia sai sakar saman sandvitsh sasa sfiny shatris shidoso shilan shimshoom shor shotiya shuan shubhu shuksor shuriok shutis shutrak shyba sibas sibin simriomr sod sokit spamra spamt srirad sutka taika tipstor tizingso tksu tobl tokvod tomp tonfa toto totobr tshans tshimiso tshomp tura tuvung uboiak umub vaf vintz voda vodl vontark yntsh zimdo zivod zombit zorliplak"~ \w ?==w "yntsh" w *" "%w"sh" # don't convert this word because the jump to zimdo would be 6 then - 7 , hex / |.,~ \i let words +=~ uwords \w # :w i 4273 # this essentially permutes the words randomly # permuting randomly is more efficient than searching through permutations in order as small changes will actually likely map to the same encoding (i.e. if you swap words of different lengths that will get undone during the encode process). let takewords 159 let bestchars -" abdfghiklmnoprstuvyz" "" let selectedwords | | words ~ \w | w ~ \l ? bestchars l - 7, let nc ,bestchars let bestwords < takewords +=~ selectedwords , let sortedwords +=~ +=~ bestwords , =1 let tailed .sortedwords>> let lens \:1 ! sortedwords >>sortedwords ~ \w1 w2 let lengthdiff -,w2,w1 let chardiff - ?bestchars =1w2 ?bestchars=1w1 +lengthdiff *5 chardiff let data . sortedwords \word let wd ! bestchars word ? >>. wd \c1 -c1~ let d1 @ nc +data let d2 @ 6 lens let d1p *d1 ^nc ,@ nc d2 +d1p % -d2 @ 6 \<,lens \@ 6 d1p ^6 takewords \fd * ==| " abcdefghijklmnopqrstuvwxyz" \c #~ :o c @ 256 fd 4 " abdfghiklmnoprstuvyz" - 737 ,hex fd # max size 736 (sometimes it is 737 for unknown reasons)  Other ideas: Remove z, this was a complete wash because z is in some short words. I considered using something like huffman encoding since some letters are common and others rare. It would save about 30 bytes of data, but now you have to encode at least the order of commonness of the alphabet (and then assume some function of probability on it, it is actually pretty linear though). That would take at least 10 bytes. I don't think that leaves enough to decode and save anything. I'm kind of surprised this method did so well without really finding any other patterns in the data. But it doesn't seem like there are any other obvious patterns that are so strong to be worth the extraction code. # Vyxal, 399 bytes, 85 words ab₴⁋ ak ƈ¶ ₴ǒ ay₃⁺ b√ṫ b□× b£ṫ Ǎ₂ǎǏ °ẋ bo b⋎≈h ǍĊ br Ǎ∩ d⋏ė d⋏ḟz d꘍τ ›¢£ǎ ∩ḟv fa ⊍½…ƈk ⊍†Ǐẏ f⋏ø ⊍¾≥‹ fȦ‹ka ß≠v ↔¥ fƒİ fy≥₃ £ṫǏ⟨ g꘍ȧ £₆zo £§£Ḣ g⋎Ċb go∪ḋ gr₴↵t £Ȧka ¥₈≥ḟ ¥Ġ⋏ġ ḋ₌l⋏÷ ₍₴ i∪…kar isɖ„ ↲₍ iꜝ⁺b izl⁋‛ Ṅ⋎k⋏£ kat kµ₴Ẇ≠ k₴≬…„ kf…ƈ k€Ḟḋ₌ ki↔Ṡo kivsk klḋ₌t kod koik kolḂṙ k꘍¼ koǏṗ k⋎§va koss k⋎Ṡh k≥τ kroǏḂ ksik ksuz k≠ʁ k¢‹⋏÷ kt꘍⁽zo la ȯ¡ l£Ẇ †ṫλ‡ lƒṖ mak m√ṫv s¥₈ shꜝø ∪Ǐǎ⌐ ∪Ǐ≠ḣ shƒ≠ siǍḟ si½ǔ  Try it Online! # 05AB1E, 126 words, 399 bytes .•2Z₃LSι#@#«Σ±ñÿ˜¸‚÷ý…qÄнβŠŒäãΣαÑz@W|RÈÚ<¸´_£]ºRùƒl®нJë2k‘ƶ9žΔÍ2s0õÙ{óžM¨àWhà —'ïš<G¾¯×c†}À|Òé´8N/§j::&βxΓ"oÑ.ðË¡ÄΛ™ζÒ₅¬]õ2b?ç9.d€γβвΣ;θǝØ,ó=-ž4ó§¸™₃λ¬ÍÕ~Oì&^uÜ≠¥ƒvé©^Ûïæ(7I†=^;L½ÃÜ-+ÙXe‡¯ÚŒ†zÏZ₁≠pxÎUθè±t&∊s†è-ÚÎîÓEd£¤Áà³à^]I>ûr\ú±ÉþÏ˜2ƒv´g¸>[—üéÃ≠JQG0(*ŠØ²DƵδтÕây/Y*.¤\4hVÌè¯ʒ<ÊvßëĀиðθH₆÷aΔθåŸнā₅·…˜l’ƶ8¥þ“Àöë₄æ*b₁¤—εÒ¥QëQÒeн≠Càz”9†Í=<Xóγ¯mpð]BIÅтîƒ6ƒ°ĆAćγΣß”/8#Dv:‡‘{zƒƒF?¼[v¡bËδvÍ¸špîÈfa÷ÆðÛн‹  Try it online! # Python, 46 words (397 bytes) import base64;print(base64.b85decode(b'VPauvY#?DX=b7AYp56X>@OHAYp7~VPa?AYpWAa&u{JAYpWGZ6INEb0A@PaA9m9Vqt4xAYx%_Y+-41AYx%|Y#?H1X>1^3X<=@3Zy;i6bRc4Ha#EAYyNFb7&x9Z*(AHav)-IVsdV8AYyrRAY@^0b7^ZJWNBw%AY^H0X?h@JZ)a~HWN&P3b!#AGZ*FIEZy;oEb#@?Ra$$07VQU~}VP;-Z)+fCVRLO^Zy;uAWO5*8Y;SUDVIXF5X=H0*AZBuDb|7YTY;1WTW_fIHAZB@Tb#owRX>4s_W*}#8XLTTFZ)bXMAZKrGXLW2KXK!+BVjyR4b7^lNXL4b5Vss#9b#!ZCAZTfGX&8Ca&l>6'))  The base85 encoded text, for testing: VPauvY#?DX=b7AYp56X>@OHAYp7~VPa?AYpWAa&u{JAYpWGZ6INEb0A@PaA9m9Vqt4xAYx%_Y+-41AYx%|Y#?H1X>1^3X<=@3Zy;i6bRc4Ha$#$EAYyNFb7&x9Z*(AHav)-IVsdV8AYyrRAY@^0b7^ZJWNBw%AY^H0X?h@JZ)a~HWN&P3b!#AGZ*FIEZy;oEb#@?Ra$\$07VQU~}VP;-Z)+fCVRLO^Zy;uAWO5*8Y;SUDVIXF5X=H0*AZBuDb|7YTY;1WTW_fIHAZB@Tb#owRX>4s_W*}#8XLTTFZ)bXMAZKrGXLW2KXK!+BVjyR4b7^lNXL4b5Vss#9b#!ZCAZTfGX&8Ca&l>6
`

Try it online