1. 主要ページへ移動
  2. メニューへ移動
  3. ページ下へ移動

トピックス

記事公開日

【小ネタ】共テ「2026年情報Ⅰ」第3問をF#で書いてみる

はじめに

先月の1月17日18日に2026年の共通テスト(共テ)が行われました。古くは、「共通一次」これを読んでいる多くの方の受験生時代は「センター試験」と呼ばれていたもので、共テはかつてと同じように国立大学の一次試験の役割を果たしています。また、私立大学でも一次試験として採用したり、共テの点数のみで合否を判定する学校が(以前より)多くなっています。例えば、GMARCH※1と呼ばれる6つの大学では、すべての学部において共テのみでの受験が可能です(ただし、合格難度は通常の試験より上がりますが)。

そんな共テですが、昨年2025年より新たに「情報」という”教科”が追加になりました。英語がリーディングとリスニングに分かれたり、理科において文系受験者用に理科基礎が追加になったりと、”科目”の追加・変更は少なくありませんでしたが、”教科”の追加というのは史上初めてだったはずです。

実は、このブログでは昨年もこの「情報」を取り上げ、共テ「情報Ⅰ」第三問をF#で書いてみるという記事を書いています。だから、今年も同様に共テの情報のプログラミング問題を解いてみて、それをF#に書き換えるという、どうでもよいネタを提供しようかと思います。

最近は、何でもかんでもAIに書かせるため、F#だろうがPythonだろうが、コードの種類なんてどうでも良いみたいな風潮がありますが、ここはF#応援団たるこのブログ。F#の宣伝ブログとして毎年恒例行事になるように、いくらアクセス数が少なかろうが、今後も続けていく予定ですので、よろしくお願い申し上げます。

ことしの「情報Ⅰ」

2回目となる2026年の情報Ⅰですが、終了当初からSNS状では昨年よりかなり難しかったという意見が散見されました。今年は物理が超難問で話題になっておりましたが、実際「情報」の方もななかなのもので、今年2026年の平均点は56.59点と昨年の69.26点より12点以上低くなりました。しかし、個人的には昨年より今年の問題の方が好みだったりします。特に第2問がよい感じで、オンラインサービスの考え方とか、画像処理のビット演算とか、非常に身近なデジタルを扱っている感じがします。この辺の知識を高校生のうちに習得していれば、大学、社会人になってもそれなりに役立つと、個人的には思います。

さて、話をプログラミングに戻します。今回の情報Ⅰでも、昨年同様”第3問(大問の3)”がプログラミングの問題となっていました。今年の問題は昨年と似ていて、いくつかの条件がある日数計算というものでした。来年以降も条件付きの日数計算が第3問の定番となるのか、それはわかりませんが、個人的な感想を言えば、今年の問題条件の方が昨年より明快で、受験生も理解しやすかったのではないかと予想しています(ただし、それが得点に繋がるかは別ですが)。

2026年情報Ⅰ第3問

今年の情報Ⅰ第3問を紹介していきたいと思います。今年の問題は文化祭での「待ち時間を計算する」という内容でした。問いの概要は以下の通りです。実際の問題文はかなり長いため、かなり省略しています。 ※以下"<< ア >>"や"<< イ >>"は、設問中で穴埋めをする箇所を意味します。

昨年の文化祭でゲームを提供したが、どんどん人が来るので待つ人が出てしまった。そのため昨年「どのぐらい人を待たせたか?」を計算したい。計算のルールは以下の通り。

  • 1プレイ3分
  • 誰もプレーしていなければ待たない
  • プレイ中に次の来訪者が到着すると、順番が来るまで待つ
  • (簡単のために)交代時間などはないものとする、また同時に来訪者が来ることはないとする

これに対して、昨年の来訪者の「到着時刻」が与えられている。

            fig
    図 昨年の3人目までの待ち時間 (赤がプレイ時間、青が待ち時間)
    ほぼ同等の図が問題にも記載されている

表 昨年の来訪者の待ち時間を整理した結果

  到着時刻 開始時刻 終了時刻 待ち時間
1人目 0 0 3 0
2人目 3 3 6 0
3人目 4 6 << ア >> 2
4人目 10 10 13 0
5人目 11 << イ >>
6人目 12 << ウ >>

質問自体の概要は以下の通り

  • 問1で、コードとは関係無く、上記のルールを理解したかどうかを質問し、
  • 問2で、それに対して各来訪者がどれぐらいの待ち時間だったのかを計算するプログラムを作成させて、
  • 問3でプレイ時間を変更して、最大の待ち時間を10分以下になるプレイ時間を計算させる

