1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

esolangAdvent Calendar 2024

Day 12

【DNCL】大学入試の言語でFizzBuzzをできる限り短く実装しよう!

Last updated at Posted at 2024-12-11

前書き

本記事は、Qiitaのesolang Advent Calendar 2024 の、12日目の記事です。

世の中にはできる限りプログラムの文字数を少なくして競う競技、通称「Code Golf」と呼ばれるものが存在しています。
まあそれをやっていきます。
ちなみに今回は基本的にバイト数を減らす方針です。

(2024/12/13 15:50分追記)
最小文字数を更新しましたので、追記に書きました。

言語紹介

今回使用する言語は2025年度の共通テストから行われる「情報I」のテスト内で実際に使用される言語です。
(2024/12/17 12:30追記)2024年度までの「情報関係基礎」のテスト内で使用されていた言語でした。
訂正してお詫び申し上げます。(@nodai2h_ITCさん、ありがとうございます。)


言語名は「DNCL」といいます。(Daigaku Nyushi Center Languageだと言われているそう)
そして意外と言語仕様がしっかりしているため、実際に実行することが可能だそうです。

今回はDNCL学習環境である「どんくり」を用いてCode Golfをします。

この言語は大学入試をするためにとてつもなく魔改造作られたされた言語であり、コードの大部分が日本語で構成されている(特に構文が)、若干Pythonよりの言語です。

しかし、「なでしこになることができなかった」、「別にPythonでもいいだろ」、「読みにくい」、「言語仕様がひどい」、「Esolang」などと散々な言われ方をしている可哀想な言語です。~

ということで、一部の人から猛烈に批判が飛んでくるようなかわいそうな言語でCode Golfをしてみようと思います!

コード

してみようとは言ってもこの記事を書いている時点ですでにコードは書き切っているので先にコードをお見せします

ドドン(セルフ)

DNCL
i0i99の間n(x,y)はa{y}a[i%x+1]または""を返すを実行する ii+1n(3,"Fizz")+n(5,"Buzz")またはiを表示するを繰り返す

(86文字、118バイト)

はい。

はい?

はい。


見てもらえばわかる通り、見てもわからないです。
ということで、どのように縮めていったか、またどのようなところで苦戦したかを見てみましょう。

DNCLのCode Golfテクニック!(無需要)

(改行を減らすみたいな大体どの言語でも言えるようなことは省きます)
DNCLは日本語を主体としている言語なので、ひらがなや漢字が多くなればなるほどバイト数が増えてしまいます。
なのでできる限り数式で書くということを念頭に置きながら書きます。

繰り返し編

いろんな言語でCode Golfをやったことがある人ならわかると思いますが、
for文って長いんですよ。
しかもこのDNCL、PythonのRangeみたいな挙動するので特に文字数とられるんです。

まあとりあえず見てみましょう。

DNCL
iを0から10まで1ずつ増やしながら
    iを表示する
を繰り返す

長いですね。
ということでほかのループも試してみましょう。

DNCL
i0
i<10の間
    iを表示する
    ii+1
を繰り返す
DNCL
i0
ここから10回
  iを表示する
    ii+1
を繰り返す
DNCL
f(i)
    iを表示する
    もしi!=10ならばf(i+1)を実行する
を実行する
f(0)

どうやらwhileが一番短そうですね。

条件分岐編

まあこんな記事読んでる時点で知っている方がほとんどでしょうが、if以外にも条件分岐する方法はあります。

DNCL
もし1ならば
    1を表示する
を実行しそうでなければ
    2を表示する
を実行する

割と長いですね。
他を見てみましょう。

DNCL
a{1,2}
a[0]を表示する

相当スッキリしましたね。
ただこの言語、「一度代入しないといけない」「Booleanの型変換が出来ない」「関数内の引数にBooleanを代入できない」と言うEsolangをEsolangたらしめる仕様があるので使い所には注意ですね。

関数内で1を返すとかが使えるなら

DNCL
もし1ならば
    1を返す
を実行する
2を返す
DNCL
1の間
    1を返す
を繰り返す
2を返す

この言語本当にwhileが強いですね

あとは論理演算子も用意されてます。

DNCL
1または2を返す

解説

DNCL
i0
i99の間
    n(x,y)
        a{y}
        a[i%x+1]または""を返す
    を実行する
    ii+1
    n(3,"Fizz")+n(5,"Buzz")またはiを表示する
を繰り返す

割と読みやすいですね!

上のパートで言った通り、反復処理はwhileが強いのでwhileで書いてます。

で、見たら分かる通り、何故か関数化されてますね?
これなにがあったかというと、、、


FizzBuzzの分岐は短くするためにできる限り数式で書きたい
 ↓
まあ{i,"Fizz","Buzz","FizzBuzz"}[i%3+i%5*2+1]だと思ってた
 ↓
{1}[0]の用に直接くっつけられないことに気づく
 ↓
Trueを数字に変換することが出来ないことに気づく
 ↓
余りが0の時だけの分岐{1}[0]または2をFizzとBuzzそれぞれに使う
 ↓
処理が被ってるのをまとめる


みたいな経緯です。

(ちなみにi%x+1となっているのは配列が1スタートだからです。)

もう主要な部分殆ど終わってしまったんですが

DNCL
n(3,"Fizz")+n(5,"Buzz")またはiを表示する

として、消してもエラーを吐かない改行を取っ払ったら終わりです!

DNCL
i0i99の間
a{y}a[i%x+1]
ii+1n(3,"Fizz")

どうやら代入の右辺には1つの要素しかこないためスペースがなくても動くようです。

DNCL
を実行する ii+1

しかし構文末尾のを実行するのあとにはスペースや改行を挟まないと動きません。
なんで?

追記

(2024/12/13 15:50追記)

DNCL
i0i99の間ii+1a{"FizzBuzz","Buzz","Fizz",i}a[i*i%3+i*i%5%3*2+1]を表示するを繰り返す

(75文字、92バイト)
@angel_p_57さん、ありがとうございました!)

解説

DNCL
i0
    i99の間
    ii+1
    a{"FizzBuzz","Buzz","Fizz",i}
    a[i*i%3+i*i%5%3*2+1]を表示する
を繰り返す

大分スッキリしましたね。
もはや分からない所が数式だけだと思います。
i*i%3を表にすると

i = 1 2 3 ...
i2 = 1 4 9 ...
i2 % 3 = 1 1 0 ...

となり、i%3==0の時だけ0になる関数となります。
また、i*i%5%3*2を表にすると

i = 1 2 3 4 5 ...
i2 = 1 4 9 16 25 ...
i2 % 5 = 1 4 4 1 0 ...
i2 % 5 % 3 = 1 1 1 1 0 ...
i2 % 5 % 3 * 2 = 2 2 2 2 0 ...

となり、i%5==0の時だけ0になる関数となります。
これにより、

DNCL
i*i%3+i*i%5%3*2+1

この数式は、
3でも5でも割り切れる時4が、
3で割り切れて5で割り切れない時3が、
5で割り切れて3で割り切れない時2が、
15で割り切れる時1
返ってくるので、配列の参照している場所にきれいに対応します。

あとがき

ここまでお読みいただきありがとうございました!!!
1時間程度で書いたコードなのでもしかしたらまだ省略できる箇所があるかもしれません、、
何かあればコメントにお願いします!

dev

1
0
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?