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

**以下の C による初歩の C プログラミング 100 本ノックを Julia で解いてみました。**

基礎プロI 100本ノック 中級編
http://www.cc.kyoto-su.ac.jp/~mmina/bp1/hundredKnocksMiddle.html

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

## No. 40 even or odd
整数値を入力させ、その値が偶数ならばeven、奇数ならばoddと表示するプログラムを作成せよ。

```julia
print("input number:")
i = parse(Int, readline())

if iseven(i)
    println("$i is even.")
else
    println("$i is odd.")
end
```

    input number:
    stdin>  7
    7 is odd.

以下のようにも。

```julia
print("input number:")
i = parse(Int, readline())

println(i, " is ", ["odd", "even"][iseven(i) + 1], ".")
```

    input number:
    stdin>  7
    7 is odd.

## No. 41 1桁の自然数?
整数値を入力させ、その値が一桁の自然数かそうでないか判定するプログラムを作成せよ。

```julia
print("input number:")
i = parse(Int, readline())

if 0 < i < 10
    println("$i is a single figure.")
else
    println("$i is not a single figure.")
end
```

    input number:
    stdin>  3
    3 is a single figure.

以下のようにも。

```julia
print("input number:")
i = parse(Int, readline())

using Printf
@printf("%d %s a single figure.\n", i, 0 < i < 10 ? "is" : "is not")
```

    input number:
    stdin>  2
    2 is a single figure.

## No. 42 小さい順?
整数値を3つ入力させ、それらの値が小さい順（等しくてもよい）に並んでいるか判定し、小さい順に並んでいる場合はOK、そうなっていない場合はNGと表示するプログラムを作成せよ。

```julia
print("input number 1:")
i = parse(Int, readline())
print("input number 2:")
j = parse(Int, readline())
print("input number 3:")
k = parse(Int, readline())

if i <= j <= k
    println("OK")
else
    println("NG")
end
```

    input number 1:
    stdin>  4
    input number 2:
    stdin>  2
    input number 3:
    stdin>  3
    NG

以下のようにも。

```julia
print("input number 1:")
i = parse(Int, readline())
print("input number 2:")
j = parse(Int, readline())
print("input number 3:")
k = parse(Int, readline())

println(["NG", "OK"][all(diff([i, j, k]) .>= 0) + 1])
```

    input number 1:
    stdin>  1
    input number 2:
    stdin>  3
    input number 3:
    stdin>  2
    "NG"

## No. 43 2次方程式の解の判別
2次方程式 ax^2 + bx + c = 0 （x^2はxの2乗の意味）の係数a, b, cを入力し、2次方程式の解が2つの実数解か、重解か、2つの虚数解かを判別するプログラムを作成せよ。

```julia
print("input a:")
a = parse(Int, readline())
print("input b:")
b = parse(Int, readline())
print("input c:")
c = parse(Int, readline())

d = b^2 - 4a*c
if d > 0
    println("2つの実数解")
elseif d == 0
    println("重解")
else
    println("2つの虚数解")
end
```

    input a:
    stdin>  1
    input b:
    stdin>  4
    input c:
    stdin>  3
    2つの実数解

以下のようにも。

```julia
print("input a:")
a = parse(Int, readline())
print("input b:")
b = parse(Int, readline())
print("input c:")
c = parse(Int, readline())

println(["2つの虚数解", "重解", "2つの実数解"][sign(b^2 - 4a*c) + 2])
```

    input a:
    stdin>  3
    input b:
    stdin>  2
    input c:
    stdin>  -4
    2つの実数解

## No. 44 通貨換算
換算したい金額（円単位）と1ドル何円かを整数値で入力すると、入力した金額が何ドル何セントか計算して表示するプログラムを作成せよ。1セントは1/100ドルである。結果は整数値でよい（1セント未満の端数切り捨て）。

```julia
print("何円?")
円 = parse(Int, readline())
print("1ドルは何円?")
レート = parse(Int, readline())

(ドル, セント) = divrem(div(100円, レート), 100)
println(円,"円は",ドル,"ドル",セント,"セント")
```

    何円?
    stdin>  10000
    1ドルは何円?
    stdin>  120
    10000円は83ドル33セント

