応用情報技術者 2019年 春期 午後 問03
券売機の注文の状態を判定するプログラムに関する次の記述を読んで、設問 1〜3 に答えよ。
T社では、U社が経営する飲食店の店舗に設置する券売機のシステムを開発している。U社が店舗で提供する商品には、丼物や定食などのメイン商品のほか、みそ汁やサラダなどのサイドメニューがある。
U社では、特定の種類の商品を組み合わせたものをセットメニューとし、単品で注文した場合よりも安く提供している。
〔食券購入時の要件〕
食券購入時の主な要件を図1に示す。

商品と分類の具体例を表1に示す。表1中のNは分類番号、Sはセットメニューへの適用可否、Oはオプションの指定に関する情報である。S は1のものがセットメニューへの適用可の商品である。分類番号1〜3で、0が0以外のものは、オプションの指定が必要であることを示し、Oの値は、分類番号4のOの値と対応している。オプションを指定する際には、Oの値が一致するオプションだけが選択できる。


〔注文の状態の判定手順〕
券売機は、画面上で商品を選択するボタンが押されるたびに、商品の情報を蓄積する。そして、蓄積した商品の情報を用いて状態遷移を初期状態から評価し直し、注文の状態を判定する。状態の判定には図2の状態遷移図を用いる。初期状態は0である。表1のN、S、Oを左から順に並べた3桁の数をイベントコードと呼び、イベントコードの値によって状態の遷移先を制御する。

状態の判定処理では、商品情報を入力された順に取得し、状態遷移図に基づいて状態遷移を評価する。例えば牛丼、大盛り、漬物を注文した場合、状態は0、1、2、4の順に遷移する。この場合、最後の状態が発券可の状態なので、発券ボタンを押すことができる。また、値引きのルールの条件を満たさないので、値引きはしない。
〔状態遷移表〕
状態遷移図をプログラムとして実装するためには、状態遷移図と状態遷移表にして取り扱う。注文の状態遷移表を表2に示す。表2は、状態番号とイベントコードの組合せの表であり、表の各マスには遷移先の状態番号と、遷移の際の値引きの金額が入る。
例えば、図2で状態が2のときに漬物の注文が入ると状態4に遷移し、値引きは発生しないので、表2では、状態番号が2でイベントコードが210のマスには4:0が入る。遷移後の状態が発券可の状態なので、発券ボタンを押すことができる。

〔券売機の注文の状態を判定するプログラム〕
券売機の注文の状態を判定するプログラム(以下、判定プログラムという)を作成した。判定プログラムは、画面上で商品を選択するボタンが押されるたびに実行される。注文の状態を判定する手順を図3に示す。判定プログラム中で利用する主な変数、定数及び関数を表3に示す。