以上のような内容となっております。おそらくプログラミングの知見がある人なら、時間さえあれば誰でもコードが自作できる内容ではあります。しかし、全体で60分という限られた試験時間の一部(15分程度)しか使えないことを思うと、誰でも簡単に満点が取れるというわけではないと思います。

さて、大問3のプログラムの紹介になるのですが、この問題には途中理解させるための(点をあげるための)設問がいくつかあって、プログラムも順を追って出てくるので、理解はしやすいようにはなっています。しかし、これを読んでいるようなレベルの方にはそんな(途中の)ものは不要でしょうから、いきなり最終的な”問3”のプログラムを紹介したいと思います。 尚、プログラム(ソースコード)中のコメントは、私が追加したものです。また"<------(x)"は設問である行を挿入する位置を聞くためテキストです。

// 問3 最長待ち時間が10分間未満となる体験時間を調べるプログラム
Touchaku = [034101112//初期値
kyakusu = 要素数(Touchaku)
<------(0)
taikenを1から15まで1ずつ増やしながら繰り返す:
| <------(1)
| Kaishi = [000000]
| Shuryou = [000000]
| Shuryou[1] = taiken
// 開始時間と終了時間を計算し代入
| iを2からkyakusuまで1ずつ増やしながら繰り返す:
| | Kaishi[i] = 最大値(<< カ >>, << キ >>)
| |_ Shuryou[i] = << ク >> 
| saichou = 0
// 待ち時間を計算して、最大値を残す
| iを0からkyakusuまで1ずつ増やしながら繰り返す:
| iを1からkyakusuまで1ずつ増やしながら繰り返す:
| |_ saichou = 最大値(<< サ >>, << ケ >> - << コ >>)
| もし<< シ >>ならば:
| |_ 表示する("体験時間", taiken, "分間:""最長待ち時間", saichou, "分間:")
|_ <------(2)
<------(3)

// 解答
// << カ >>, << キ >>: Shuryou[i - 1], Touchaku[i](順不同)
// <<  ク >>: Kaishi[i] + taiken
// << ケ >>: Kaishi[i]
// << コ >>: Touchaku[i]
// << サ >>: saichou
// << シ >>: saichou < 10
// (0)の位置に「taiken = 1」と「saichou = 0」を挿入
// (2)の位置に「taiken = taiken + 1」を挿入

// 実行結果
// 体験時間1分間:最長待ち時間0分間
// 体験時間2分間:最長待ち時間2分間
// 体験時間3分間:最長待ち時間4分間
// 体験時間4分間:最長待ち時間8分間

このような内容です。この後、最後の問題として「最長待ち時間が10分を超えると以降の計算が無駄なので、繰り返し条件を変更する」という設問があるのですが、そこは今は省略します。

さて、プログラムをみてどう感じますか?大学入試の問題、しかも共テという万人が受ける問題の中身ですから当然ではありますが、どの言語を学んでいる人にとってもクセのない非常なシンプルなループ文とif文で構成されているのが分かると思います。

これをF#で書いてみる

さて、これをF#で書いてみようというのが、今回の趣旨です。といっても、上記の様に非常にシンプルなので、残念ながらどのコードで書いても大して変わらないとは思います。

まずは、できるだけ元のプログラムに書き方を合わせてF#へ移植すると次のようになります。

/// 2026年情報1第3問
let jouhou2026_3 () =

    let Touchaku = [034101112//初期値
    let kyakusu = Touchaku.Length //要素数
    let mutable saichou = 0 //最長待ち時間を入れる変数

    for taiken = 1 to 15 do //taikenはここで宣言
        let Kaishi = Array.create kyakusu 0 //要素6(kyakusu)の配列を作成
        let Shurou = Array.create kyakusu 0 //要素6(kyakusu)の配列を作成
        Shurou[0] <- taiken //終了の最初を1体験時間に設定
        // 開始時間と終了時間を計算し代入
        for i = 1 to (kyakusu - 1do
            Kaishi[i] <- max (Shurou[i - 1]) Touchaku[i]
            Shurou[i] <- Kaishi[i] + taiken
        saichou <- 0
        // 待ち時間を計算して、最大値を残す
        for i = 0 to (kyakusu - 1do
            saichou <- max saichou (Kaishi[i] - Touchaku[i])
        // 最大待ち時間が10分以下なら出力
        if saichou < 10 then
            Console.WriteLine("体験時間" + taiken.ToString() + "分間:最長待ち時間" + saichou.ToString() + "分間" )        
        else ()

    () //戻り値(unit)<=この場合はあってもなくても良いがわかりやすさのため

まあ普通ですね。これを短くしつつF#らしくするにはどうしたらよいでしょう?いくつかのポイントが考えられます。

  • for文を使わない
  • Kaishi配列とShurou配列を別に宣言する必要はない
  • saichouをmuatbleな変数として持つ必要がない
  • ちょっと配列計算を入れてみる

この辺をふまえて、上のプログラムコードを改良したのが下のコードです。

/// 2026年情報1第3問改
let jouhou2026_3kai () =
    let Touchaku = [034101112//初期値
    let kyakusu = Touchaku.Length //要素数

    // ”開始時間”と”終了時間”と”待ち時間”を計算する再帰関数
    let rec jikankeisan (jikan:int[,]) taiken i =
        jikan[0, i] <- max jikan[1, i - 1] Touchaku[i] //iの開始時刻
        jikan[1, i] <- jikan[0, i] + taiken //iの終了時刻
        jikan[2, i] <- jikan[0, i] - Touchaku[i] //iの待ち時間の計算をここでやる
        if (i + 1)  < kyakusu then jikankeisan jikan taiken (i + 1else () //再帰させる

    // 計算のメインとなる再帰関数
    let rec mainloop taiken =
        //3x6の2次元配列を作成
        // 行0: 開始時間, 1:終了時間, 2:待ち時間
        let jikan = Array2D.create 3 kyakusu 0 
        jikan[10] <- taiken  //終了の最初を1体験時間に設定
        do jikankeisan jikan taiken 1 //時間計算再帰関数の実行
        // 最大待ち時間が10分以下なら出力
        let saichou = Array.max (jikan[2, *])  //配列をスライスして結果だけ取り出し最大値を抽出
        if saichou< 10 then
            Console.WriteLine("体験時間" + taiken.ToString() + "分間:最長待ち時間" + saichou.ToString() + "分間" )        
        else ()
        //条件を付けて再帰させる
        if (taiken < 15) && (saichou < 10then mainloop (taiken + 1//再帰させる
        else () //条件に合わなければループを抜ける
    do mainloop 1 //メイン再帰関数の実行

    () //戻り値(unit)<=この場合はあってもなくても良いがわかりやすさのため

結構、見た目が変わったのではないでしょうか?

for文を排除して、再帰関数※2化しました。すると、for文では入れ子だったものが、関数化するため入れ子が回避されます。元はfor文だった待ち時間の計算を「関数として独立」させることができるので、変更も簡単だし、使い回せるし、何よりより複雑な計算式だった場合でも間違いの特定が容易になります。また、時間の計算結果を1つの2次元配列にまとめているため、計算結果が確認しやすくなるはずです・・・ とまあ偉そうに書いておりますが、結局効果は「人による」で終わってしまいそうなレベルの工夫でしかないですけどね。

どちらを選ぶかは自由ですが、最初のF#のコードであれば、F#の文法を知らない人でもある程度理解できる(読める)はずでです。例えば、最初のコードを設問に使っても、共テの元の(日本語の)コードと正答率はさほど変わらないと思います。しかし、こちらの「改良」コードはかなりF#的な書き方をされているため、これで設問されたら正答率はかなり下がるでしょう。何故なら、再帰関数は普段関数型の言語を使っていない人にとっては、なかなか馴染みがないものでしょうからね。

まとめ

というわけで、いかがだったでしょうか?正直に言えば、共テの問題をF#による書き換える行為自体には全く意味が無いかもしれません。しかし、これはF#布教の一部なのでお許し下さい・・・ それに加えて、仮にF#に興味がない人であっても、この記事で現在高校生が学んでいる「情報」のレベル感を感じて貰えるのでは?と思って記事を作っています。

最近の生成AIはコードをバリバリ書いてくれますので、プログラミングの勉強は不要になるでしょうか?例えば、生成AIが英語を翻訳してくれるから英語の勉強が不要になるか?と言えばそんな事はないわけで、同じようにプログラミングが書ける必要はなくてもプログラミングを理解することの重要性は残ると私は考えています。試験問題を見ての通り、今の(共テを受けるような)高校生はかなり勉強しています。今回の共テ「情報Ⅰ」にしても、今の大人達を見渡せば、IT関連職種の人でなければ、平均どころか半分も取れない人の方が大半では?そして、今後の世の中はそのテストを経験した人が”普通”になっていくわけです。頼もしくはありますが、一方で私もそんな若い人達に置いて行かれないように勉強しなければならない、と改めて思うのでありました。

(担当M)

※1; 大学受験業界用語で、MARCH(M:明治大学、A:青山学院大学、R:立教大学、C:中央大学、H:法政大学)にG:学習院大学を加えた大学群のこと。

※2; 関数の中で、自分自身を呼び出す関数のこと。関数をFor文の様に使えるため、関数型の言語ではよく使われる。