基礎プロI 100本ノック 上級編

各プログラムにおいて、特に指定が無い限りは入力値が指定された形式であるかどうかをチェックする必要はない(例えば整数型の値を入力させるところでアルファベットを入力された場合など)。

問題の順序は難しさの順序ではないので、好きな問題から手をつけるとよいだろう。難しさの目安として問題の後ろに☆をつけておく(多いほど難しいと思われる)。

No. 80 互いに素 ☆

2つの正の整数値を入力させ、互いに素であるか判定するプログラムを作成せよ。なお、2つの正の整数が互いに素とは、1以外に共通公約数を持たない関係のことである。

【実行例、下線部は入力例】
$ ./knock80
2つの値をスペースで区切って入力: 23 24
互いに素
$ ./knock80
2つの値をスペースで区切って入力: 69 23
互いに素でない
$

ヒント:両方の値が割りきれる2より大きい整数が存在しないことを確認すればよい。

No. 81 中間値 ☆

3つの整数値を入力させ、3つの値のうち2番目に大きい値を表示するプログラムを作成せよ。

【実行例、下線部は入力例】
$ ./knock81
3つの値を入力: 23 24 25
24
$ ./knock81
3つの値を入力: 16 8 21
16
$

ヒント:ていねいに場合分けすればよいが意外に面倒くさい。大きい順、あるいは小さい順に値を並び替える方法もあるが少し難しい。

No. 82 パスカルの三角形 ☆

パスカルの三角形とは、1段目は1のみ、2段目からは段の数だけ数字が並び、両端は1、その間は左上と右上の値を足した値、として作っていった数字の並びである(Wikipedia「パスカルの三角形」参照)。このパスカルの三角形を15段まで計算して表示するプログラムを作成せよ。ただし表示は左詰で値はスペースで区切って表示するのでよい(三角形に並べなくてもよい)。

【実行例】
$ ./knock82
1 
1 1 
1 2 1 
1 3 3 1 
1 4 6 4 1 
1 5 10 10 5 1 
1 6 15 20 15 6 1 
1 7 21 35 35 21 7 1 
1 8 28 56 70 56 28 8 1 
1 9 36 84 126 126 84 36 9 1 
1 10 45 120 210 252 210 120 45 10 1 
1 11 55 165 330 462 462 330 165 55 11 1 
1 12 66 220 495 792 924 792 495 220 66 12 1 
1 13 78 286 715 1287 1716 1716 1287 715 286 78 13 1 
1 14 91 364 1001 2002 3003 3432 3003 2002 1001 364 91 14 1
$

ヒント:2次元配列を使うとよい。両端でないi段目、左からj番目の値a[i][j]は、一つ上の段の値を使って計算できる。上の実行結果を見て考えるとよいだろう。

No. 83 じゃんけん5回勝負 ☆

次の仕様のじゃんけんプログラムを作成せよ。
・人間は、グー、チョキ、パーをそれぞれ0、1、2の数字で入力する。
・コンピュータは乱数を使って出す手を選ぶ。乱数の使い方は演習資料の高度なテクニック集を見よ。
・5回勝負として、人間とコンピュータの勝った回数を数え、勝敗がつくたびに1回ずつ表示する。あいこは決着がつくまで再勝負。途中でどちらかが3勝しても、5回最後まで勝負を続ける。
・指定された範囲以外の値を入力したら負けにする

【実行例。下線部は入力値の例。メッセージはこの通りでなくてよい。】
$ ./knock83
あなたの手を選んでください(グー0、チョキ1、パー2): 0
コンピュータはチョキ
あなたの勝ち
あなた1勝、わたし0勝
あなたの手を選んでください(グー0、チョキ1、パー2): 2
コンピュータはパー
あいこ
あなたの手を選んでください(グー0、チョキ1、パー2): 2
コンピュータはチョキ
わたしの勝ち
あなた1勝、わたし1勝
あなたの手を選んでください(グー0、チョキ1、パー2): 3
そんな手はありません。あなたの負け
あなた1勝、わたし2勝
(中略)
あなた3勝、わたし2勝
あなたの総合勝利です。参りました。
$

ヒント:まず1回だけのじゃんけんプログラムを作り、それを元に5回勝負にするとよい。勝敗判定はすべての組み合わせを条件判定する方法でもよいが、値の関係を上手く使うと比較的簡単な計算で判定できる。

No. 84 トランプを切る ☆☆

