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"*/);
}
冒頭付近のエンコード文字列について
番号の名前は、非常に単純なスキームを使用して圧縮されます。頻繁に使用される部分文字列は、name 配列への 1 文字のインデックスに置き換えられます。最初のセットで完全に使用されていない部分文字列の最後に、追加の名前エントリの「ルックアップ テーブル」が追加されます。検索は再帰的です。エントリは他のエントリを参照できます。
たとえば、11 の圧縮名はelM
. このprint()
関数は、文字e
とl
(数字の '1' ではなく小文字の 'L') を逐語的に出力しますが、 を見つけるM
ので、29 番目のエントリのインデックス (ASCII 'M' - ASCII '0') でそれ自体を呼び出します。ルックアップ テーブルに。この文字列はevL
であるため、 および を出力e
しv
、ルックアップ テーブルの 28 番目のエントリのインデックス ( ) を使用して自分自身を再度呼び出し、en
そのまま出力します。これはen
、eL
for (のeen
後eight
に使用eighteen
) で使用され、tO
for 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 を使用したり、他のいくつかの最適化によって同じ数の文字が保存され、ウォッシュが発生しました。
†「 is 」の両側に数字を印刷する必要があることを明確にするために、要件が変更されました。この新しいバージョンはその要件を満たし、必要な余分なサイズを考慮して (それ以上の) いくつかの最適化を実装しています。