divrem(div(100円, レート), 100) は以下のようなことをやっている。

```julia
print("何円?")
円 = parse(Int, readline())
print("1ドルは何円?")
レート = parse(Int, readline())

ドル = 円/レート
セント = 100(ドル - floor(ドル))
println(円,"円は",floor(Int, ドル),"ドル",floor(Int, セント),"セント")
```

    何円?
    stdin>  10000
    1ドルは何円?
    stdin>  120
    10000円は83ドル33セント

## No. 45 タクシー料金
初乗り料金が1700mまで610円、それ以降は313mごとに80円のタクシーがある。このタクシーに乗った距離をm単位で入力し、料金を計算するプログラムを作成せよ。

```julia
print("input number:")
距離 = parse(Int, readline())

if 距離 < 1700
    println("金額 = 610")
else
    println("金額 = $(610 + cld(距離 - 1700, 313)*80)")
end
```

    input number:
    stdin>  10000
    金額 = 2770

ceil(a/b) と cld(a, b) の関係

```julia
print("input number:")
距離 = parse(Int, readline())

println("金額 = ", 610 + (距離 < 1700 ? 0 : cld(距離 - 1700, 313)*80))
```

    input number:
    stdin>  2014
    金額 = 770

## No. 46 入場料
神山美術館の入場料金は、一人600円であるが、5人以上のグループなら一人550円、20人以上の団体なら一人500円である。人数を入力し、入場料の合計を計算するプログラムを作成せよ。

```julia
print("input number:")
n = parse(Int, readline())

if n >= 20
    println(500n)
elseif n >= 5
    println(550n)
else
    println(600n)
end
```

    input number:
    stdin>  22
    11000

## No. 47 値の入れ替え
異なる整数値を2つ入力し、それぞれ別の変数に格納する。そして、それらの変数の値を入れ替えた後、それぞれの変数の値を表示するプログラムを作成せよ。単に順序を変えて表示するだけではダメ。必ず変数の値を入れ替えること。下の実行例の場合、まず変数aに2、bに5が入力された状態から、aの値が5、bの値が2になるように入れ替える。

```julia
print("input a:")
a = parse(Int, readline())
print("input b:")
b = parse(Int, readline())

(a, b) = (b, a)
println("a = $a, b = $b")
```

    input a:
    stdin>  1
    input b:
    stdin>  2
    a = 2, b = 1

Julia や Python では，一時変数を使用しないで値を入れ替えることができる。

## No. 48 繰り返し計算
最初に2以上の整数値を入力し、次の規則で計算し、計算回数と計算結果を表示し、計算結果が1になるまで繰り返すプログラムを作成せよ。
規則：ある値が偶数ならその値を1/2にする。奇数ならその値を3倍して1を足す。

```julia
print("input number:")
n = parse(Int, readline())

count = 0
while n != 1
    count += 1
    if iseven(n)
        n ÷= 2
    else
        n = (3n + 1)
    end
    println("$count: $n")
end
```

    input number:
    stdin>  3
    1: 10
    2: 5
    3: 16
    4: 8
    5: 4
    6: 2
    7: 1

## No. 49 九九
九九の表を、2重の繰り返しを使って表示するプログラムを作成せよ。2重の繰り返しを使わず単に表示するだけではダメ。値の間はタブ(\t)を使って間をあけること。

```julia
for i in 1:9
    for j in 1:9
        print("$(i*j)\t")
    end
    println()
end
```

    1	2	3	4	5	6	7	8	9	
    2	4	6	8	10	12	14	16	18	
    3	6	9	12	15	18	21	24	27	
    4	8	12	16	20	24	28	32	36	
    5	10	15	20	25	30	35	40	45	
    6	12	18	24	30	36	42	48	54	
    7	14	21	28	35	42	49	56	63	
    8	16	24	32	40	48	56	64	72	
    9	18	27	36	45	54	63	72	81	

