【C】マクドナルドのコンパイラを再再実装する。その1

この記事は[N高グループ・N中等部 Advent Calendar 2024](https://qiita.com/advent-calendar/2024/nhighschool-njuniorhighschool)、7日目の記事です。とか言いつつ1日遅れてます。すみません。

はじめに
--
こんにちは。とある元梅田プロクラ生です。今年の春にN高を卒業し、[42Tokyo](https://42tokyo.jp/)というエンジニアの学校で基礎からプログラミングを学び直しています。

主に今まで、メインでやってきた分野はゲーム分野で、その他にも、競プロ、C、Web系も少しだけ触ったことがあります。

今回作る作品について
--
さて、アドベントカレンダーのタイトルでは、『__まあ適当にくるCでも読みながらどないか書いていきますわ__』とは書いてみたものの、何を何を作りましょうか...。
ちなみに42tokyoでは、C言語、C++を使った、既存のシステムや関数の再発明の課題を中心として勉強を行なっていきます。有名なプログラム、fizzbuzzや今までに作ったプログラム、Pythonで解いた競プロ問題の再実装あたりは、割と良いかもしれません。
<br>
__うーん__
<br><br>
どうしましょうか、

まあ適当にくるCでも読みながらどないか書いていきますわ..か、
<br>
<br>
<br>
、、、、、、、、、、、はっ!!
<br>
__『ま』__ あ適当に、
__『く』__ るCでも読みながら、
__『ど』__ ないか書いていきますわ、、、！！？

## まくどだ！マクドナルドコンパイラの季節だ！！
マクドナルドコンパイラとは、去年私が書いた記事、[【Python】マクドナルドのコンパイラを再実装する。](https://qiita.com/HINOKAGUZUTI/items/67487d486e60f879bf47)に出てくるプログラムの名前です。まだこの記事を読んだことがない方は先にそちらを読んでみることをお勧めします。

コード自体はお客さんの入力をプログラミング言語、厨房内で扱うデータを機械語と置き換えたときに、レジの部分をコンパイラとみなし、自然言語から、データへの変換を行なってみるという内容になっています。
<br><br>
これが、マクドナルドのアルゴリズム。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622119/45cd4415-87c1-9a07-479d-32112a959fcb.png)
この部分がコンパイラですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622119/2e116c59-508a-0b0b-6742-f5d6f2153a96.png)
<br>
今回は、この仕組みをC言語で再々実装していきたいと思います。

さてどんな実装にしようか、？
--
一旦再実装してみるとはいったものの前回と全く同じものを作ったってあまり面白くありません。
まずはこの要件定義の部分からやっていきたいと思います。

## 最低限必要な要素
前回実装した要素としてはこんな感じ
<br>

* 注文を尋ねる文章の出力
* 入力の受け取り

この辺りは、printfやreadを使用すれば簡単に書けるかと思います。入力の文字数制限だけ設けてやった方が作りやすいかもしれないですね。
<br>
* 入力された値から要素を抽出

要するに文字列から部分文字列をとってくるという作業ですね。ただ少し難しいのは、部分文字列の候補が多いこと。探索の仕方を工夫すれば、計算回数は多少減りますが、そこの実装はやりながら決めていこうと思います。
42の課題で、strnstrという、部分文字列をとってくる関数を再実装したことがあるので、それを拡張して、複数の部分文字列対応をできるようにしてみたいと思います。
<be>
* 注文の終了を受け取る

前回は、以上という単語が文字列に含まれていたら、注文を終了したとみなし、出力に移っていました。今回はもっと単純に、何も入力されなかったら終了にしようと思います。
<br>
* オーダーリストの成形
* 出力

部分文字列が入ってくると、個数とメニュー名をリストに追加していくという処理をしていましたが、複数行に渡って同じメニューを頼んだ時に、別々の要素として、リストにメニューが追加されてしまうという問題がコメントで指摘されていました。
今回は、あらかじめ、メニュー名と対応した、個数の配列を用意しておき、個数が1以上の時、メニュー名と個数を出力するという仕様にします。
<br>

*スマイルを注文された時の対応

<br>

__もちろん、その場でとびきりの笑顔を見せつけてやりますよ！__

<br><br>
あとC言語で日本語のようなマルチバイト文字を扱うのはかったるいので今回は全て英語での対応とします。

## 追加の機能

* 時間帯別メニューへの対応

前回のコードでは、すべての時間帯のメニューに対応させることができませんでした。また、メニューを書き換える際は、コードを直接直すしか手がありませんでした。
そこで、今回は、プログラム実行時にコマンドライン引数として、メニューが書かれたファイルを渡し、それを読み取っていくという形式にします。
```:menu
Hamburger
Cheeseburger
Double Cheeseburger
Teriyaki Burger
French fries
Nugget
Apple pie
Coca Cola
Qoo
Iced Tea
Coffee
```
こんな感じで改行しながら、メニューファイルを書いていきます。42の課題でget_next_lineという改行区切りでファイルを読み取り、内容を返してくれるという関数を実装したので、それを流用する予定です。
計算速度が遅くなってしまうのでメニューの数にはある程度の制限を設けなければいけませんが、このような形式で行えば、時間帯別メニューだけでなく、期間限定やマックカフェメニューにも対応できるのは強みです。
<br>
* 数字への対応

以前は、たとえば`ハンバーガーを3つ`くださいのような注文ができませんでした。　今回は、簡易的な実装にはなりますが、英語は、単語の前に数詞がつくことが多いため、
`three Hamburger`のような入力に対して、threeが来た時点で3という数値を保存しておき、次にきたメニュー名の数を3つ増やすという実装にしてみようと思います。
<br>

* 部分文字列の中に他の部分文字列がある場合の対応

前回の記事を書いた時点で、以下のようなバグが見つかっていました。
```:前回記事
また、今回のメニューにはないが、朝マックのハッシュポテトなどがあった場合、
ハッシュポテトとポテトが検出されてしまう問題が発生してしまうことが考えられる。

一応簡単に実装する方法としては、マクドナルドのメニューが基本的にカタカナなのを利用して、
検出したメニューの前後の文字がカタカナになっていないかを検出するなどの方法が考えられるが、
ポテトとハッシュポテトは同じ時間帯に存在しないため、今回は割愛させていただく。

追記）ダブルチーズバーガーとチーズバーガーに関しては見逃してください、、、完全に忘れてました。。
```

今回は、このダブルチーズバーガーを注文した時にチーズバーガーの数値も増えてしまうという問題を完全に解決する方法を思いついたので、それも実装してみようと思う。ぜひ楽しみにしておいて欲しい。

実装
--
__『さあいよいよ実装だ！』__

<br><br>
と言いたい人生でした...
<br>
get_next_line関数を自分のPCに持ってきた時点でバグが起きてしまい、それと格闘している間にアドベントカレンダーの日程を一日過ぎてしまいました。

流石にこれ以上遅れるわけにはいかないので、急いでタイトルにその1をつけました。
<br>
__今回は要件定義だけで許していただきたい、、__

~~絶対に~~ 完成はさせます！！、、させるつもりです。来年春くらいまでには...

記事を更新したら[Twitter(旧X)](https://x.com/hinokagu_)に投げるので、更新を見守ってくれる方はぜひフォローして待っていてくれると嬉しいです。

その2は多分[42tokyoアドベントカレンダー](https://qiita.com/advent-calendar/2024/42tokyo)後半あたりで投げます。おそらくメニュー表の読み込みあたりまでの実装。

<br>
では、

次回の更新をお楽しみに！
--
by とある元梅田プロクラ生兼元マクド店員