以下の C による初歩の C プログラミング 100 本ノックを Julia で解いてみました。
基礎プロI 100本ノック 上級編
http://www.cc.kyoto-su.ac.jp/~mmina/bp1/hundredKnocksAdvanced.html
各プログラムにおいて、特に指定が無い限りは入力値が指定された形式であるかどうかをチェックする必要はない(例えば整数型の値を入力させるところでアルファベットを入力された場合など)。
問題の順序は難しさの順序ではないので、好きな問題から手をつけるとよいだろう。難しさの目安として問題の後ろに☆をつけておく(多いほど難しいと思われる)。
No. 80 互いに素 ☆
2つの正の整数値を入力させ、互いに素であるか判定するプログラムを作成せよ。なお、2つの正の整数が互いに素とは、1以外に共通公約数を持たない関係のことである。
print("2つの値をスペースで区切って入力:")
(a, b) = parse.(Int, split(readline()))
if gcd(a, b) == 1
println("互いに素")
else
println("互いに素でない")
end
2つの値をスペースで区切って入力:
stdin> 69 23
互いに素でない
ユークリッドの互除法により最大公約数を求める
print("2つの値をスペースで区切って入力:")
(a, b) = parse.(Int, split(readline()))
while b != 0
(a, b) = (b, a%b)
end
# a が最大公約数
if a == 1
println("互いに素")
else
println("互いに素でない")
end
2つの値をスペースで区切って入力:
stdin> 69 23
互いに素でない
No. 81 中間値 ☆
3つの整数値を入力させ、3つの値のうち2番目に大きい値を表示するプログラムを作成せよ。
3つの整数値は相異なるという条件のもとであれば,「3個の整数は相異なるとすれば,3個の整数の和から,一番小さい整数と,一番大きい整数を引けばよい」。
print("3つの値を入力:")
(a, b, c) = parse.(Int, split(readline()))
println("$(a + b + c - minimum([a, b, c]) - maximum([a, b, c]))")
3つの値を入力:
stdin> 16 8 21
16
3個の整数のいずれかは同じとすれば,
2 2 1 のときは 1
2 1 1 のときは 1
2 2 2 のときは 解なし
No. 82 パスカルの三角形 ☆
パスカルの三角形とは、1段目は1のみ、2段目からは段の数だけ数字が並び、両端は1、その間は左上と右上の値を足した値、として作っていった数字の並びである(Wikipedia「パスカルの三角形」参照)。このパスカルの三角形を15段まで計算して表示するプログラムを作成せよ。ただし表示は左詰で値はスペースで区切って表示するのでよい(三角形に並べなくてもよい)
using Combinatorics
for n in 0:14
[print(x, " ") for x in binomial.(n, 0:n)]
println()
end
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
愚直に作る
p = zeros(Int, 15, 17)
p[1, 2] = 1
println(1)
for i in 2:15
for j in 2:i+1
p[i, j] = p[i - 1, j - 1] + p[i - 1, j]
end
[print(x, " ") for x in p[i, 2:i+1]]
println()
end
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
注
実際のパスカルの三角形は p[i, 2:i+1], i = 1, 2, ... に作られる。
これにより,最初の項だとか最後の項だとか考えなくて済む。
No. 83 じゃんけん5回勝負 ☆
次の仕様のじゃんけんプログラムを作成せよ。
- 人間は、グー、チョキ、パーをそれぞれ0、1、2の数字で入力する。
- コンピュータは乱数を使って出す手を選ぶ。乱数の使い方は演習資料の高度なテクニック集を見よ。
- 5回勝負として、人間とコンピュータの勝った回数を数え、勝敗がつくたびに1回ずつ表示する。あいこは決着がつくまで再勝負。途中でどちらかが3勝しても、5回最後まで勝負を続ける。
- 指定された範囲以外の値を入力したら負けにする
function janken()
print("あなたの手を選んでください(グー0、チョキ1、パー2):")
while true
you = parse(Int, replace(readline(), "." => "9")) # 小数点を含む数は 0, 1, 2 以外の数になる
if you ∉ 0:2 # ∉ は 'not in'
println("そんな手はありません。あなたの負け")
return 1
end
computer = rand(0:2, 1)[1]
println("$you, $computer")
result = (you - computer + 3) % 3
result != 0 && return result
print("あいこでした。もう一度あなたの手を選んでください(グー0、チョキ1、パー2):")
end
end
(you, computer) = (0, 0)
for i in 1:5
if janken() == 2
you += 1
else
computer += 1
end
println("あなた$(you)勝,わたし$(computer)勝")
end
if you > computer
print("あなたの総合勝利です。参りました。")
else
print("わたしの総合勝利です。ありがとうございました。")
end
あなたの手を選んでください(グー0、チョキ1、パー2):
stdin> 0
0, 1
あなた1勝,わたし0勝
あなたの手を選んでください(グー0、チョキ1、パー2):
stdin> 0
0, 1
あなた2勝,わたし0勝
あなたの手を選んでください(グー0、チョキ1、パー2):
stdin> 0
0, 2
あなた2勝,わたし1勝
あなたの手を選んでください(グー0、チョキ1、パー2):
stdin> 0
0, 0
あいこでした。もう一度あなたの手を選んでください(グー0、チョキ1、パー2):
stdin> 0
0, 2
あなた2勝,わたし2勝
あなたの手を選んでください(グー0、チョキ1、パー2):
stdin> 0
0, 2
あなた2勝,わたし3勝
わたしの総合勝利です。ありがとうございました。
No. 84 トランプを切る ☆☆
トランプをランダムに順番を変えて表示するプログラムを作成せよ。トランプは4つのスート(マーク)、1〜13までの数字の52枚である。トランプを表現する配列を作り、適当に順序を入れ替えていけばよい。適当に順序を入れ替えるには、例えば2つの入れ替えるカードを乱数を使って選び、それらを入れ替える操作を何回も繰り返せばよい。
using Random
suits = ["♥", "♦", "♠", "♣"]
numbers = string.(collect(1:13))
cards = vec([i*j for j in numbers, i in suits])
println(cards)
cards = cards[shuffle(collect(1:52))]
println(cards)
["♥1", "♥2", "♥3", "♥4", "♥5", "♥6", "♥7", "♥8", "♥9", "♥10", "♥11", "♥12", "♥13", "♦1", "♦2", "♦3", "♦4", "♦5", "♦6", "♦7", "♦8", "♦9", "♦10", "♦11", "♦12", "♦13", "♠1", "♠2", "♠3", "♠4", "♠5", "♠6", "♠7", "♠8", "♠9", "♠10", "♠11", "♠12", "♠13", "♣1", "♣2", "♣3", "♣4", "♣5", "♣6", "♣7", "♣8", "♣9", "♣10", "♣11", "♣12", "♣13"]
["♣12", "♠9", "♦1", "♥11", "♣9", "♠2", "♥10", "♣1", "♠13", "♥5", "♦3", "♥1", "♣3", "♦10", "♥7", "♣11", "♠4", "♣2", "♦11", "♠6", "♦4", "♦7", "♠11", "♥12", "♥13", "♠8", "♠5", "♦8", "♠3", "♣10", "♥6", "♣8", "♥4", "♦13", "♠1", "♣4", "♣5", "♦2", "♥3", "♥9", "♣13", "♦5", "♦12", "♦9", "♥8", "♥2", "♦6", "♣7", "♣6", "♠7", "♠12", "♠10"]
愚直に作る
suits = ["♥", "♦", "♠", "♣"]
numbers = string.(collect((1:13)))
cards = vec([i*j for j in numbers, i in suits])
println(cards)
for i in 1:52
j = rand(1:52, 1)[1]
(cards[j], cards[i]) = (cards[i], cards[j])
end
println(cards)
["♥1", "♥2", "♥3", "♥4", "♥5", "♥6", "♥7", "♥8", "♥9", "♥10", "♥11", "♥12", "♥13", "♦1", "♦2", "♦3", "♦4", "♦5", "♦6", "♦7", "♦8", "♦9", "♦10", "♦11", "♦12", "♦13", "♠1", "♠2", "♠3", "♠4", "♠5", "♠6", "♠7", "♠8", "♠9", "♠10", "♠11", "♠12", "♠13", "♣1", "♣2", "♣3", "♣4", "♣5", "♣6", "♣7", "♣8", "♣9", "♣10", "♣11", "♣12", "♣13"]
["♣8", "♦13", "♥10", "♠8", "♦9", "♠2", "♥12", "♦5", "♥5", "♠10", "♥8", "♦2", "♠13", "♠3", "♥4", "♦8", "♦6", "♠6", "♥3", "♦3", "♠11", "♠9", "♣2", "♠5", "♠12", "♥1", "♥6", "♣13", "♦7", "♦12", "♣3", "♣9", "♠7", "♥2", "♣1", "♣7", "♦4", "♣10", "♣4", "♣11", "♠1", "♣6", "♥9", "♥7", "♥11", "♦11", "♣12", "♣5", "♥13", "♠4", "♦10", "♦1"]
注
2個の乱数番目のカードを入れ替えることを52回繰り返しても,ランダム性は保証できない(シャッフルされないカードが残る可能性がある)。かと言って,数千回やるのは無駄というものである。
i = 1,2,..., 52 に対して,i 番目のカードと乱数番目のカードを入れ替えるを行えばランダム性が保証できる。
No. 85 石取りゲーム ☆☆
最初に石の個数を入力し(10個以上とする)、二人のプレイヤーが交互に1〜3個ずつ石を取り、最後の1個を取った方が負けとなるゲームがある。このゲームプログラムを作成せよ。具体的には実行例を参照のこと。
function 石取り(石の数, player)
println("石の数 = $石の数")
while true
print("プレイヤー$(player)の番です\n何個取る(1〜$(min(石の数, 3))個)?")
n = parse(Int, readline())
if 1 <= n <= min(石の数, 3)
石の数 -= n
break
end
end
if 石の数 == 1
println("プレイヤー$(player)の勝ちです")
end
return 石の数
end
print("石の数を入力してください(10以上):")
石の数 = parse(Int, readline())
while 石の数 > 0
(石の数 = 石取り(石の数, 1)) == 1 && break
(石の数 = 石取り(石の数, 2)) == 1 && break
end
石の数を入力してください(10以上):
stdin> 10
石の数 = 10
プレイヤー1の番です
何個取る(1〜3個)?
stdin> 1
石の数 = 9
プレイヤー2の番です
何個取る(1〜3個)?
stdin> 2
石の数 = 7
プレイヤー1の番です
何個取る(1〜3個)?
stdin> 1
石の数 = 6
プレイヤー2の番です
何個取る(1〜3個)?
stdin> 2
石の数 = 4
プレイヤー1の番です
何個取る(1〜3個)?
stdin> 1
石の数 = 3
プレイヤー2の番です
何個取る(1〜3個)?
stdin> 2
プレイヤー2の勝ちです
No. 86 コンピュータ必勝石取りゲーム ☆☆☆
No. 85の石取りゲームを人間とコンピュータが対戦する。どちらから石を取り始めるかはコンピュータが決めてよいとしたとき、コンピュータが必ず勝つプログラムを作成せよ。
最初に指定された数が4の倍数プラス1なら後手、それ以外なら先手を選ぶ。
先手を選んだ場合
まず最初の1手は、とった後の残りの石の数が4の倍数プラス1になるようにとる。
そのあとは、相手の取った石の数との和が4になるようにとっていく。
後手を選んだ場合
最初から相手の取った数との和が4になるようにとっていく。
print("石の数を入力してください(10以上):")
石の数 = parse(Int, readline())
if 石の数 % 4 != 1
println("石の数: ", 石の数)
println("ではわたしから")
n = (石の数%4 + 3)%4
println(n, "個とります")
石の数 -= n
end
while 石の数 > 1
println("石の数: ", 石の数)
while true
print("何個取る(1〜3個)?")
n = parse(Int, readline())
if 1 <= n <= min(石の数, 3)
石の数 -= n
break
end
end
println("石の数: ", 石の数)
n = 4 - n
println(n, "個とります")
石の数 -= n
if 石の数 == 1
println("石の数: ", 石の数)
println("次の手で,あなたは残った 1 個を取らざるを得ないので,あなたの負けです。")
break
end
end
石の数を入力してください(10以上):
stdin> 21
石の数: 21
何個取る(1〜3個)?
stdin> 2
石の数: 19
2個とります
石の数: 17
何個取る(1〜3個)?
stdin> 2
石の数: 15
2個とります
石の数: 13
何個取る(1〜3個)?
stdin> 2
石の数: 11
2個とります
石の数: 9
何個取る(1〜3個)?
stdin> 2
石の数: 7
2個とります
石の数: 5
何個取る(1〜3個)?
stdin> 2
石の数: 3
2個とります
石の数: 1
次の手で,あなたは残った 1 個を取らざるを得ないので,あなたの負けです。
No. 87 運命数 ☆☆
カバラ数秘術という簡単な占いがある。誕生日を年(西暦)・月・日で表し、それぞれの数字を足し合わせる。合計した数字が10以上であれば、再びすべての桁の数字を足し合わせる。これを1桁の数字になるまで繰り返し、得られた数字を運命数とする。ただし、計算途中で11、22、33のようにゾロ目の数字になった場合は、それを運命数とする。
例:2015年12月23日→2+0+1+5+1+2+2+3=16→1+6=7
運命数を計算するプログラムを作成せよ。
print("誕生日をYYYYMMDDの形式で入力してください:")
i = readline()
n = 0 # 注
while true
n = sum(parse.(Int, split(i, "")))
n < 10 && break
if 11 <= n <= 99
(n1, n2) = divrem(n, 10)
n1 == n2 && break
end
i = string(sum(n))
end
println(n)
誕生日をYYYYMMDDの形式で入力してください:
stdin> 20201212
1
注
代入する値は何でもよいが,これがないと while ループ内で設定される n がローカル変数になり,したがってwhile ループを抜けた後に n を参照すると「未定義エラー」になる。
while ループの外で定義される n がある場合,while ループ内の n はループの外のグローバル変数になり,したがって while ループ内で再定義された n を while ループを抜けた後に n を参照すると while ループ内で再定義された n になる。
REPL 環境で実行している場合などでは,これ以前の何処かで n に何らかの値が代入されていることもありうる。そのような場合にはここで n = 0 する必要はない。
No. 88 big or small ☆
コンピュータは1から99の数字をランダムに選ぶ(正解値と呼ぶ)。プレイヤは値を入力し、正解値と一致すればクリアとなり値を入力した回数を表示する。一致しなければ正解値が入力値より大きいか小さいかを表示する。この数当てゲームプログラムを作成せよ。
正解値 = rand(1:99, 1)[1] # 1 個の要素を持つベクトルなので,取り出すには添字指定が必須
count = 0
while true
count += 1
print("数を入力:")
n = parse(Int, readline())
n == 正解値 && (println("正解!! $(count)回でクリア"); break)
println("それより" * (n < 正解値 ? "大き" : "小さ") * "いです")
end
数を入力:
stdin> 50
それより小さいです
数を入力:
stdin> 25
それより大きいです
数を入力:
stdin> 37
それより小さいです
数を入力:
stdin> 31
それより大きいです
数を入力:
stdin> 34
それより小さいです
数を入力:
stdin> 32
それより大きいです
数を入力:
stdin> 33
正解!! 7回でクリア
No. 89 逆 big or small ☆☆☆
プレイヤは1から99の数字をランダムに選ぶ(正解値と呼ぶ)。コンピュータは値を推測して表示する(推測値と呼ぶ)。プレイヤは、推測値が正解値と一致していれば0、推測値よりも正解値が大きければ正の値、推測値よりも正解値が小さければ負の値を入力する。推測値が正解値と一致すればクリアとなり回数を表示して終了する。プレイヤがズルをしない(正解値を変えたりしないなど)場合、多くとも7回までに必ずクリアできるプログラムを作成せよ。
print("input number:")
正解値 = parse(Int, readline())
count = 0
(lo, hi) = (1, 99)
while true
count += 1
n = (lo + hi) ÷ 2
println("$(n)ですか?")
n == 正解値 && (println("正解!! $(count)回でクリア"); break)
if n < 正解値 # 注
println("それより大きいです")
lo = n
else
println("それより小さいです")
hi = n
end
end
input number:
stdin> 58
50ですか?
それより大きいです
74ですか?
それより小さいです
62ですか?
それより小さいです
56ですか?
それより大きいです
59ですか?
それより小さいです
57ですか?
それより大きいです
58ですか?
正解!! 7回でクリア
注
大きいか小さいかだけを教えてもらい,二分探索する。
No. 90 ブラックジャックその1 ☆☆
トランプをシャッフルするプログラムはNo.84で作成した。これを使って、ブラックジャックゲームを作ってみよう。ブラックジャックは、最初に2枚のカードを配り、2〜10は数字通り、JとQとKは10、Aは1か11として合計し21に近いほど勝ちとなるが、21を超えると負け(バストと呼ぶ)というゲームである。
まず最初にトランプをシャッフルし、2枚を先頭から順番に引き、それらのカードの数字(マークは無視してよい)と合計値を表示するプログラムを作成せよ。
using Random
numbers = shuffle(repeat(1:13, 4))
# println(numbers)
for i in 1:13*2
one = popat!(numbers, 1)
two = popat!(numbers, 1)
one == 1 && (one = -11) # J の 11 と区別するため -11 にする
two == 1 && (two = -11)
result = abs(one) + abs(two)
result > 21 && -11 in [one, two] && (result -= 10) # 1 にして合計するのと同じ
println("$one + $two ==> $result")
end
13 + 11 ==> 24
5 + 12 ==> 17
3 + 7 ==> 10
3 + 9 ==> 12
6 + 2 ==> 8
12 + 3 ==> 15
5 + 11 ==> 16
8 + 7 ==> 15
8 + 3 ==> 11
-11 + 13 ==> 14
7 + 2 ==> 9
10 + 9 ==> 19
13 + -11 ==> 14
5 + 4 ==> 9
9 + 2 ==> 11
11 + 6 ==> 17
12 + 6 ==> 18
2 + 4 ==> 6
11 + -11 ==> 12
7 + 12 ==> 19
10 + 10 ==> 20
10 + 5 ==> 15
4 + 9 ==> 13
4 + 8 ==> 12
8 + 6 ==> 14
13 + -11 ==> 14
No. 91 ブラックジャックその2 ☆☆☆☆
No.90で作ったブラックジャックゲームをさらに進化させよう。ブラックジャックでは、最初に配られた2枚の合計では足りない場合、21を超えない限り何枚でもカードを追加で引くことができる。
合計が16以下の場合はもう一枚カードを引き、17以上になったら止める、というルールで自動的にカードを引くプログラムを作成せよ。
using Random
function replace2(x, old, new)
res = indexin([old], x)[1]
isnothing(res) || (x[res] = new)
return x
end;
function blackjack()
numbers = shuffle(repeat(vcat([-11, collect(2:13)...]), 4))
println(numbers)
hands = []
append!(hands, popat!(numbers, 1))
append!(hands, popat!(numbers, 1))
while length(numbers) > 10 # とりあえずゲームを進められるだろうという限界を設定する
result = sum(abs.(hands))
if result > 21
hands = replace2(hands, -11, 1)
end
result = sum(abs.(hands))
println("sum($hands) ==> $result")
if result > 18
return result
end
append!(hands, popat!(numbers, 1))
end
end;
for i in 1:10
result = blackjack()
if result > 21
println("負け")
else
println("勝ち")
end
end
[11, 3, 2, 13, 9, 2, 4, 10, 3, 6, 5, 9, 13, 11, -11, 7, 3, 10, 11, 10, 8, 8, 6, 5, 9, 3, -11, 2, 6, 7, 12, -11, -11, 4, 12, 6, 5, 12, 4, 8, 13, 4, 5, 10, 9, 8, 12, 11, 2, 7, 7, 13]
sum(Any[11, 3]) ==> 14
sum(Any[11, 3, 2]) ==> 16
sum(Any[11, 3, 2, 13]) ==> 29
負け
[10, 4, 12, 13, 8, 11, 5, 7, 7, 10, 3, 9, 7, 8, 11, 5, 3, 3, 10, 11, 12, 2, 2, 4, -11, 9, 12, -11, 2, 5, 8, 11, 8, 6, 4, -11, 4, 13, 6, 5, 9, 9, 6, 3, -11, 6, 7, 13, 13, 10, 2, 12]
sum(Any[10, 4]) ==> 14
sum(Any[10, 4, 12]) ==> 26
負け
[8, -11, 10, 9, 11, 9, 12, 4, 13, 3, 2, 8, 6, 11, -11, 13, 4, 13, 4, 2, 2, 5, 10, 5, 5, 12, 8, 9, 11, 3, 6, -11, 11, 7, 3, 10, 8, 13, 12, 12, 10, 7, 5, 2, 6, 3, 6, 4, -11, 9, 7, 7]
sum(Any[8, -11]) ==> 19
勝ち
[4, 7, -11, 11, 8, 3, 9, 7, 6, 7, 10, 8, 10, 9, 12, 6, 11, 12, 10, 3, 6, 2, 2, 3, -11, 9, 13, 8, 7, 2, 13, 11, -11, 5, 8, -11, 12, 6, 3, 5, 5, 13, 11, 4, 5, 2, 4, 13, 4, 12, 10, 9]
sum(Any[4, 7]) ==> 11
sum(Any[4, 7, 1]) ==> 12
sum(Any[4, 7, 1, 11]) ==> 23
負け
[9, 5, 12, 9, 7, 8, 3, 3, 10, -11, 5, 13, 6, 5, 6, 3, -11, 2, 6, 12, 11, 7, 11, 8, 13, 4, 9, 5, 4, 3, 13, 11, 8, 12, 7, 2, 4, 10, 12, -11, 8, 10, -11, 2, 10, 11, 6, 2, 13, 9, 4, 7]
sum(Any[9, 5]) ==> 14
sum(Any[9, 5, 12]) ==> 26
負け
[3, 12, 8, 3, 10, 9, 10, 7, 9, -11, 6, 13, 2, 3, 9, 2, 13, -11, -11, 11, 5, 7, 12, 6, 11, 11, 4, 6, 7, 5, 9, 11, 2, 12, 10, 8, 4, 4, 5, 10, 13, 13, 8, 5, 6, 2, -11, 3, 8, 12, 4, 7]
sum(Any[3, 12]) ==> 15
sum(Any[3, 12, 8]) ==> 23
負け
[8, 6, 4, 12, 8, 4, 5, 11, 5, 2, 8, 11, -11, 11, 6, 6, 12, 9, 3, 8, -11, 3, 6, 5, 7, 10, -11, 11, 9, 13, 2, 3, 10, 7, 13, 9, 4, 13, 10, 7, 5, 2, 13, 10, 12, 3, -11, 4, 2, 7, 12, 9]
sum(Any[8, 6]) ==> 14
sum(Any[8, 6, 4]) ==> 18
sum(Any[8, 6, 4, 12]) ==> 30
負け
[-11, 8, 9, 7, 6, 10, 10, 5, -11, 3, 5, 6, 3, 2, 4, 13, 7, 9, 3, 3, 11, 11, 9, 7, 7, 2, 5, 6, 8, 8, 12, 6, 2, 4, 10, 13, 13, 12, -11, 2, 5, 4, 11, 11, 8, 9, 13, 12, 12, -11, 10, 4]
sum(Any[-11, 8]) ==> 19
勝ち
[11, 3, 10, 3, -11, 6, 9, 4, 3, 6, 5, 12, 2, 7, 5, 4, 13, 7, 7, 9, 12, 7, -11, 4, 12, 6, 13, 10, 6, 5, 4, 2, 11, 5, 2, 8, 9, 8, 10, 13, 12, 10, 8, 3, 13, 11, -11, 2, 9, 11, 8, -11]
sum(Any[11, 3]) ==> 14
sum(Any[11, 3, 10]) ==> 24
負け
[10, -11, 7, 11, 12, 10, 7, 3, 2, 12, 2, 8, 6, 7, 13, 6, 7, 6, 10, 8, 2, 5, 11, 11, -11, 13, 3, 2, 13, 12, 3, 6, 11, 5, 13, 3, 4, 5, -11, 4, 12, 4, -11, 9, 9, 4, 8, 9, 8, 9, 10, 5]
sum(Any[10, -11]) ==> 21
勝ち
No. 92 世界の人 ☆
1から50まで順に表示していくが、3の倍数と3のつく数字のときは頭に"aho"と付けて表示するプログラムを作成せよ。
for i in 1:50
(i1, i2) = divrem(i, 10)
(i % 3 == 0 || (i1 == 3 || i2 == 3)) && print("aho")
println(i)
end
1
2
aho3
4
5
aho6
7
8
aho9
10
11
aho12
aho13
14
aho15
16
17
aho18
19
20
aho21
22
aho23
aho24
25
26
aho27
28
29
aho30
aho31
aho32
aho33
aho34
aho35
aho36
aho37
aho38
aho39
40
41
aho42
aho43
44
aho45
46
47
aho48
49
50
No. 93 宇宙の人 ☆☆☆
まず開始値と終了値をそれぞれ入力させる。次に、開始値から終了値まで順に、3の倍数と3のつく数字のときは頭に"aho"と付けて表示するプログラムを作成せよ。開始値と終了値の値の妥当性(例えば終了値の方が開始値よりも大きいか)チェックは省略してよい。
print("開始値:")
開始値 = parse(Int, readline())
print("終了値:")
終了値 = parse(Int, readline())
for i in 開始値:終了値
n0 = i
flag = i % 3 == 0
while i > 0
(n1, n2) = divrem(i, 10)
flag |= n2 == 3
i = n1
end
flag && print("aho ")
println(n0)
end
開始値:
stdin> 290
終了値:
stdin> 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
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桁の数字を入力させる。そして、ヒットの数を数え、表示するプログラムを作成せよ。
正解 = rand(0:9, 4)
print("4桁の数を入力:")
数 = parse.(Int, split(readline(), ""))
hit = sum([x == y for (x, y) in zip(正解, 数)])
println(正解)
println("$hit hit")
4桁の数を入力:
stdin> 1222
[9, 6, 4, 3]
0 hit
No. 95 hit and blow その2 ☆☆☆☆☆
No.94に続いて、ブローの数も数えて表示するプログラムを作成せよ。(No.94のプログラムをコピーして、それに追加するとよい。)
正解 = rand(0:9, 4)
print("4桁の数を入力:")
数 = parse.(Int, split(readline(), ""))
正解0 = copy(正解)
数0 = copy(数)
hit = 0
for i in 1:4
if 数[i] == 正解[i]
数[i] = -1
正解[i] = -1
hit += 1
end
end
blow = 0
for i in 1:4
数[i] < 0 && continue
for j in 1:4
正解[j] < 0 && continue
if 数[i] == 正解[j]
for k = 1:4
数[k] == 数[i] && (数[k] = -1)
正解[k] == 正解[j] && (正解[k] = -1)
end
blow += 1
end
end
end
println(正解0)
println("$hit hit")
println("$blow blow")
4桁の数を入力:
stdin> 1111
[8, 1, 2, 5]
1 hit
0 blow
No. 96 hit and blow その3 ☆☆☆☆☆
No.95に続いて、正解と一致するまで繰り返して予想させるようにしてゲームを完成させよう。
function counthitandblow(正解0, 数)
正解 = copy(正解0)
hit = 0
for i in 1:4
if 数[i] == 正解[i]
数[i] = -1
正解[i] = -1
hit += 1
end
end
blow = 0
for i in 1:4
数[i] < 0 && continue
for j in 1:4
正解[j] < 0 && continue
if 数[i] == 正解[j]
for k = 1:4
数[k] == 数[i] && (数[k] = -1)
正解[k] == 正解[j] && (正解[k] = -1)
end
blow += 1
end
end
end
return (hit, blow)
end
counthitandblow (generic function with 1 method)
function hitandblow()
正解 = rand(0:9, 4)
loop = 0
while true
loop += 1
print("$(loop)回目 0000 を入力すれば答えを表示して終了\n4桁の数を入力:")
数 = parse.(Int, split(readline(), ""))
join(string.(数), "") == "0000" && (println("正解 = $(join(string.(正解), ""))"); break)
(hit, blow) = counthitandblow(正解, 数)
hit == 4 && (println("正解です"); break)
println("$hit hit, $blow blow")
end
end
hitandblow()
1回目 0000 を入力すれば答えを表示して終了
4桁の数を入力:
stdin> 1234
0 hit, 1 blow
2回目 0000 を入力すれば答えを表示して終了
4桁の数を入力:
stdin> 5678
2 hit, 0 blow
3回目 0000 を入力すれば答えを表示して終了
4桁の数を入力:
stdin> 9011
0 hit, 0 blow
4回目 0000 を入力すれば答えを表示して終了
4桁の数を入力:
stdin> 2367
0 hit, 1 blow
5回目 0000 を入力すれば答えを表示して終了
4桁の数を入力:
stdin> 0000
正解 = 7478
No. 97 ビンゴその1 ☆☆☆
ビンゴゲームのカードを作るプログラムを作ろう。縦5マス、横5マス、計25マスのそれぞれに1〜75までの数字をランダムに配置する※。同じ番号は2回以上配置しない。作成したカードは、実行例のようにタブ(\t)を開けて表示すること。
※一般的なビンゴカードは、縦の5列それぞれは1〜15、16〜30、31〜45、46〜60、61〜75のそれぞれの数字のうち5つずつを配置し、中央のマスはフリーとしているが、ここでは簡単のためにこのようにしている。余裕があれば一般的なカードを作ってるとよいだろう。
using Random
function prepare()
bingocard = zeros(Int, 5, 5)
for i in 1:5
bingocard[:, i] = shuffle(15(i-1)+1:15i)[1:5]
end
bingocard[3, 3] = 0
return bingocard
end
bingocard = prepare()
Base.print_matrix(stdout, bingocard)
7 29 44 54 72
15 28 39 60 73
6 16 0 58 75
2 21 34 51 63
5 26 36 46 68
No. 98 ビンゴその2 ☆☆☆☆☆
No.97で作ったビンゴカードで、ビンゴの抽選をするプログラムを作ろう。1〜75の数字をランダムな順番で1つずつ選んでいく。選んだ数字がカードにあれば、その数字のマス目を開ける。空いたマス目が縦横斜めのいずれかに5つ並べばビンゴとなり終了する。抽選の経過がわかるように表示を工夫しよう。
function isbingo(bingocard)
return any(vcat(vec(sum(bingocard, dims=1)), sum(bingocard, dims=2),
sum(diag(bingocard)), sum(diag(bingocard[5:-1:1, :]))) .== 0)
end
bingocard = prepare()
抽選番号 = shuffle(1:75)
for (i, 番号) in enumerate(抽選番号)
println("$(i)個目: $番号")
where = bingocard .== 番号
if sum(where) == 1
println("あった!")
bingocard[where] .= 0
if isbingo(bingocard)
println("BINGO")
Base.print_matrix(stdout, bingocard)
println()
break
end
end
Base.print_matrix(stdout, bingocard)
println()
end
1個目: 42
12 24 43 48 62
1 22 39 58 63
7 23 0 53 74
8 21 38 60 64
4 17 34 46 75
2個目: 19
12 24 43 48 62
1 22 39 58 63
7 23 0 53 74
8 21 38 60 64
4 17 34 46 75
3個目: 31
12 24 43 48 62
1 22 39 58 63
7 23 0 53 74
8 21 38 60 64
4 17 34 46 75
4個目: 43
あった!
12 24 0 48 62
1 22 39 58 63
7 23 0 53 74
8 21 38 60 64
4 17 34 46 75
5個目: 54
12 24 0 48 62
1 22 39 58 63
7 23 0 53 74
8 21 38 60 64
4 17 34 46 75
6個目: 14
12 24 0 48 62
1 22 39 58 63
7 23 0 53 74
8 21 38 60 64
4 17 34 46 75
7個目: 68
12 24 0 48 62
1 22 39 58 63
7 23 0 53 74
8 21 38 60 64
4 17 34 46 75
:
途中省略
:
51個目: 72
0 0 0 0 62
0 22 39 0 0
0 23 0 0 0
8 0 0 0 0
0 0 34 46 0
52個目: 23
あった!
BINGO
0 0 0 0 62
0 22 39 0 0
0 0 0 0 0
8 0 0 0 0
0 0 34 46 0
No. 99 自由制作 ☆×?
自由に作品を作ろう。HandyGrpahicなどのグラフィクスライブラリを使って絵を表示するプログラムでもよい。
サイコロを振って出た目の平均値を求める
$n$ 個のサイコロを $m$ 回振り,結果を $m \times n$ 行列に記録する。
行方向の平均値は mean(行列, dims=2)
で求められる。但し,結果は $m \times 1$ 行列なので,必要ならベクトルに変換する。
これを,1 行の関数で書く。
means(n, m=10000) = mean(rand(1:6, m, n), dims=2);
using Plots, Distributions, Statistics
function f(n, m=10000)
x = means(n, m)
p = histogram(x, normalize=:pdf, ylabel="pdf", xlabel="mean of $n dice", label="")
println("mean = $(mean(x)), sd = $(std(x, corrected=false))")
savefig("fig$n.png")
plot!(range(1, 6, step=0.01), pdf.(Normal(mean(x), std(x)), range(1, 6, step=0.01)))
plot!(p)
end;
1 個のダイス[^1]の場合は一様分布だが,要するに度数分布に過ぎない。
平均値と標準偏差の理論値は 3.5 と std(1:6, corrected=false) = 1.707825127659933
「^1」: dice は複数形なので,「1 個のダイス」というのはおかしな言い方だそうだ。
f(1)
mean = 3.4844, sd = 1.7101335152554602
2 個では,三角分布。
f(2)
mean = 3.50925, sd = 1.2042173547578527
3 個だと,だんだん山型になる。
f(3)
mean = 3.5073, sd = 0.9775093287420723
f(10)
mean = 3.4940599999999997, sd = 0.5316302440606628