「2重の繰り返しを使って」という条件を無視して以下のようにも書ける

```julia
Base.print_matrix(stdout, collect(1:9) .* collect(1:9)', "", "\t", "\n")
```

    1	 2	 3	 4	 5	 6	 7	 8	 9
    2	 4	 6	 8	10	12	14	16	18
    3	 6	 9	12	15	18	21	24	27
    4	 8	12	16	20	24	28	32	36
    5	10	15	20	25	30	35	40	45
    6	12	18	24	30	36	42	48	54
    7	14	21	28	35	42	49	56	63
    8	16	24	32	40	48	56	64	72
    9	18	27	36	45	54	63	72	81

## No. 50 foobar
1から100までの値を繰り返しで表示するが、3の倍数の時はfoo、5の倍数の時はbarと数字の代わりに表示するプログラムを作成せよ。なお、3と5の両方の倍数の時はfoobarと表示される。

```julia
for i in 1:100
    if i % 15 == 0
        println("foobar")
    elseif i % 3 == 0
        println("foo")
    elseif i % 5 == 0
        println("bar")
    else
        println(i)
    end
end
```

    1
    2
    foo
    4
    bar
    foo
    7
    8
    foo
    bar
    11
    foo
    13
    14
    foobar
     :
    bar
    foo
    97
    98
    foo
    bar

## No. 51 お支払い
指定した金額を100円玉と10円玉と1円玉だけで、できるだけ少ない枚数で支払いたい。金額を入力するとそれぞれの枚数を計算して表示するプログラムを作成せよ。

```julia
print("input money:")
money = parse(Int, readline())

(百円玉, res) = divrem(money, 100)
(十円玉, 一円玉) = divrem(res, 10)
using Printf
@printf("100円玉%g枚，10円玉%g枚，1玉%g枚\n", 百円玉, 十円玉, 一円玉)
```

    input money:
    stdin>  1234567
    100円玉12345枚，10円玉6枚，1玉7枚

## No. 52 閏年
西暦を入力したらその年が閏（うるう）年かどうかを判定するプログラムを作成せよ。なお、4で割り切れる年のうち、100で割り切れないか、400で割り切れる年は閏年である。

```julia
print("input year:")
year = parse(Int, readline())

using Dates    
if isleapyear(Date(year))
    println(year, "は閏年である")
else
    println(year, "は閏年でない")
end
```

    input year:
    stdin>  2000
    2000は閏年である

愚直に書く

```julia
print("input year:")
year = parse(Int, readline())

if year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)
    println(year, "は閏年である")
else
    println(year, "は閏年でない")
end
```

    input year:
    stdin>  2000
    2000は閏年である

## No. 53 素因数分解
自然数の入力値を素因数分解して結果を表示するプログラムを作成せよ。

```julia
print("input number:")
n = parse(Int, readline())

using Primes
println(factor(Vector, n))
```

    input number:
    stdin>  840
    [2, 2, 2, 3, 5, 7]

愚直に書く

```julia
print("input number:")
n = parse(Int, readline())
while n % 2 == 0
    print(2, " ")
    n ÷= 2
end
for i in 3:2:ceil(Int, sqrt(n))
    if n != 1
        while n % i == 0
            print(i, " ")
            n ÷= i
        end
    else
        break
    end
end
```

    input number:
    stdin>  840
    2 2 2 3 5 7 

## No. 54 最大最小
まずデータの個数を入力させ、次にデータの個数だけ整数値を入力させる。この入力データの中で最大値と最小値を求め表示するプログラムを作成せよ。データの個数は100個までとする。なお、データの個数とデータはファイルからリダイレクトで入力させればよいので、入力のためのメッセージは不要である（実行例を参照すること）。

```julia
using Statistics
function minmax(filename)
    txt = readlines(filename)
    x = parse.(Int, txt[2:end])  # データは2行目以降
    println("最小値 = $(minimum(x)), 最大値 = $(maximum(x))")
end
minmax("small.data")
minmax("middle.data")
minmax("large.data")
```

    最小値 = 128, 最大値 = 962
    最小値 = 20, 最大値 = 988
    最小値 = 5, 最大値 = 996