設問1:状態遷移について、(1)、(2)に答えよ。
(1)鮭定食、野菜サラダ、ゴマドレッシング、みそ汁の順番で注文が入った場合の状態遷移について、図2の状態番号を使って遷移する順を答えよ。
模範解答
0,2,3,4,5
解説
解答の論理構成
- 初期状態は【問題文】で「初期状態は0」であると示されています。
- 1品目「鮭定食」のイベントコード
- 表1より N=“1”, S=“1”, O=“0” なので “110”。
- 表2の“状態番号0×イベントコード110”のセルは “2:0”。
- よって状態は “0→2” へ遷移します。
- 2品目「野菜サラダ」のイベントコード
- N=“2”, S=“1”, O=“2” で “212”。
- 表2の“状態番号2×イベントコード212”は “3:0”。
- よって “2→3” へ遷移します。
- 3品目「ゴマドレッシング」のイベントコード
- N=“4”, S=“0”, O=“2” で “402”。
- 表2の“状態番号3×イベントコード402”は “4:0”。
- よって “3→4” へ遷移します。
- 4品目「みそ汁」のイベントコード
- N=“3”, S=“1”, O=“0” で “310”。
- 表2の“状態番号4×イベントコード310”は “5:50”。
- よって “4→5” へ遷移し、ここで値引き“50”が適用されます。
- 以上より遷移順は “0,2,3,4,5” となり、模範解答と一致します。
誤りやすいポイント
- 「鮭定食」は O=“0” であるためイベントコードは “110”。「111」と誤記しやすいです。
- 「みそ汁」は S=“1”。S=“0”と誤ると “300” になり、表2では自己ループ “4:0” なので最終状態が誤ります。
- 「ゴマドレッシング」は分類4のため N=“4”。分類2と混同して “212” を選んでしまうミスが散見されます。
- 値引き“50”は状態4→5 のときだけ加算される点を見落としやすく、状態遷移自体を誤る原因になります。
FAQ
Q: イベントコードはどの順に並べるのですか?
A: 【問題文】で「表1のN、S、Oを左から順に並べた3桁の数をイベントコード」と定義されています。必ず N→S→O の順です。
A: 【問題文】で「表1のN、S、Oを左から順に並べた3桁の数をイベントコード」と定義されています。必ず N→S→O の順です。
Q: 発券可否はどこで判定されるのですか?
A: 図3の手順(8)と表2の“発券可”列で判断します。本問では最終状態“5”で表2の発券可が“true”なので発券可能です。
A: 図3の手順(8)と表2の“発券可”列で判断します。本問では最終状態“5”で表2の発券可が“true”なので発券可能です。
Q: 値引きは複数回適用されますか?
A: 表2では“値引きの金額”が遷移ごとに設定されていますが、セット割引は条件を満たした最初の遷移(状態4→5, “5:50”)で一度だけ付与される実装です。
A: 表2では“値引きの金額”が遷移ごとに設定されていますが、セット割引は条件を満たした最初の遷移(状態4→5, “5:50”)で一度だけ付与される実装です。
関連キーワード: 状態遷移表, イベントコード, 割引計算, 有限オートマトン
設問1:状態遷移について、(1)、(2)に答えよ。
(2)表2中のア、イに入れる適切な字句を答えよ。
模範解答
ア:false
イ:3:0
解説
解答の論理構成
-
状態3の発券可否(ア)
- 図2で発券可を示す二重円は「2、4、5」、単一円は「0、1、3」です。
- 表2の“発券可”列には、この図2の結果がそのまま入ります。
- 従って単一円である状態「3」は発券不可なので、アには false が入ります。
-
状態4でイベントコード「212」が発生した際の遷移(イ)
- イベントコード「212」は表1のN=2、S=1、O=2、すなわち「サイドメニュー−1」かつ“オプション必須”の商品です。
- 図2を見ると、サイドメニュー−1でオプションが未指定のときは必ず状態「3」に遷移し、そこでオプション(イベントコード「402」など)を待つ設計になっています。
- すでに発券可能な状態「4」にいても、新たにオプション必須のサイドメニュー−1を追加すると再びオプション待ちの状態「3」に戻る必要があります。
- また、値引きはこの時点では発生しないので金額は0です。
- よって イ には 3:0 が入ります。
誤りやすいポイント
- 発券可否を図2の円の形ではなく表2の既存値だけで判断してしまい、状態「3」を true と誤記する。
- 「212」が図2の矢印に明示されていないため自己ループと勘違いし、4:0 や E:0 としてしまう。
- “オプション必須”の判定をOの値だけでなくSの値まで誤って読んでしまい、イベントコードを取り違える。
FAQ
Q: イベントコードはどのように作られますか?
A: 表1のN・S・Oを「左から順に並べた3桁の数」と問題文にあるとおりです。例えば“野菜サラダ”はN=2, S=1, O=2なのでイベントコードは「212」となります。
A: 表1のN・S・Oを「左から順に並べた3桁の数」と問題文にあるとおりです。例えば“野菜サラダ”はN=2, S=1, O=2なのでイベントコードは「212」となります。
Q: 状態3と状態4の違いは何ですか?
A: 状態3は「オプションが未指定の商品を含むため発券不可」、状態4は「すべての必須オプションが確定し発券可」の違いです。オプション必須の商品を追加すると4→3に戻る点がポイントです。
A: 状態3は「オプションが未指定の商品を含むため発券不可」、状態4は「すべての必須オプションが確定し発券可」の違いです。オプション必須の商品を追加すると4→3に戻る点がポイントです。
Q: 値引き金額はどこで加算されますか?
A: 表2の遷移マスの“:”の右側に設定されており、図4では discount ← discount + オ で累積計算します。
A: 表2の遷移マスの“:”の右側に設定されており、図4では discount ← discount + オ で累積計算します。
関連キーワード: 状態遷移表, イベントコード, ステートマシン, セットメニュー値引き
設問2:
図4中のウ~キに入れる適切な字句を答えよ。
模範解答
ウ:order[i].A
エ:order[i].N100+order[i].S10
オ:status_table[status][event_index].discount
カ:status_table[status][event_index].status
キ:acceptedがtrueに等しい
解説
解答の論理構成
-
[ウ]
- 図3(2)に「商品の金額を注文金額に加算する」とあり、表3の order 配列には「order[i].A で…商品の金額を参照」と明記されています。
- よって amount ← amount + order[i].A が成立し、[ウ] は order[i].A です。
-
[エ]
-
図3(3)は「注文された商品のイベントコードを算出する」。
-
問題文には「表1のN、S、Oを左から順に並べた3桁の数をイベントコードと呼び」とあるため、event_code = N×100 + S×10 + O
-
これを order 配列要素で表すと order[i].N100+order[i].S10 となり、末尾の + order[i].O は既にプログラム行に固定で書かれているので、[エ] は order[i].N100+order[i].S10 です。
-
-
[オ]
- 図3(4)では「状態遷移の際の値引きの金額を取得」すると記されています。
- 表3には「status_table[stat][ev].discount で値引きの金額を参照」とあるので、[オ] は status_table[status][event_index].discount です。
-
[カ]
- 図3(5)は「…次の状態番号を取得して、状態番号を更新」。
- 表3には「status_table[stat][ev].status で遷移先の状態番号を参照」と示されているため、[カ] は status_table[status][event_index].status です。
-
[キ]
- 図3(8)で「発券の可否を判定して、発券ボタンの状態を変化」とあります。
- 表3によれば発券可のフラグは status_table[stat][ACCEPT_INDEX].accept に格納され、図4ではいったん accepted へ代入されています。
- よって判定条件は accepted が true に等しい となり、[キ] は acceptedがtrueに等しい です。
誤りやすいポイント
- イベントコードの組立順を逆にしやすい
「N、S、Oを左から順に並べた3桁」とあるため 100,10 の重みを付け忘れると誤答になります。 - event_code と event_index の混同
get_event_index() で得るのは列インデックスであり、そのまま状態を更新できない点に注意が必要です。 - 発券可否の判定先
accept フラグを status_table から直接参照せず、一度 accepted へ格納しているので if 条件で status_table を再参照してしまうミスが多発します。 - discount 加算漏れ
サイドメニュー値引きは遷移表から取得する設計です。表から読む代わりに別ロジックで判定しようとすると整合が取れなくなります。
FAQ
Q: 発券可の状態は状態遷移表を直接見ても良いですか?
A: はい、列 ACCEPT_INDEX に true が入っている行が発券可です。ただしプログラムでは一旦 accepted ← status_table[status][ACCEPT_INDEX].accept へ代入してから判定します。
A: はい、列 ACCEPT_INDEX に true が入っている行が発券可です。ただしプログラムでは一旦 accepted ← status_table[status][ACCEPT_INDEX].accept へ代入してから判定します。
Q: [エ] で + order[i].O を書かなくてよい理由は?
A: 図4中の行は event_code ← エ + order[i].0 となっており、末尾の + order[i].O は既に固定で存在します。[エ] には残りの 部分のみを記述します。
A: 図4中の行は event_code ← エ + order[i].0 となっており、末尾の + order[i].O は既に固定で存在します。[エ] には残りの 部分のみを記述します。
Q: 値引き額はいつ確定しますか?
A: 各商品処理時に status_table から取得し discount に加算します。ループ後に合計割引額が確定しており、追加計算は不要です。
A: 各商品処理時に status_table から取得し discount に加算します。ループ後に合計割引額が確定しており、追加計算は不要です。
関連キーワード: 状態遷移表, イベントコード, 値引き計算, 配列参照, 発券判定
設問3:
図4の判定プログラムについて、プログラムに変更を加えず、表1,2の内容を変更するだけで対応できる要件を解答群の中から二つ選び、記号で答えよ。
ここで、表1, 2の内容について、業務運用中の変更は行わないものとする。
解答群
ア:12:00~14:00の間はランチタイムとし、鮭定食を一時的に提供しないようにする。
イ:オプションの指定が必須なメイン商品について、並、大盛り、特盛りのオプションの指定の後に、ご飯にかけるつゆの量について、普通、多め、少なめの指定ができるようにする。
ウ:サイドメニュー1とサイドメニュー2の商品で、セットメニューに組み込める商品を複数個ずつ注文したときに、値引きも複数回適用する。
エ:メイン商品にカレーを追加する。カレーには並、大盛りを指定できるが、特盛りは指定できない。
模範解答
イ、エ
解説
解答の論理構成
- 判定プログラムは、商品の情報を「表1の N、S、O を左から順に並べた3桁の数をイベントコード」として生成し、そのイベントコードで「表2 注文の状態遷移表」を参照して遷移・値引きを決定します。プログラム本体は、
event_code ← エ + order[ i ].0
event_index ← get_event_index( event_code )
のように、コード生成と表引きだけを行っており、時間帯や個数などの判断ロジックはありません。 - したがって「プログラムに変更を加えず、表1,2の内容を変更するだけで対応できる要件」は、
・表1に商品やオプションの行を追加/削除する
・表2に新しいイベントコード列や遷移・値引きを追加する
のみで実現できるものに限られます。
【ア】「12:00~14:00の間はランチタイムとし、鮭定食を一時的に提供しない」
時間帯判定はプログラムに新たな条件分岐が必要で、表だけでは対応不可。
時間帯判定はプログラムに新たな条件分岐が必要で、表だけでは対応不可。
【イ】「オプションの指定が必須なメイン商品について、並、大盛り、特盛りのオプションの指定の後に、ご飯にかけるつゆの量について、普通、多め、少なめの指定ができる」
つゆ量はオプションに該当します。表1の「分類番号4」に、
・普通 … N=4, S=0, O=3
・多め … N=4, S=0, O=3
・少なめ … N=4, S=0, O=3
のような行を追加し、表2に新イベントコード「403」の遷移列を追加すれば対応できます。プログラム側は既存の get_event_index() と配列参照だけで動作します。
つゆ量はオプションに該当します。表1の「分類番号4」に、
・普通 … N=4, S=0, O=3
・多め … N=4, S=0, O=3
・少なめ … N=4, S=0, O=3
のような行を追加し、表2に新イベントコード「403」の遷移列を追加すれば対応できます。プログラム側は既存の get_event_index() と配列参照だけで動作します。
【ウ】「サイドメニュー1とサイドメニュー2の商品で、セットメニューに組み込める商品を複数個ずつ注文したときに、値引きも複数回適用する」
現在の表2では、値引きは「4 の行・310 列」にある 5:50 の 1 回のみです。複数回値引きを実現するには、値引き回数をカウントする新しい状態やループ処理が必要で、プログラム改修が不可欠。
現在の表2では、値引きは「4 の行・310 列」にある 5:50 の 1 回のみです。複数回値引きを実現するには、値引き回数をカウントする新しい状態やループ処理が必要で、プログラム改修が不可欠。
【エ】「メイン商品にカレーを追加する。カレーには並、大盛りを指定できるが、特盛りは指定できない」
表1にメイン商品の行を追加し、
・カレー並 … N=1, S=1, O=1
・カレー大盛り … N=1, S=1, O=1
を登録、特盛りを載せなければ済みます。イベントコードは既存の「111」で表2に列があり、遷移・値引きは変更不要。
表1にメイン商品の行を追加し、
・カレー並 … N=1, S=1, O=1
・カレー大盛り … N=1, S=1, O=1
を登録、特盛りを載せなければ済みます。イベントコードは既存の「111」で表2に列があり、遷移・値引きは変更不要。
以上より、表だけで対応できるのは【イ】【エ】です。
誤りやすいポイント
- プログラムが「時間」や「個数」を全く扱っていない事実を見落とし、【ア】や【ウ】も表で対処できると誤解する。
- 「値引きを複数回」という要求は、状態を増やせば表だけで対応できると考えがちだが、既存プログラムは値引き金額を累積させるロジックを値引き列に依存しているため、値引きのタイミングを追加するための遷移が不足する。
- オプション追加時に「O の値」が既存の 1,2 と重複できる点を忘れ、新しい分類番号を作成しようとして表2に大幅変更が必要だと判断してしまう。
FAQ
Q: 新しく追加したイベントコード列(例:403)は、get_event_index() の修正が要るのでは?
A: 列を増やす際に、テーブルと同時にイベントコード→列インデックスの対応を設定ファイル等で登録すればよく、プログラム本体のロジック変更は不要です。
A: 列を増やす際に、テーブルと同時にイベントコード→列インデックスの対応を設定ファイル等で登録すればよく、プログラム本体のロジック変更は不要です。
Q: 値引き列を複数追加すれば【ウ】も表だけで実装できないか?
A: 値引き金額を加算する式は 1 回の遷移で 1 列しか参照できません。複数回値引きを行うには、遷移を分割して別の状態に入り直すか、ループで同じ列を再参照する処理が必要になるためプログラム修正が不可欠です。
A: 値引き金額を加算する式は 1 回の遷移で 1 列しか参照できません。複数回値引きを行うには、遷移を分割して別の状態に入り直すか、ループで同じ列を再参照する処理が必要になるためプログラム修正が不可欠です。
Q: 【イ】の追加オプションで「O = 3」を使う根拠は?
A: 表1では「O の値は、分類番号4のOの値と対応している」と明記されています。既存の値 1,2 と重複しない新しい値 3 を割り当てれば区別できます。
A: 表1では「O の値は、分類番号4のOの値と対応している」と明記されています。既存の値 1,2 と重複しない新しい値 3 を割り当てれば区別できます。
関連キーワード: 状態遷移表, イベントコード, オプション管理, 値引き処理, テーブル駆動制御