トランプをランダムに順番を変えて表示するプログラムを作成せよ。トランプは4つのスート(マーク)、1〜13までの数字の52枚である。トランプを表現する配列を作り、適当に順序を入れ替えていけばよい。適当に順序を入れ替えるには、例えば2つの入れ替えるカードを乱数を使って選び、それらを入れ替える操作を何回も繰り返せばよい。

【実行例、表示の方法はこの通りでなくてもよい】
$ ./knock84
ダイヤ5
クローバーA
クローバー7
ダイヤ8
クローバー10
ダイヤK
ダイヤ4
スペード9
ハートQ
(以下略)

ヒント:トランプを数値で表現するには、スートと数字を別々に配列にする方法、それらを2次元配列にする方法、0から51までの1次元配列として扱い最後に表示する際に計算でスートと数字を取り出す方法、などが考えられる。なお、2つの入れ替えるカードを選ぶ代わりに、最初の要素から最後の要素までを順番に選び、それぞれについてランダムに選んだ入れ替え先のカードと入れ替えることで、少ない回数で確実にランダムな順序とすることができる。

No. 85 石取りゲーム ☆☆

最初に石の個数を入力し(10個以上とする)、二人のプレイヤーが交互に1〜3個ずつ石を取り、最後の1個を取った方が負けとなるゲームがある。このゲームプログラムを作成せよ。具体的には実行例を参照のこと。

【実行例、下線部は入力例】
$ ./knock85
石の数を入力してください(10以上): 15
石の数: 15
プレイヤー1の番です
何個取る(1〜3個)? 3
石の数: 12
プレイヤー2の番です
何個取る(1〜3個)? 2
石の数: 10
プレイヤー1の番です
何個取る(1〜3個)? 4
プレイヤー1の番です
何個取る(1〜3個)? 3
石の数: 7
プレイヤー2の番です
何個取る(1〜3個)? 3
石の数: 4
プレイヤー1の番です
何個取る(1〜3個)? 2
石の数: 2
プレイヤー2の番です
何個取る(1〜3個)? 1
石の数: 1
プレイヤー2の勝ち
$ ./knock85
石の数を入力してください(10以上): 10
石の数: 10
プレイヤー1の番です
何個取る(1〜3個)? 3
石の数: 7
プレイヤー2の番です
何個取る(1〜3個)? 2
石の数: 5
プレイヤー1の番です
何個取る(1〜3個)? 3
石の数: 2
プレイヤー2の番です
何個取る(1〜3個)? 3
石の数: -1
プレイヤー2の反則負け

上記実行例中、1〜3以外の数字が入力された場合は再度入力させている。

No. 86 コンピュータ必勝石取りゲーム ☆☆☆

No. 85の石取りゲームを人間とコンピュータが対戦する。どちらから石を取り始めるかはコンピュータが決めてよいとしたとき、コンピュータが必ず勝つプログラムを作成せよ。

【実行例、下線部は入力例】
$ ./knock86
石の数を入力してください(10以上): 20
石の数: 20
ではわたしから
3個取ります
石の数: 17
何個取る(1〜3個)? 3
石の数: 14
1個取ります
石の数: 13
何個取る(1〜3個)? 4
何個取る(1〜3個)? 0
何個取る(1〜3個)? 1
石の数: 12
3個取ります
石の数: 9
何個取る(1〜3個)? 2
石の数: 7
2個取ります
石の数: 5
何個取る(1〜3個)? 3
石の数: 2
1個取ります
石の数: 1
わたしの勝ち
$ ./knock85
石の数を入力してください(10以上): 21
石の数: 21
あなたからどうぞ
何個取る(1〜3個)? 3
石の数: 18
1個取ります
石の数: 17
(以下略)

ヒント:最後の1個をプレイヤーに取らせるには、何個目を取らせればよいか?上の実行例もヒントになっている。

No. 87 運命数 ☆☆

カバラ数秘術という簡単な占いがある。誕生日を年(西暦)・月・日で表し、それぞれの数字を足し合わせる。合計した数字が10以上であれば、再びすべての桁の数字を足し合わせる。これを1桁の数字になるまで繰り返し、得られた数字を運命数とする。ただし、計算途中で11、22、33のようにゾロ目の数字になった場合は、それを運命数とする。
例:2015年12月23日→2+0+1+5+1+2+2+3=16→1+6=7
運命数を計算するプログラムを作成せよ。

【実行例、下線部は入力例】
$ ./knock86
誕生日をYYYYMMDDの形式で入力してください: 20151223
運命数は7
$ ./knock86
誕生日をYYYYMMDDの形式で入力してください: 20151011
運命数は11
$