## No. 55 夢想花again
「とんで」を9回「まわって」を3回繰り返した後「まわる」と表示して改行する、を3回繰り返すプログラムを作成せよ。「とんで」「まわって」と3行文の繰り返しは必ず繰り返し構文を使うこと。

```julia
for i in 1:3
    for j in 1:9
        print("とんで")
    end
    for j in 1:3
        print("まわって")
    end
    println("まわる")
end
```

    とんでとんでとんでとんでとんでとんでとんでとんでとんでまわってまわってまわってまわる
    とんでとんでとんでとんでとんでとんでとんでとんでとんでまわってまわってまわってまわる
    とんでとんでとんでとんでとんでとんでとんでとんでとんでまわってまわってまわってまわる

## No. 56 2進数変換
0〜65535の整数値を入力させ、入力値を16桁の2進数に変換して表示するプログラムを作成せよ。

```julia
print("input number:")
number = parse(Int, readline())

println(string(number, base=2, pad=16))
```

    input number:
    stdin>  10000
    0010011100010000

愚直に書く

```julia
print("input number:")
number = parse(Int, readline())

bin = ""
for i in 1:16
    (number, bit) = divrem(number, 2)
    bin = string(bit) * bin  # Julia では文字列の連結演算子は '*'
end
println(bin)
```

    input number:

    stdin>  10000

    0010011100010000

## No. 57 テスト集計
まず受験者数を入力させ、次に受験者数ごとに英語、数学、国語の点数をスペースで区切って入力させる（具体的な入力方法は下記のscanfの使い方の説明、および入力データの中身を見よ）。入力が終了したら、英語、数学、国語の平均点、および各受験生の合計点を計算して表示するプログラムを作成せよ。受験者数は100人までとする。なお、データの個数とデータはファイルからリダイレクトで入力させればよいので、入力のためのメッセージは不要である（実行例を参照すること）。

```julia
using Printf
using CSV, DataFramesMeta, Statistics

function exam(filename)
    df = CSV.read(filename, DataFrame, skipto=2, header=["英語", "数学", "国語", ""])[!, 1:3]
    # データフレーム用ではないデータフレームを読み込むための対応
    # データが2行目以降 ==> skipto=2 を指定する
    # ヘッダーがない ==> header=["英語", "数学", "国語", ""])
    # データの各行の末尾に空白が入っている ==> [!, 1:3] で1~3列を取り出す（上記 header では 4 列分の名前を定義すること）
    df = @transform df :合計点 = :英語 + :数学 + :国語
    (英語, 数学, 国語) = mean.(eachcol(df))
    @printf("平均点 英語:%g, 数学:%g, 国語:%g\n", 英語, 数学, 国語)
    println("個人合計得点\n", df.合計点)
end

exam("examSmall.data")
exam("examMiddle.data")
exam("examLarge.data")
```

    平均点 英語:46.3, 数学:51.3, 国語:55.9
    個人合計得点
    [141, 114, 107, 145, 201, 145, 201, 197, 96, 188]
    平均点 英語:55.14, 数学:53.88, 国語:54.74
    個人合計得点
    [136, 64, 144, 101, 160, 261, 197, 164, 143, 116, 154, 185, 221, 142, 154, 179, 214, 141, 139, 80, 173, 191, 180, 144, 111, 213, 219, 88, 180, 193, 129, 198, 176, 207, 102, 109, 211, 169, 215, 231, 181, 157, 115, 106, 236, 114, 181, 132, 265, 167]
    平均点 英語:52.87, 数学:51.32, 国語:51.12
    個人合計得点
    [151, 241, 145, 146, 156, 118, 128, 97, 184, 249, 203, 81, 191, 193, 58, 197, 77, 131, 165, 184, 135, 182, 164, 126, 94, 146, 260, 117, 170, 70, 139, 202, 216, 82, 117, 112, 101, 111, 107, 176, 106, 227, 253, 171, 243, 199, 192, 88, 177, 153, 234, 139, 103, 166, 148, 90, 141, 193, 127, 227, 195, 116, 98, 193, 141, 189, 206, 135, 135, 224, 204, 74, 212, 179, 185, 85, 246, 139, 177, 134, 162, 177, 182, 190, 126, 168, 78, 197, 172, 116, 81, 126, 95, 54, 162, 164, 289, 141, 107, 178]

