C (170 文字)
i,j;main(c,s){char**r=s,*p=*++r;for(;i<3;)j--?putchar(!p[-1]?p=*r,++i,j=0,10:
"##3#3133X=W.<X/`^_G0?:0@"[i*8+c/2]-33>>c%2*3+j&1?"|_"[j&1]:32):(j=3,c=*p++&31,
c-=c>6?10:1);}
これは、入力文字列をコマンドライン引数として受け取ります。stdin を使用するための変換は、もう 1 文字になります。
i,j;main(c){char s[99],*p=s;for(gets(s+1);i<3;)j--?putchar(!*p?p=s,++i,j=0,10:
"##3#3133X=W.<X/`^_G0?:0@"[i*8+c/2]-33>>c%2*3+j&1?"|_"[j&1]:32):(j=3,c=*++p&31,
c-=c>6?10:1);}
標準入力バージョンは、最大 98 文字の入力を受け入れることができます。もちろん、それ以上だfloor(terminalWidth / 3)
と改行が混乱します。
各文字の出力は、各行のセルがセグメントである 3x3 グリッドのように扱われます。セグメントは「オン」または「オフ」のいずれかです。セグメントが「オン」の場合、位置に応じてa'|'
または aが出力されます。'_'
オフの場合はスペースが出力されます。文字配列は、各セグメントがオンかオフかを決定するビットの配列です。コードの後にそれについての詳細:
i,j; /* Loop variables. As globals, they'll be initialized to zero. */
main(c,s){
/* The signature for main is
*
* main(int argc, char **argv)
*
* Rather than add more characters for properly declaring the parameters,
* I'm leaving them without type specifiers, allowing them to default to
* int. On almost all modern platforms, a pointer is the same size as
* an int, so we can get away with the next line, which assigns the int
* value s to the char** variable r.
*/
char**r=s,*p=*++r;
/* After coercing the int s to a char** r, offset it by 1 to get the
* value of argv[1], which is the command-line argument. (argv[0] would
* be the name of the executable.)
*/
for(;i<3;) /* loop until we're done with 3 lines */
j--?
/* j is our horizontal loop variable. If we haven't finished a
* character, then ... */
putchar( /* ...we will output something */
!p[-1]? /* if the previous char was a terminating null ... */
p=*r,++i,j=0,10
/* ... reset for the next row. We need to:
*
* - reinitialize p to the start of the input
* - increment our vertical loop variable, i
* - set j to zero, since we're finished with this
* "character" (real characters take 3 iterations of
* the j loop to finish, but we need to short-circuit
* for end-of-string, since we need to output only one
* character, the newline)
* - finally, send 10 to putchar to output the newline. */
:"##3#3133X=W.<X/`^_G0?:0@"[i*8+c/2]-33>>c%2*3+j&1?
/* If we haven't reached the terminating null, then
* check whether the current segment should be "on" or
* "off". This bit of voodoo is explained after the
* code. */
"|_"[j&1]:32
/* if the segment is on, output either '|' or '_',
* depending on position (value of j), otherwise,
* output a space (ASCII 32) */
)/* end of putchar call */
:(j=3,c=*p++&31,c-=c>6?10:1);
/* this is the else condition for j--? above. If j was zero,
* then we need to reset for the next character:
*
* - set j to 3, since there are three cells across in the grid
* - increment p to the next input character with p++
* - convert the next character to a value in the range 0–15.
* The characters we're interested in, 0–9, A–F, and a–f, are
* unique in the bottom four bits, except the upper- and
* lowercase letters, which is what we want. So after anding
* with 15, the digits will be in the range 16–25, and the
* letters will be in the range 1–6. So we subtract 10 if
* it's above 6, or 1 otherwise. Therefore, input letters
* 'A'–'F', or 'a'–'f' map to values of c between 0 and 5,
* and input numbers '0'–'9' map to values of c between
* 6 and 15. The fact that this is not the same as the
* characters' actual hex values is not important, and I've
* simply rearranged the data array to match this order.
*/
}
文字配列は、文字グリッドを記述します。配列内の各文字は、2 つの入力文字に対する出力グリッドの 1 つの水平行を表します。グリッド内の各セルは 1 ビットで表されます。これは、セグメントが「オン」であることを意味し (したがって、位置に応じてaまたは aを1
出力します)、セグメントが「オフ」であることを意味します。'|'
'_'
0
2 つの入力文字のグリッド全体を記述するには、配列内の 3 文字が必要です。配列内の各文字の下位 3 ビット (ビット 0 ~ 2) は、2 つの偶数入力文字の 1 つの行を表します。次の 3 ビット (ビット 3 ~ 5) は、2 つのうち奇数の入力文字の 1 つの行を表します。ビット 6 と 7 は未使用です。+33 のオフセットを持つこの配置により、エスケープ コードや非 ASCII 文字を使用せずに、配列内のすべての文字を印刷可能にすることができます。
入力文字の 7 つのセグメントすべてのビットを配列内の 1 つの文字に入れるなど、いくつかの異なるエンコーディングをいじりましたが、これが全体的に最短であることがわかりました。この方式では、入力文字 16 文字のみのセグメントを表すために配列内に 24 文字が必要ですが、他のエンコーディングでは、ASCII 以外の文字を使用する必要がありました (モールス符号のゴルフの回答でこれを使用すると、当然ながら問題が発生しました)。 、および/または複雑なデコードコード。このスキームのデコード コードは驚くほど単純ですが、括弧を追加する必要がないように C の演算子の優先順位を最大限に活用しています。
それを理解するために小さなステップに分けてみましょう。
"##3#3133X=W.<X/`^_G0?:0@"
これはエンコードされた配列です。デコードする適切な文字を取得しましょう。
[i*8
最初の 8 文字はセグメントの一番上の行を表し、次の 8 文字はセグメントの真ん中の行を表し、最後の 8 文字はセグメントの一番下の行を表します。
+c/2]
この時点で、c には 0 ~ 15 の値が含まれており、これは ABCDEF0123456789 の入力に対応し、配列はエンコードされた文字ごとに 2 つの入力文字をエンコードすることに注意してください。したがって、配列の最初の文字'#'
は 'A' と 'B' の一番上の行のビットを保持し、2 番目の文字も'#'
'C' と 'D' の一番上の行をエンコードします。
-33
エンコーディングの結果、32 未満の値がいくつか発生するため、エスケープ コードが必要になります。このオフセットにより、エンコードされたすべての文字が、印刷可能なエスケープされていない文字の範囲になります。
>>
右シフト演算子は算術演算子よりも優先順位が低いため、このシフトはオフセットを減算した後の文字に対して行われます。
c%2*3
c%2
は偶数の場合は 0、奇数の場合は 1 と評価されるため、奇数文字の場合は右に 3 シフトしてビット 3 ~ 5 を取得し、偶数文字の場合はまったくシフトせず、ビット 0 ~ 2 へのアクセスを提供します。 . c&1
偶数/奇数チェックに使用することを好みますが、それは私が他の場所で使用するものですが、&
演算子の優先順位が低すぎて、括弧を追加せずにここで使用することはできません。%
演算子には適切な優先順位があります。
+j
j
現在の出力位置の正しいビットを取得するには、さらにビットをシフトします。
&1
ビットごとの and 演算子は、算術演算子とシフト演算子の両方よりも優先順位が低いため、シフトによって関連するビットがビット 0 になった後にビット 0 が設定されているかどうかをテストします。
?
ビットゼロが設定されている場合...
"|_"
... によって選択されたこれらの文字の 1 つを出力します ...
[j&1]
... 水平ループ変数が偶数か奇数か。
:32
それ以外の場合 (ビット 0 が設定されていない)、出力 32 (空白文字)。
私はこれをこれ以上削減することはできないと思います。