果冻,果冻编码中的309个字节
“Æ÷“¥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”@;Ṫ
在线尝试!
我认为是时候该挑战自己了。与仅使用ASCII的语言相比,使用Jelly(及其8位代码页)给我带来了12.5%的优势,并且Jelly拥有内置的带有短名称的基本转换运算符,因此可以轻松应对这一挑战,但是大部分节省了归功于更好的压缩算法(每种怪物平均该程序的字节数少于一个字节)。
算法与解释
基于单词的分类
我认为,为了获得良好的成绩,必须比其他条目更多地利用输入的结构。一件非常值得注意的事情是,许多怪物的名字都以“ 形容词 种 ” 的形式出现。a red dragon
和a blue dragon
都是龙的类型,因此显示为D
。其他一些怪物则以“ 种 工作 ” 的形式命名,例如orc shaman
;。是一种兽人,显示为o
。复杂的事情是不死的;a kobold zombie
既是狗头蛇又是僵尸,而后一种状态在NetHack怪物命名中优先,因此我们将其分类为Z
。
因此,我对出现在怪物名称中的单词进行了如下分类:指示符是一个强烈建议适当怪物类别的单词(例如,sphere
强烈建议该怪物属于该类别e
);一个不确定的词是一个词,这多建议少(lord
不告诉你),和所有其他的非词,我们不关心。基本思想是,我们从头到尾从头到尾查看怪物名称中的单词,然后选择看到的第一个指示符。因此,有必要确保每个怪物名称都至少包含一个指示符,其后紧接着是模棱两可的单词。作为例外,出现在怪物名称中的单词看起来像@
(最大的一组)都被归类为歧义。指示符之前可能出现任何内容;例如,颜色名称(例如red
)总是在名称中早于指示符出现,因此被认为是非单词(因为在确定怪物的身份时不会对其进行检查)。
最后,与其他程序一样,该程序也归结为哈希表。但是,该表未包含所有怪物名称或怪物名称中出现的所有单词的条目;相反,它仅包含指标。歧义词的哈希不会出现在表中,而是必须分配给空插槽(尝试查找歧义词将始终出现为空)。对于非单词,单词是否出现在表中或哈希是否冲突都无关紧要,因为我们从不使用查找非单词的值。(表相当稀疏,因此大多数非单词不会出现在表中,但是flesh
由于哈希冲突,在表中会发现一些非单词,例如。)
以下是程序这一部分工作方式的一些示例:
woodchuck
是一个字长的单词(因此是一个指示器),表查找woodchuck
为我们提供了预期的答案r
。
abbot
也是一个单词,但看起来像一个@
。因此,abbot
被认为是一个不明确的词;表查找为空,@
默认情况下我们返回答案。
vampire lord
由一个指示符(vampire
与相对应V
)和一个歧义词(lord
不在表中)组成。这意味着我们检查两个单词(以相反的顺序),然后给出的正确答案V
。
gelatinous cube
由一个非单词(gelatinous
对应于H
由于哈希冲突)和一个指示符(cube
对应于b
)组成。由于我们仅采用表中找到的最后一个单词,因此b
按预期返回。
gnome mummy
由两个指示符组成,分别gnome
与G
和mummy
对应M
。我们采用最后一个指标,即get M
,这就是我们想要的。
用于处理基于单词的分类的代码是Jelly程序的最后一行。运作方式如下:
ḲÇ€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
有两种实际情况;如果输入完全由歧义词组成,则t0
删除表查找的整个输出,并且@
默认情况下我们得到结果;如果输入中包含指标,t0
则会删除最右边指标右侧的所有内容,并Ṫ
为我们提供该指标的相应结果。
表压缩
当然,将输入拆分为单词并不能单独解决问题。我们仍然必须对指示符和对应的怪物类之间的对应关系进行编码(并且缺少歧义词的对应关系)。为此,我构造了一个稀疏表,其中使用了181个条目(对应于181个指标;这比378个怪兽有了很大的改进!),共有966个条目(对应于哈希函数的966个输出值)。该表通过使用两个字符串在程序中进行编码:第一个字符串指定表中“间隙”的大小(不包含任何条目);第二个字符串指定与每个条目相对应的Monster类。这些都通过基本转换以简洁的方式表示。
在Jelly程序中,从第一行µ
开始的第二行表示表查找的代码以及程序本身。这是程序的这一部分的工作方式:
“…’ḃ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
双射基数21类似于基数21,不同之处在于21是合法数字,而0不是。这对我们来说是一种更方便的编码,因为我们将两个相邻条目的间隔记为1,以便可以通过累积和找到有效索引。对于表中包含值的部分,我们有58个唯一值,因此我们首先解码为58个连续的整数,然后使用查找表将其映射到所使用的实际字符中再次解码。(其中大多数是字母,因此我们以非字母条目开头此辅助查找表&;:'
,然后仅追加一个以大写和小写字母开头的Jelly常数;它也有其他垃圾内容,但我们不在乎关于那个。)
果冻的“找不到索引”标记值,如果您使用它来索引列表,则返回列表的最后一个元素;因此,我在查找表上附加了一个零(即使该表主要由字符组成,也为一个整数零),以给出更合适的标记来指示缺少的条目。
哈希函数
该程序的其余部分是哈希函数。这开始就很简单,OḌ
; 这会将输入字符串转换为ASCII代码,然后计算最后一个代码,再加上倒数第二个代码的10倍,再加上之前代码的100倍,依此类推(在Jelly中它的表示非常简短,因为它通常用作字符串→整数转换函数)。但是,如果仅通过模运算直接减少此哈希,最终将需要一个相当大的表。因此,我从一系列操作开始,以减少表格。它们各自的工作方式如下:我们采用当前哈希值的五次幂;然后我们以常数为模减少该值(该常数取决于我们正在使用的操作)。通过两种方式,此链提供的节省(就减少结果表的大小而言)比其成本(就需要对操作链本身进行编码)节省的成本多:可以使表很多小(966,而不是3529项),并采用多阶段提供了更多的机会,有利于引入碰撞(这并没有太大的发生,但有一个这样的碰撞:既Death
和Yeenoghu
散列806,从而使我们能够去掉一个从表中输入,因为它们都转到&
)。此处使用的模数为[3529、2163、1999、1739、1523、1378、1246、1223、1145、966]。顺便提一句,提高到第五次幂的原因是,如果直接取值,差距往往保持不变,而幂运算则使差距四处移动,并有可能使表格在而不是陷入局部最小值(更均匀分布的间隙允许间隙尺寸的更短编码)。这必须的奇次幂,以便防止这样的事实X 2 =( - X)2引入碰撞,和5工作优于3。
程序的第一行使用增量编码对模序列进行编码:
“…’;“…‘_\
“…’ Compressed integer list encoding, arbitrary sized integers
; Append
“…‘ Compressed integer list encoding, small integers (≤ 249)
_\ Take cumulative differences
程序的其余部分,第二行的开始,实现了哈希函数:
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).
验证
这是我用来验证程序正常运行的Perl脚本:
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
> _ <