行列として扱う

```julia
using Printf
function exam(filename)
    f = open(filename, "r")
    n = parse(Int, readline(f))
    x = zeros(Int, n, 3)
    for i in 1:n
        x[i, :] = parse.(Float64, split(readline(f)))
    end
    (英語, 数学, 国語) = mean(x, dims=1)
    @printf("平均点 英語:%g, 数学:%g, 国語:%g\n", 英語, 数学, 国語)
    scores = sum(x, dims=2)
    println("個人合計得点")
    println(scores')
end

exam("examSmall.data")
exam("examMiddle.data")
exam("examLarge.data")
```

    平均点 英語:46.3, 数学:51.3, 国語:55.9
    個人合計得点
    [141 114 107 145 201 145 201 197 96 188]
    平均点 英語:55.14, 数学:53.88, 国語:54.74
    個人合計得点
    [136 64 144 101 160 261 197 164 143 116 154 185 221 142 154 179 214 141 139 80 173 191 180 144 111 213 219 88 180 193 129 198 176 207 102 109 211 169 215 231 181 157 115 106 236 114 181 132 265 167]
    平均点 英語:52.87, 数学:51.32, 国語:51.12
    個人合計得点
    [151 241 145 146 156 118 128 97 184 249 203 81 191 193 58 197 77 131 165 184 135 182 164 126 94 146 260 117 170 70 139 202 216 82 117 112 101 111 107 176 106 227 253 171 243 199 192 88 177 153 234 139 103 166 148 90 141 193 127 227 195 116 98 193 141 189 206 135 135 224 204 74 212 179 185 85 246 139 177 134 162 177 182 190 126 168 78 197 172 116 81 126 95 54 162 164 289 141 107 178]

## No. 58 棒グラフ
0以上の整数値を5つ入力させ、それぞれの値に対して、次の形式でグラフを描くプログラムを作成せよ。
形式：左端に値を表示し、適切に空白を空けて":"を書く（:で揃えるためにタブ\tを使うとよい）。その後ろに値の数だけ*を描くが、5個おきに空白を１つ入れる。具体例は下記の実行例を参照すること。

```julia
n = [(print("input data[$i]"); parse(Int, readline())) for i in 1:5]
for i in n
    println(i, "\t:", replace("*" ^ i, "*****" => "***** "))
end 
```

    input data[1]
    stdin>  4
    input data[2]
    stdin>  6
    input data[3]
    stdin>  5
    input data[4]
    stdin>  7
    input data[5]
    stdin>  23
    4	:****
    6	:***** *
    5	:***** 
    7	:***** **
    23	:***** ***** ***** ***** ***

## No. 59 行列の和
3x3行列の和を求めて表示するプログラムを作成せよ。行列の値は2次元配列で表現し、繰り返しを使って計算すること。
3x3行列とは縦3つ、横3つの9つの要素(値)をひとまとめにして扱うものである。2つの3x3行列の和は次式のように、それぞれ同じ位置にある値を足したものとして計算できる。

```julia
function inputmatrix(size)
    x = zeros(Int, size, size)
    for i in 1:size
        x[i, :]  = parse.(Int, split(readline()))
    end
    return x
end

print("1つめの行列")
a = inputmatrix(3)
print("2つめの行列")
b = inputmatrix(3)

c = a .+ b
println(c)
println("和")
Base.print_matrix(stdout, c)
```

    1つめの行列
    stdin>  1 2 3
    stdin>  4 5 6
    stdin>  7 8 9
    2つめの行列
    stdin>  2 3 4
    stdin>  5 6 7
    stdin>  8 9 0
    [3 5 7; 9 11 13; 15 17 9]
    和
      3   5   7
      9  11  13
     15  17   9