ヒント:1の桁の数字は10で割った余りである。10で割ると1の桁を捨てて、それぞれの桁を右にずらした値になる。10で割った値が0になるまでこれらを繰り返すことで、各桁の数字を取り出すことができる。

No. 88 big or small ☆

コンピュータは1から99の数字をランダムに選ぶ(正解値と呼ぶ)。プレイヤは値を入力し、正解値と一致すればクリアとなり値を入力した回数を表示する。一致しなければ正解値が入力値より大きいか小さいかを表示する。この数当てゲームプログラムを作成せよ。

【実行例、下線部は入力例】
$ ./knock87
数を入力: 50
それより小さいです
数を入力: 25
それより小さいです
数を入力: 13
それより大きいです
数を入力: 19
それより小さいです
数を入力: 16
それより小さいです
数を入力: 14
正解!! 6回でクリア
$

No. 89 逆 big or small ☆☆☆

プレイヤは1から99の数字をランダムに選ぶ(正解値と呼ぶ)。コンピュータは値を推測して表示する(推測値と呼ぶ)。プレイヤは、推測値が正解値と一致していれば0、推測値よりも正解値が大きければ正の値、推測値よりも正解値が小さければ負の値を入力する。推測値が正解値と一致すればクリアとなり回数を表示して終了する。プレイヤがズルをしない(正解値を変えたりしないなど)場合、多くとも7回までに必ずクリアできるプログラムを作成せよ。

【実行例、下線部は入力例】
$ ./knock88
50ですか? 1
75ですか? -1
62ですか? -1
56ですか? -1
53ですか? -1
51ですか? 1
52ですか? 0
7回で当てました
$ ./knock88
50ですか? -1
25ですか? -1
13ですか? -1
7ですか? 1
10ですか? 0
5回で当てました
$

ヒント:2^7 = 128 > 99であるので7回までにクリアすることができる。若干余裕があるので、上記の実行例の通りでなくても同じような方法ならばクリアすることが可能である。

No. 90 ブラックジャックその1 ☆☆

トランプをシャッフルするプログラムはNo.84で作成した。これを使って、ブラックジャックゲームを作ってみよう。ブラックジャックは、最初に2枚のカードを配り、2〜10は数字通り、JとQとKは10、Aは1か11として合計し21に近いほど勝ちとなるが、21を超えると負け(バストと呼ぶ)というゲームである。
まず最初にトランプをシャッフルし、2枚を先頭から順番に引き、それらのカードの数字(マークは無視してよい)と合計値を表示するプログラムを作成せよ。

【実行例、表示の方法はこの通りでなくてもよい】
$ ./knock90
2 7 : 合計9
$ ./knock90
9 J : 合計19
$ ./knock90
A K : 合計21
$

ヒント:2枚だけなのでAは11と数えるのでよいが、後のために、とりあえず11として合計値を計算し、21を超える場合は1として数える(合計値から10を引く)とよい。

No. 91 ブラックジャックその2 ☆☆☆☆

No.90で作ったブラックジャックゲームをさらに進化させよう。ブラックジャックでは、最初に配られた2枚の合計では足りない場合、21を超えない限り何枚でもカードを追加で引くことができる。
合計が16以下の場合はもう一枚カードを引き、17以上になったら止める、というルールで自動的にカードを引くプログラムを作成せよ。

【実行例、表示の方法はこの通りでなくてもよい】
$ ./knock91
8 6 : 合計14
もう一枚引きます
8 6 4 : 合計18
これでOKです
$ ./knock91
8 2 : 合計10
もう一枚引きます
8 2 3 : 合計13
もう一枚引きます
8 2 3 3 : 合計16
もう一枚引きます
8 2 3 3 5 : 合計21
これでOKです
$ ./knock91
K 5 : 合計15
もう一枚引きます
K 5 Q : 合計25
バストです
$

ヒント:何枚目まで引いたか覚えておく変数を作る。バストするか17以上になるまで引いた枚数を1つ増やし、表示を繰り返す。手持ちのカードを覚えておく配列を別に作って、引いたカードをコピーするようにしてもよいだろう(対戦化するならこのような工夫が必要になる)。

No. 92 世界の人 ☆

1から50まで順に表示していくが、3の倍数と3のつく数字のときは頭に"aho"と付けて表示するプログラムを作成せよ。

