Jelly , 309 byte trong mã hóa của Jelly
“Æ÷“¥s“ɲ“¡µ’;“ịƊ⁴çNṂ‘_\
OḌ;¢*5$%¥/µ“+⁷ż!¤ña¡jIȧƁfvḶg/Ọ=^ƝĠ0Ẇƭ³½N~=.Ɗ°ɗẇ⁵\ɦ*ɠPf⁾?ṾHḣ 2=⁹ƒ!©ƊĠṣƥ®Ƙ0Yƙ>!ȧtƊN0w,$ɠẎ46fẋ⁷(ṣẆm⁾ŻƓṫµsçwṣḂḲd0Ruṛ’ḃ21+\iµØW“&;:' ”;“¡3ȧ%⁾xƑ?{Ñṃ;Ċ70|#%ṭdṃḃ÷ƑĠẏþḢ÷ݳȦṖcẇọqƁe ʠ°oḲVḲ²ụċmvP[ỴẊẋ€kṢ ȯḂ;jɓỴẏeṾ⁴ḳḢ7Ẓ9ġƤṙb€xÇ4ɗ⁻>Ẉm!Ƈ)%Ḃẇ$ġ£7ȧ`ỵẈƘɗ¡Ṃ&|ƙƥ³ẏrṛbḋƙċ⁻ṁƲRṀẹṾ<ñ⁻Ṅ7j^ɓĊ’b58¤ị;0ị@
ḲÇ€t0”@;Ṫ
Hãy thử trực tuyến!
Tôi quyết định đã đến lúc tôi phải tự mình thực hiện thử thách. Việc sử dụng Jelly (và mã hóa 8 bit của nó) mang lại cho tôi lợi thế 12,5% so với các ngôn ngữ chỉ có ASCII và Jelly thuận tiện cho thử thách này do có các toán tử chuyển đổi cơ sở tích hợp với tên ngắn, nhưng phần lớn tiết kiệm là do thuật toán nén tốt hơn (chương trình này tính trung bình ít hơn một byte cho mỗi loại quái vật).
Thuật toán và giải thích
Phân loại dựa trên từ
Tôi quyết định rằng để có được điểm cao, cần phải tận dụng lợi thế của cấu trúc đầu vào hơn các mục khác. Một điều rất đáng chú ý là nhiều quái vật có tên thuộc dạng " loài tính từ "; a và a đều là hai loại rồng, và do đó xuất hiện dưới dạng . Một số quái vật khác có tên của dạng " công việc loài ", chẳng hạn như ; là một loại orc, điều này xuất hiện như . Các vấn đề phức tạp là xác sống; a vừa là kobold vừa là zombie, và trạng thái sau được ưu tiên trong việc đặt tên quái vật NetHack, do đó chúng tôi muốn phân loại nó thành .red dragon
blue dragon
D
orc shaman
o
kobold zombie
Z
Như vậy, tôi đã phân loại các từ xuất hiện trong tên quái vật như sau: chỉ báo là một từ gợi ý mạnh mẽ đến lớp quái vật thích hợp (ví dụ sphere
mạnh mẽ gợi ý rằng quái vật ở trong lớp e
); một từ mơ hồ là một từ mà làm cho ít của một gợi ý rất nhiều ( lord
không cho bạn biết nhiều), và tất cả các từ khác là nonwords mà chúng ta không quan tâm. Ý tưởng cơ bản là chúng ta nhìn vào các từ trong tên quái vật từ cuối trở về đầu và chọn chỉ số đầu tiên mà chúng ta thấy. Như vậy, cần phải đảm bảo rằng mỗi tên quái vật chứa ít nhất một chỉ số, được theo dõi hoàn toàn bằng những từ mơ hồ. Như một ngoại lệ, những từ xuất hiện trong tên của quái vật trông giống như một@
(nhóm lớn nhất) đều được phân loại là mơ hồ. Bất cứ điều gì có thể xuất hiện trước một chỉ số; ví dụ, tên màu (chẳng hạn như red
) luôn xuất hiện sớm hơn trong tên so với chỉ báo và do đó được coi là từ khóa (vì chúng không bao giờ được kiểm tra trong khi xác định danh tính của quái vật).
Cuối cùng, chương trình này đi xuống một bảng băm, giống như các chương trình khác làm. Tuy nhiên, bảng không chứa các mục nhập cho tất cả các tên quái vật hoặc cho tất cả các từ xuất hiện trong tên quái vật; đúng hơn, nó chỉ chứa các chỉ số. Các giá trị băm của các từ mơ hồ không xuất hiện trong bảng, nhưng phải được gán cho các vị trí trống (cố gắng tìm kiếm một từ mơ hồ sẽ luôn xuất hiện trống rỗng). Đối với từ khóa, không quan trọng là từ đó có xuất hiện trong bảng hay không, hoặc liệu hàm băm có va chạm hay không, bởi vì chúng ta không bao giờ sử dụng giá trị của việc tìm kiếm một từ không. (Bảng khá thưa thớt, vì vậy hầu hết các từ khóa không xuất hiện trong bảng, nhưng một số ít, chẳng hạn như flesh
, được tìm thấy trong bảng do hậu quả của va chạm băm.)
Dưới đây là một số ví dụ về cách phần này của chương trình hoạt động:
woodchuck
là một từ dài (do đó là một chỉ báo) và việc tra cứu bảng trên woodchuck
cho chúng ta câu trả lời dự định r
.
abbot
cũng là một từ dài, nhưng trông giống như một @
. Như vậy, abbot
được coi là một từ mơ hồ; việc tra cứu bảng xuất hiện trống rỗng và chúng tôi trả lời câu trả lời @
theo mặc định.
vampire lord
bao gồm một chỉ báo ( vampire
tương ứng với V
) và một từ mơ hồ ( lord
, không có trong bảng). Điều này có nghĩa là chúng tôi kiểm tra cả hai từ (theo thứ tự ngược lại), sau đó đưa ra câu trả lời đúng V
.
gelatinous cube
bao gồm một từ không ( gelatinous
tương ứng với H
do va chạm băm) và chỉ báo ( cube
, tương ứng với b
). Vì chúng ta chỉ lấy từ cuối cùng được tìm thấy trong bảng, điều này trả về b
, như mong đợi.
gnome mummy
bao gồm hai chỉ số, gnome
tương ứng G
và mummy
tương ứng với M
. Chúng tôi lấy chỉ số cuối cùng, và nhận được M
, đó là những gì chúng tôi muốn.
Mã để xử lý phân loại dựa trên từ là dòng cuối cùng của chương trình Jelly. Đây là cách nó hoạt động:
ḲÇ€t0”@;Ṫ
Ḳ Split on spaces
Ç€ Call function 2 (table lookup) on each entry
t0 Remove trailing zeroes (function 2 returns 0 to mean "not found")
”@; Prepend an @ character
Ṫ Take the last result
Có hai trường hợp thực tế; nếu đầu vào chỉ bao gồm các từ mơ hồ, hãy t0
xóa toàn bộ đầu ra của tra cứu bảng và chúng ta sẽ nhận được @
kết quả theo mặc định; nếu có các chỉ báo trong đầu vào, t0
sẽ xóa bất cứ thứ gì ở bên phải của chỉ báo ngoài cùng bên phải và Ṫ
sẽ cho chúng ta kết quả tương ứng cho chỉ báo đó.
Nén bảng
Tất nhiên, việc ngắt đầu vào thành các từ không tự giải quyết được vấn đề; chúng ta vẫn phải mã hóa sự tương ứng giữa các chỉ số và các lớp quái vật tương ứng (và thiếu sự tương ứng từ các từ mơ hồ). Để làm điều này, tôi đã xây dựng một bảng thưa thớt với 181 mục được sử dụng (tương ứng với 181 chỉ số; đây là một cải tiến lớn so với 378 quái vật!) Và tổng số 966 mục (tương ứng với 966 giá trị đầu ra của hàm băm). Bảng được mã hóa trong chương trình anh ta thông qua việc sử dụng hai chuỗi: chuỗi đầu tiên chỉ định kích thước của các "khoảng trống" trong bảng (không chứa mục nào); và chuỗi thứ hai chỉ định lớp quái vật tương ứng với mỗi mục. Cả hai đều được thể hiện một cách súc tích thông qua chuyển đổi cơ sở.
Trong chương trình Jelly, mã cho tra cứu bảng, cùng với chính chương trình, được thể hiện trong dòng thứ hai, từ dòng đầu tiên µ
trở đi. Đây là cách phần này của chương trình hoạt động:
“…’ḃ21+\iµØW“&;:' ”;“…’b58¤ị;0ị@
“…’ Base 250 representation of the gap sizes
ḃ21 Convert to bijective base 21
+\ Cumulative sum (converts gaps to indexes)
i Find the input in this list
µ Set as the new default for missing arguments
ØW Uppercase + lowercase alphabets (+ junk we ignore)
“&;:' ”; Prepend "&;:' "
“…’ Base 250 representation of the table entries
b58 Convert to base 58
¤ Parse the preceding two lines as a unit
i Use the table to index into the alphabets
;0 Append a zero
i@ Use {the value as of µ} to index into the table
Cơ sở sinh học 21 giống như cơ sở 21, ngoại trừ 21 là số hợp pháp và 0 không. Đây là một mã hóa thuận tiện hơn cho chúng tôi vì chúng tôi tính hai mục liền kề là có khoảng cách là 1, để chúng tôi có thể tìm thấy các chỉ mục hợp lệ thông qua tổng tích lũy. Khi nói đến phần của bảng chứa các giá trị, chúng ta có 58 giá trị duy nhất, vì vậy trước tiên chúng ta giải mã thành 58 số nguyên liên tiếp và sau đó giải mã lại bằng bảng tra cứu ánh xạ các giá trị này vào các ký tự thực tế đang được sử dụng. (Hầu hết đây là các chữ cái, vì vậy chúng tôi bắt đầu bảng tra cứu thứ cấp này với các mục không phải là chữ cái &;:'
, và sau đó chỉ thêm một hằng số Jelly bắt đầu bằng các chữ cái viết hoa và chữ thường; nó cũng có một số rác khác nhưng chúng tôi không quan tâm về điều đó.)
Giá trị sentinel "không tìm thấy" của Jelly, nếu bạn sử dụng nó để lập chỉ mục vào danh sách, sẽ trả về phần tử cuối cùng của danh sách; do đó, tôi đã thêm một số không (một số nguyên bằng 0, mặc dù bảng chủ yếu được tạo thành các ký tự) vào bảng tra cứu để đưa ra một thông báo thích hợp hơn để chỉ ra một mục bị thiếu.
Hàm băm
Phần còn lại của chương trình là hàm băm. Điều này bắt đầu đơn giản là đủ, vớiOḌ
; điều này chuyển đổi chuỗi đầu vào thành mã ASCII của nó và sau đó tính toán mã cuối cùng, cộng với 10 lần mã áp chót, cộng với 100 lần mã trước đó, v.v. (điều này có một đại diện rất ngắn trong Jelly vì nó được sử dụng phổ biến hơn như một chuỗi → hàm chuyển đổi số nguyên). Tuy nhiên, nếu chúng ta đơn giản giảm băm này trực tiếp thông qua thao tác mô đun, cuối cùng chúng ta sẽ cần một bảng khá lớn. Vì vậy, thay vào đó, tôi bắt đầu với một chuỗi các hoạt động để giảm bảng. Mỗi cái đều hoạt động như thế này: chúng ta lấy sức mạnh thứ năm của giá trị băm hiện tại; sau đó chúng ta giảm modulo giá trị một hằng số (hằng số phụ thuộc vào thao tác chúng ta đang sử dụng). Chuỗi này mang lại nhiều tiền tiết kiệm hơn (về việc giảm kích thước bảng kết quả) so với chi phí (về việc cần phải mã hóa chính chuỗi hoạt động), theo hai cách: nó có thể tạo bảngnhỏ hơn nhiều (966 thay vì 3529 mục) và việc sử dụng nhiều giai đoạn mang lại nhiều cơ hội hơn để giới thiệu các va chạm có lợi (điều này không xảy ra nhiều, nhưng có một xung đột như vậy: cả hai Death
và Yeenoghu
băm đến 806, do đó cho phép chúng tôi loại bỏ một nhập từ bảng, khi cả hai đi đến&
). Các mô-đun được sử dụng ở đây là [3529, 2163, 1999, 1739, 1523, 1378, 1246, 1223, 1145, 966]. Ngẫu nhiên, lý do để tăng sức mạnh thứ năm là vì nếu bạn chỉ lấy giá trị trực tiếp, các khoảng trống có xu hướng giữ nguyên kích thước, trong khi lũy thừa di chuyển các khoảng trống xung quanh và có thể khiến bảng có thể được phân phối đều hơn sau chuỗi thay vì bị mắc kẹt trong một mức tối thiểu cục bộ (các khoảng trống phân bố đồng đều hơn cho phép mã hóa các kích thước khoảng cách hơn). Đây phải là một sức mạnh kỳ lạ để ngăn chặn thực tế rằng x ² = (- x ) ² giới thiệu va chạm và 5 hoạt động tốt hơn 3.
Dòng đầu tiên của chương trình mã hóa chuỗi các mô đun bằng mã hóa delta:
“…’;“…‘_\
“…’ Compressed integer list encoding, arbitrary sized integers
; Append
“…‘ Compressed integer list encoding, small integers (≤ 249)
_\ Take cumulative differences
Phần còn lại của chương trình, bắt đầu của dòng thứ hai, thực hiện hàm băm:
OḌ;¢*5$%¥/
O Take ASCII codepoints
Ḍ "Convert from decimal", generalized to values outside the range 0-9
;¢ Append the table of moduli from the previous line
/ Then reduce by:
*5$ raising to the power 5 (parsing this as a group)
%¥ and modulusing by the right argument (parsing this as a group, too).
xác minh
Đây là tập lệnh Perl tôi đã sử dụng để xác minh rằng chương trình hoạt động chính xác:
use warnings;
use strict;
use utf8;
use IPC::Run qw/run/;
my %monsters = ("Aleax", "A", "Angel", "A", "Arch Priest", "@", "Archon", "A",
"Ashikaga Takauji", "@", "Asmodeus", "&", "Baalzebub", "&", "Chromatic Dragon",
"D", "Croesus", "@", "Cyclops", "H", "Dark One", "@", "Death", "&", "Demogorgon",
"&", "Dispater", "&", "Elvenking", "@", "Famine", "&", "Geryon", "&",
"Grand Master", "@", "Green-elf", "@", "Grey-elf", "@", "Hippocrates", "@",
"Ixoth", "D", "Juiblex", "&", "Keystone Kop", "K", "King Arthur", "@",
"Kop Kaptain", "K", "Kop Lieutenant", "K", "Kop Sergeant", "K", "Lord Carnarvon",
"@", "Lord Sato", "@", "Lord Surtur", "H", "Master Assassin", "@", "Master Kaen",
"@", "Master of Thieves", "@", "Medusa", "@", "Minion of Huhetotl", "&",
"Mordor orc", "o", "Nalzok", "&", "Nazgul", "W", "Neferet the Green", "@", "Norn",
"@", "Olog-hai", "T", "Oracle", "@", "Orcus", "&", "Orion", "@", "Pelias", "@",
"Pestilence", "&", "Scorpius", "s", "Shaman Karnov", "@", "Thoth Amon", "@",
"Twoflower", "@", "Uruk-hai", "o", "Vlad the Impaler", "V", "Wizard of Yendor",
"@", "Woodland-elf", "@", "Yeenoghu", "&", "abbot", "@", "acid blob", "b",
"acolyte", "@", "air elemental", "E", "aligned priest", "@", "ape", "Y",
"apprentice", "@", "arch-lich", "L", "archeologist", "@", "attendant", "@",
"baby black dragon", "D", "baby blue dragon", "D", "baby crocodile", ":",
"baby gray dragon", "D", "baby green dragon", "D", "baby long worm", "w",
"baby orange dragon", "D", "baby purple worm", "w", "baby red dragon", "D",
"baby silver dragon", "D", "baby white dragon", "D", "baby yellow dragon", "D",
"balrog", "&", "baluchitherium", "q", "barbarian", "@", "barbed devil", "&",
"barrow wight", "W", "bat", "B", "black dragon", "D", "black light", "y",
"black naga hatchling", "N", "black naga", "N", "black pudding", "P",
"black unicorn", "u", "blue dragon", "D", "blue jelly", "j", "bone devil", "&",
"brown mold", "F", "brown pudding", "P", "bugbear", "h", "captain", "@",
"carnivorous ape", "Y", "cave spider", "s", "caveman", "@", "cavewoman", "@",
"centipede", "s", "chameleon", ":", "chickatrice", "c", "chieftain", "@",
"clay golem", "'", "cobra", "S", "cockatrice", "c", "couatl", "A", "coyote", "d",
"crocodile", ":", "demilich", "L", "dingo", "d", "disenchanter", "R", "djinni",
"&", "dog", "d", "doppelganger", "@", "dust vortex", "v", "dwarf king", "h",
"dwarf lord", "h", "dwarf mummy", "M", "dwarf zombie", "Z", "dwarf", "h",
"earth elemental", "E", "electric eel", ";", "elf mummy", "M", "elf zombie", "Z",
"elf", "@", "elf-lord", "@", "energy vortex", "v", "erinys", "&", "ettin mummy",
"M", "ettin zombie", "Z", "ettin", "H", "fire ant", "a", "fire elemental", "E",
"fire giant", "H", "fire vortex", "v", "flaming sphere", "e", "flesh golem", "'",
"floating eye", "e", "fog cloud", "v", "forest centaur", "C", "fox", "d",
"freezing sphere", "e", "frost giant", "H", "gargoyle", "g", "garter snake", "S",
"gas spore", "e", "gecko", ":", "gelatinous cube", "b", "ghost", " ", "ghoul",
"Z", "giant ant", "a", "giant bat", "B", "giant beetle", "a", "giant eel", ";",
"giant mimic", "m", "giant mummy", "M", "giant rat", "r", "giant spider", "s",
"giant zombie", "Z", "giant", "H", "glass golem", "'", "glass piercer", "p",
"gnome king", "G", "gnome lord", "G", "gnome mummy", "M", "gnome zombie", "Z",
"gnome", "G", "gnomish wizard", "G", "goblin", "o", "gold golem", "'",
"golden naga hatchling", "N", "golden naga", "N", "gray dragon", "D", "gray ooze",
"P", "gray unicorn", "u", "green dragon", "D", "green mold", "F", "green slime",
"P", "gremlin", "g", "grid bug", "x", "guard", "@", "guardian naga hatchling",
"N", "guardian naga", "N", "guide", "@", "healer", "@", "hell hound pup", "d",
"hell hound", "d", "hezrou", "&", "high priest", "@", "hill giant", "H",
"hill orc", "o", "hobbit", "h", "hobgoblin", "o", "homunculus", "i",
"horned devil", "&", "horse", "u", "housecat", "f", "human mummy", "M",
"human zombie", "Z", "human", "@", "hunter", "@", "ice devil", "&", "ice troll",
"T", "ice vortex", "v", "iguana", ":", "imp", "i", "incubus", "&", "iron golem",
"'", "iron piercer", "p", "jabberwock", "J", "jackal", "d", "jaguar", "f",
"jellyfish", ";", "ki-rin", "A", "killer bee", "a", "kitten", "f", "knight", "@",
"kobold lord", "k", "kobold mummy", "M", "kobold shaman", "k", "kobold zombie",
"Z", "kobold", "k", "kraken", ";", "large cat", "f", "large dog", "d",
"large kobold", "k", "large mimic", "m", "leather golem", "'", "lemure", "i",
"leocrotta", "q", "leprechaun", "l", "lich", "L", "lichen", "F", "lieutenant",
"@", "little dog", "d", "lizard", ":", "long worm", "w", "lurker above", "t",
"lynx", "f", "mail daemon", "&", "manes", "i", "marilith", "&", "master lich",
"L", "master mind flayer", "h", "mastodon", "q", "mind flayer", "h", "minotaur",
"H", "monk", "@", "monkey", "Y", "mountain centaur", "C", "mountain nymph", "n",
"mumak", "q", "nalfeshnee", "&", "neanderthal", "@", "newt", ":", "ninja", "@",
"nurse", "@", "ochre jelly", "j", "ogre king", "O", "ogre lord", "O", "ogre", "O",
"orange dragon", "D", "orc mummy", "M", "orc shaman", "o", "orc zombie", "Z",
"orc", "o", "orc-captain", "o", "owlbear", "Y", "page", "@", "panther", "f",
"paper golem", "'", "piranha", ";", "pit fiend", "&", "pit viper", "S",
"plains centaur", "C", "pony", "u", "priest", "@", "priestess", "@", "prisoner",
"@", "purple worm", "w", "pyrolisk", "c", "python", "S", "quantum mechanic", "Q",
"quasit", "i", "queen bee", "a", "quivering blob", "b", "rabid rat", "r",
"ranger", "@", "raven", "B", "red dragon", "D", "red mold", "F",
"red naga hatchling", "N", "red naga", "N", "rock mole", "r", "rock piercer", "p",
"rock troll", "T", "rogue", "@", "rope golem", "'", "roshi", "@", "rothe", "q",
"rust monster", "R", "salamander", ":", "samurai", "@", "sandestin", "&",
"sasquatch", "Y", "scorpion", "s", "sergeant", "@", "sewer rat", "r", "shade", " ",
"shark", ";", "shocking sphere", "e", "shopkeeper", "@", "shrieker", "F",
"silver dragon", "D", "skeleton", "Z", "small mimic", "m", "snake", "S",
"soldier ant", "a", "soldier", "@", "spotted jelly", "j", "stalker", "E",
"steam vortex", "v", "stone giant", "H", "stone golem", "'", "storm giant", "H",
"straw golem", "'", "student", "@", "succubus", "&", "tengu", "i", "thug", "@",
"tiger", "f", "titan", "H", "titanothere", "q", "tourist", "@", "trapper", "t",
"troll", "T", "umber hulk", "U", "valkyrie", "@", "vampire bat", "B",
"vampire lord", "V", "vampire", "V", "violet fungus", "F", "vrock", "&", "warg",
"d", "warhorse", "u", "warrior", "@", "watch captain", "@", "watchman", "@",
"water demon", "&", "water elemental", "E", "water moccasin", "S", "water nymph",
"n", "water troll", "T", "werejackal", "d", "wererat", "r", "werewolf", "d",
"white dragon", "D", "white unicorn", "u", "winged gargoyle", "g",
"winter wolf cub", "d", "winter wolf", "d", "wizard", "@", "wolf", "d",
"wood golem", "'", "wood nymph", "n", "woodchuck", "r", "wraith", "W", "wumpus",
"q", "xan", "x", "xorn", "X", "yellow dragon", "D", "yellow light", "y",
"yellow mold", "F", "yeti", "Y", "zruty", "z");
for my $monster (sort keys %monsters) {
run ["./jelly", "fu", "monsters.j", $monster], \ "", \my $out;
print "$monster -> \"$out\" (",
($out ne $monsters{$monster} ? "in" : ""), "correct)\n";
}
mail daemon
> _ <