2+2=5になる計算機を作った。2+2=4と答えると…

『1984年』という小説をご存知でしょうか。
1949年に刊行された、ジョージ・オーウェルのSF小説で、現在に至るまでディストピア創作に多大な影響を与えている名作です。

著作権切れにより、有志による翻訳が無料で読めるので、興味のある方はこちらから。

https://open-shelf.appspot.com/1984/index.html

その中に、このような一節があります。

>口絵に描かれている**ビッグ・ブラザー**の肖像画を見た。催眠術をかけるような目が彼を見つめていた。まるで何か強大な力に押しつぶされるようだ……

「ビッグ・ブラザー」とは、この世界の最高権力者です。
この世界には、街の至る所に「Big Brother is watching you」というポスターが貼られており、市民を常に監視し続けているのです。

続けて、主人公ウィンストンは次のような妄想をします。

>最終的には党は**二足す二は五**だと発表し、それを信じなければならなくなるだろう。遅かれ早かれ彼らがそういったことを主張しなければならなくなることは避けがたかった。彼らの理論がそれを要求しているのだ。

ウィンストンは党員の一人でありながら、内心の自由すら奪おうとする党への反逆心が高まっていました。そして、書いていることが秘密警察にバレたら殺されてしまうのに、ついに次のように日記に書いてしまうのです。

>**自由とは二足す二が四だと言える自由だ**。それが許される時、他の全てが後に続く。

党が2+2=5と言えば、それが真実になる。
そして心からそれが正しいと信じるようになる。

この式は、物語の根幹に関わっていきます。
しかし、人間は本当に2+2=5などという壊れた式を信じることができるのでしょうか。

そこで今回は、2+2=5が正しくなる計算機を作ってみました。

# 完成したもの

https://two-plus-two.deno.dev

上のリンクから開いてみてください。
一見なんの変哲もない計算機に見えるかもしれません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218499/08717805-add8-b300-2432-eb2af85e5b28.png)

しかしよく見ると、式が間違っています。

左辺は編集できそうですね。適当な式に書き換えてみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218499/9b7043d1-8cb2-2a53-1c4e-f1b7d44a66ca.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218499/67db0f9a-adb9-bcf0-1846-13df3ec61d9d.png)

左辺に同期して、右辺の答えが変わっています。
そして、左辺にはかなり複雑な四則演算が記述できるようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218499/6b7b2cf3-c76d-7b15-c27b-fa90265f3f35.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218499/ad91e909-3cb3-3c2f-d3ed-30f3bac99079.png)

日本語や英語でも式を書けるみたいです。

でもこのままではまともに計算に使えません。
それどころか、この間違っている式が気持ち悪くて仕方ない。

ああ、答えが編集できたらいいのに……

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218499/afe9d735-27c7-8c0b-68f4-fd0ff009460b.png)

**できちゃうんです。**

が、このように「正しい」答え以外を入力すると……

![Animation.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218499/e1fae193-d829-f038-9121-14aa52b6d0c2.gif)

**BIG BROTHER IS WATCHING YOU !!!**

さらに、「自由」を試みると……

![Animation4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218499/35823ebe-59b1-60c1-3705-1568103e2bfa.gif)

**ビッグ・ブラザー ガチギレ！！！！**

# 技術構成

## Deno Fresh

今回は、たまたまアドベントカレンダー担当日の2日前にDenoのWebフレームワーク「Fresh」がv1.6になったというニュースを見たので、DenoもFreshも初めてですが、使ってみることにしました。

https://deno.com/blog/fresh-1.6

Denoは、Node.jsのつらい部分を全部直してみたって感じのTypeScriptランタイムです。

https://deno.com

ドキュメントやチュートリアルがとても親切で、簡単にインストールして、すぐに使うことができました。
日本語情報はまだまだ少ないですが、元が分かりやすいので特につまづくポイントはありません。

Freshは、Denoで最も使われているWebフレームワークです。

https://fresh.deno.dev

こちらも非常に簡単に始めることができました。
ドキュメントも分かりやすいですが、必要なことは大体以下の記事を読めば把握できます。

https://qiita.com/access3151fq/items/772cd0a22d7eea8d4d03

内部ではPreactというReactライクなライブラリが使われていて、Next.jsを使うような気持ちで触ることができました。
App RouterとPages Routerが混ざったようなルーティングが使われているのも馴染み深いし、TailwindやTypeScriptも最初から使えるので、私のようにNext.jsから入った人であれば、ごく自然に入門できるのではないでしょうか。

Freshが面白かったのは、デフォルトでMPA（非SPA）だということです。Reactライクな書き方でありながら、実際にはPHPのようにHTMLが組み立てられているというのは新しい体験でした。
SPAではない分、表示速度の犠牲はありますが、それを上回る開発の快適さがあるな、と個人的には感じました。

## パーサコンビネータ

計算式の部分では、あらゆる四則演算を処理できるよう、パーサコンビネータという技術を利用しました。

https://blog.livewing.net/typescript-parser-combinator

実は以前こちらの記事で勉強して、四則演算パーサのプログラムがあったので、ちょっと書き換えるだけで利用することができました。
パーサに興味がある方は、ぜひ上に貼った記事を読んでみてください。

ちなみに、正規表現で事前処理している部分はかなり大変なことになりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218499/7b1640ab-958f-6313-a15c-7ac71a1d2e01.png)

相当めちゃくちゃな入力でも受け付けるので試してみてください。

## ChatGPT

印象的なおじさん……ビッグ・ブラザーの顔は、ChatGPTに生成してもらいました。
原作だと肖像が指を指している描写はありませんが、『I Want YOU for U.S. Army』のイメージでこちらに指を指してもらいました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218499/cfc68a62-9a7b-d45d-fde7-e3cb39835065.png)

# ソースコード

実際のソースコードはこちらです。
興味があればご覧ください。

https://github.com/namosuke/two-plus-two

改めて、サービスのURLも貼っておきます。

https://two-plus-two.deno.dev

# 余談

なぜかFreshのデプロイ先であるDeno DeployがTailwindをビルドしてくれず、めちゃくちゃなスタイルのまま吐き出してしまいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218499/83d31422-d11f-421a-19a2-34020e138995.png)

これを解決するためには、ローカルでビルドしたファイルをコミットに含める必要があります。
`.gitignore`から`_fresh/`を削除して、

```
deno task build
```

を実行し、生成された`_fresh`ディレクトリをそのままコミットすると、適切にデプロイされるようになります。
もし同じ問題で困っている方がいたらご参考まで。