【実行例】
$ ./knock92
1
2
aho 3
4
5
aho 6
7
8
aho 9
10
11
aho 12
aho 13
14
(途中省略)
29
aho 30
aho 31
aho 32
aho 33
aho 34
aho 35
(以下省略)
49
50
$

ヒント:50までの数字なので、3のつく数字は一の桁か十の桁のどちらかが3の場合となる。一の桁は10で割った余りで判定できる。十の桁は範囲を考えればよい。(次の92と同じ方法で判定してもよい)

No. 93 宇宙の人 ☆☆☆

まず開始値と終了値をそれぞれ入力させる。次に、開始値から終了値まで順に、3の倍数と3のつく数字のときは頭に"aho"と付けて表示するプログラムを作成せよ。開始値と終了値の値の妥当性(例えば終了値の方が開始値よりも大きいか)チェックは省略してよい。

【実行例, 下線部は入力例】
$ ./knock92
start: 290
end: 310
290
aho 291
292
aho 293
aho 294
295
296
aho 297
298
299
aho 300
aho 301
aho 302
aho 303
aho 304
aho 305
aho 306
aho 307
aho 308
aho 309
aho 310
$

ヒント:3のつく数字の判定は、どのような数字でも対応できるように、それぞれの桁の数字を取り出して3かどうかを判定する必要がある。No.87を参考にせよ。
また、条件が複雑になる場合、次のような方法を使うとよい:まずある変数の値を0としておき、いずれかの条件が該当したらその変数の値を1にする。すべての条件チェックが終わったら、その変数の値が0か1かで処理を切り替える。このような条件の成否を記憶しておく変数をフラグ変数と呼ぶ。

No. 94 hit and blow その1 ☆☆☆

hit and blowという数当てゲームがある。出題者は0〜9999の範囲の数字を正解として選ぶ。次に、解答者は予想する数字を言う。出題者は同じ桁(位置)に同じ数字があればヒット、桁は違うが同じ数字があればブローとして数え、ヒットとブローの数を答える(3桁以下の数字は頭に0が付いているものとする)。例えば、次のようになる:
正解:1234 予想:1234 → 4ヒット(=クリア)
正解:1234 予想:5678 → 0ヒット0ブロー
正解:1234 予想:1892 → 1ヒット1ブロー
正解:0034 予想:3400 → 0ヒット4ブロー
正解:1222 予想:1234 → 2ヒット0ブロー(ヒットはブローより優先して判定する)
正解:1112 予想:1221 → 1ヒット2ブロー

このゲームを3回に分けて作ってみよう。まず、コンピュータは正解となる4つの数字をランダムに選ぶ(同じ数字を何回使ってもよいし、0で始まってもよい)。次に、プレイヤーに4桁の数字を入力させる。そして、ヒットの数を数え、表示するプログラムを作成せよ。

【実行例、下線部は入力例】
$ ./knock94
4桁の数字を入力: 1234
target = 7107
0 hit
$ ./knock94
4桁の数字を入力: 1234
target = 9834
2 hit
$ ./knock94
4桁の数字を入力: 0000
target = 0048
2 hit
$

ヒント:正解の数字は、4桁の数字を別々に選ぶのでよい。後の判定のために配列に格納しておくと都合が良い。
プレイヤーの入力する数字は整数値で入力させ、No.87と同じ方法で各桁の数字を取り出して、別の配列に格納しておく。この時、逆順に(1の位から)数字を取り出せば、最初の桁が0であってもうまくいく。
入力値の各桁の数字が取り出せたら、各桁の数字を比較して一致している個数をカウントすればよい。

No. 95 hit and blow その2 ☆☆☆☆☆

No.94に続いて、ブローの数も数えて表示するプログラムを作成せよ。(No.94のプログラムをコピーして、それに追加するとよい。)

【実行例、下線部は入力例】
$ ./knock95
4桁の数字を入力: 1234
target = 3295
1 hit, 1 blow
$ ./knock94
4桁の数字を入力: 1234
target = 3318
0 hit, 2 blow
$ ./knock94
4桁の数字を入力: 0012
target = 0210
2 hit, 2 blow
$

ヒント:ヒットはブローよりも優先されるので、まずヒットのチェックを行う。この時、ヒットした数字は再びブローでチェックしてはいけないことに注意。また、ブローをチェックする際にも、一度ブローと判定した数字はチェックしてはならない(正解、予想値ともに)。再びチェックしてしまうことを防止する方法は様々考えられるが、例えばヒットやブローになった桁を覚えておくフラグ変数を使う、ヒットやブローになった数字を使わない数字(例えば-1)に書き換えてチェック対象から外す(この方法の場合は元の正解を消してしまわないように配列をコピーしておくとよいだろう)、などが考えられる。

