C-数語
445 431 427 421 399 386 371 359 * 356 354 † 348 347文字
それでおしまい。これをこれ以上短くすることはできないと思います。
改行はすべて読みやすくするためのもので、削除できます。
i;P(x){char*p=",one,two,three,four,five,six,sM,eight,nine,tL,elM,twelve,NP,4P,
fifP,6P,7P,8O,9P,twLQ,NQ,forQ,fifQ,6Q,7Q,8y,9Q,en,evL,thir,eL,tO,ty, is ,.\n,
4RmagicS,zero,";while(x--)if(*++p-44&&!x++)*p>95|*p<48?putchar(*p),++i:P(*p-48);
}main(c){for(scanf("%d",&c);c+(i=-4);P(34),P(c=i),P(35))P(c?c>19?P(c/10+18),
(c%=10)&&putchar(45):0,c:37);P(36);}
以下では、それは多少縮小されていませんが、それでも読みにくいです。より読みやすいバージョンについては、以下を参照してください。
i;
P(x){
char*p=",one,two,three,four,five,six,sM,eight,nine,tL,elM,twelve,NP,4P,fifP,6P,7P,8O,9P,twLQ,NQ,forQ,fifQ,6Q,7Q,8y,9Q,en,evL,thir,eL,tO,ty, is ,.\n,4RmagicS,zero,";
while(x--)
if(*++p-44&&!x++)
*p>95|*p<48?putchar(*p),++i:P(*p-48);
}
main(c){
for(scanf("%d",&c);c+(i=-4);P(34),P(c=i),P(35))
P(c?
c>19?
P(c/10+18),
(c%=10)&&
putchar(45)
:0,
c
:37);
P(36);
}
展開してコメント:
int count; /* type int is assumed in the minified version */
void print(int index){ /* the minified version assumes a return type of int, but it's ignored */
/* see explanation of this string after code */
char *word =
/* 1 - 9 */
",one,two,three,four,five,six,sM,eight,nine,"
/* 10 - 19 */
"tL,elM,twelve,NP,4P,fifP,6P,7P,8O,9P,"
/* 20 - 90, by tens */
"twLQ,NQ,forQ,fifQ,6Q,7Q,8y,9Q,"
/* lookup table */
"en,evL,thir,eL,tO,ty, is ,.\n,4RmagicS,zero,";
while(index >= 0){
if(*word == ',')
index--;
else if(index == 0) /* we found the right word */
if(*word >= '0' && *word < 'a') /* a compression marker */
print(*word - '0'/*convert to a number*/);
else{
putchar(*word); /* write the letter to the output */
++count;
}
++word;
}
}
int main(int argc, char **argv){ /* see note about this after code */
scanf("%d", &argc); /* parse user input to an integer */
while(argc != 4){
count = 0;
if(argc == 0)
print(37/*index of "zero"*/);
else{
if(argc > 19){
print(argc / 10/*high digit*/ + 20/*offset of "twenty"*/ - 2/*20 / 10*/);
argc %= 10; /* get low digit */
if(argc != 0) /* we need a hyphen before the low digit */
putchar('-');
}
print(argc/* if 0, then nothing is printed or counted */);
}
argc = count;
print(34/*" is "*/);
print(argc); /* print count as word */
print(35/*".\n"*/);
}
print(36/*"four is magic.\n"*/);
}
先頭付近のエンコードされた文字列について
番号の名前は非常に単純なスキームを使用して圧縮されます。頻繁に使用される部分文字列は、1文字のインデックスで名前配列に置き換えられます。追加の名前エントリの「ルックアップテーブル」が、最初のセットで完全に使用されていない部分文字列の最後に追加されます。ルックアップは再帰的です。エントリは他のエントリを参照できます。
たとえば、11の圧縮名はelM
です。print()
関数は文字を出力e
し、l
(小文字の「L」ではなく番号「1」)逐語的に、しかし、それは見つけM
、それは29のエントリ(ASCII「M」 - ASCII「0」)のインデックスを持つ自分自身を呼び出すように、ルックアップテーブルに。この文字列は、evL
それが出力して、e
そしてv
、その後、あるルックアップテーブル内の28項目の指標で再び自分自身を呼び出しen
、出力逐語的です。for (他のすべての名前に使用される)で使用en
されるeL
for een
(後eight
に使用されるeighteen
)でも使用されるため、これは便利です。tO
teen
-teen
このスキームにより、数値名のかなり重要な圧縮が行われますが、圧縮解除に必要なコードはごくわずかです。
文字列の最初と最後のコンマは、この文字列内で部分文字列を見つける単純な方法を説明しています。ここに2つの文字を追加すると、後でさらに文字が節約されます。
虐待について main()
argv
無視され(したがって、圧縮バージョンでは宣言されません)、argcの値は無視されますが、ストレージは現在の数を保持するために再利用されます。これにより、追加の変数を宣言する必要がなくなります。
の欠如について #include
一部を省略すること#include <stdio.h>
は不正行為であると文句を言うでしょう。それはまったくありません。与えられたものは、私が知っているすべてのCコンパイラで正しくコンパイルされる、完全に合法なCプログラムです(警告は表示されます)。stdio関数のプロトタイプがない場合、コンパイラーはそれらがを返すcdecl関数であると想定し、int
渡すべき引数がわかっていると信頼します。とにかく、このプログラムでは戻り値は無視され、戻り値はすべてcdecl( "C"呼び出し規約)関数であり、渡すべき引数はわかっています。
出力
出力は期待どおりです:
0
ゼロは4です。
4つは魔法です。
1
1つは3つです。
3は5です。
5は4です。
4つは魔法です。
4
4つは魔法です。
20
20は6です。
6は3です。
3は5です。
5は4です。
4つは魔法です。
21
21は9です。
9は4です。
4つは魔法です。
*以前のバージョンでは、仕様の2つの部分でマークがありませんでした。ゼロを処理せず、コマンドラインでstdinの代わりに入力を受け取りました。ゼロを追加した文字を処理しましたが、コマンドライン引数の代わりにstdinを使用したほか、他のいくつかの最適化により、同じ数の文字が保存され、結果としてウォッシュが発生しました。
†「is」の両側に数字を印刷する必要があることを明確にするために、要件が変更されました。この新しいバージョンはその要件を満たし、必要な追加サイズを考慮して(以上)の最適化をいくつか実装しています。