No. 96 hit and blow その3 ☆☆☆☆☆

No.95に続いて、正解と一致するまで繰り返して予想させるようにしてゲームを完成させよう。

【実行例、下線部は入力例】
$ ./knock96
1回目
4桁の数字を入力: 1234
0 hit, 2 blow
2回目
4桁の数字を入力: 5678
0 hit, 1 blow
3回目
4桁の数字を入力: 9090
0 hit, 1 blow
4回目
4桁の数字を入力: 9912
0 hit, 2 blow
5回目
4桁の数字を入力: 0301
0 hit, 2 blow
6回目
4桁の数字を入力: 6565
1 hit, 0 blow
7回目
4桁の数字を入力: 4529
1 hit, 0 blow
8回目
4桁の数字を入力: 3169
正解
$

ヒント:入力からヒット・ブローのチェックまでを無限ループとし、1回繰り返すごとに回数を増やしていく。4ヒットになったら正解として、無限ループを終了する(break;を使うとよいだろう)。

No. 97 ビンゴその1 ☆☆☆

ビンゴゲームのカードを作るプログラムを作ろう。縦5マス、横5マス、計25マスのそれぞれに1〜75までの数字をランダムに配置する。同じ番号は2回以上配置しない。作成したカードは、実行例のようにタブ(\t)を開けて表示すること。
※一般的なビンゴカードは、縦の5列それぞれは1〜15、16〜30、31〜45、46〜60、61〜75のそれぞれの数字のうち5つずつを配置し、中央のマスはフリーとしているが、ここでは簡単のためにこのようにしている。余裕があれば一般的なカードを作ってるとよいだろう。

【実行例】
$ ./knock97
26	64	27	23	17	
34	54	65	37	25	
24	30	8	57	44	
35	68	43	3	18	
13	42	38	73	10
$

ヒント:同じ番号を2回配置しないための方法としては、例えば75個の数字を配列に入れてランダムに順番をシャッフルし(No.84参照)、先頭から順番にカードに配置していけばよい。他にも方法は考えられる。カードは、No.98のために2次元配列で表現するのがよい。

No. 98 ビンゴその2 ☆☆☆☆☆

No.97で作ったビンゴカードで、ビンゴの抽選をするプログラムを作ろう。1〜75の数字をランダムな順番で1つずつ選んでいく。選んだ数字がカードにあれば、その数字のマス目を開ける。空いたマス目が縦横斜めのいずれかに5つ並べばビンゴとなり終了する。抽選の経過がわかるように表示を工夫しよう。

【実行例】
$ ./knock98
56	33	22	51	62	
12	17	66	30	6	
53	43	48	71	37	
59	34	8	68	25	
67	23	16	28	20	
1個目: 12
あった!
56	33	22	51	62	
0	17	66	30	6	
53	43	48	71	37	
59	34	8	68	25	
67	23	16	28	20	
2個目: 45
56	33	22	51	62	
0	17	66	30	6	
53	43	48	71	37	
59	34	8	68	25	
67	23	16	28	20
(途中省略)
56個目: 44
0	0	22	0	0	
0	0	0	0	6	
0	0	0	71	0	
0	34	0	68	0	
67	0	0	0	0	
57個目: 68
あった!
0	0	22	0	0	
0	0	0	0	6	
0	0	0	71	0	
0	34	0	0	0	
67	0	0	0	0	
***** BINGO *****
$

ヒント:NO.97のプログラムに、抽選する数字をシャッフルしなおす処理と、抽選を行う繰り返しを追加する。抽選は例えば次の手順を行う:1.次の数字を取り出す。2:取り出した数字がカードに含まれているかチェックする。3:含まれていたらそのマス目に目印をつける。上の実行例では、そのマス目の数字を0に書き換えている。4:カードを表示する。5:縦横斜めに並んだかチェックする。縦の5列、横の5行、右上がり斜め、右下がり斜めのそれぞれに対して、全てが0かどうかを判定する。並んだらメッセージを表示してプログラムを終了する。
手順はこれに限らない。少々手間のかかるプログラムであるが、行うべき処理を分割して考えよう。

No. 99 自由制作 ☆×?

自由に作品を作ろう。HandyGrpahicなどのグラフィクスライブラリを使って絵を表示するプログラムでもよい。