タートルグラフィックスで学ぶ Python のキホン 第 9 章
教材コード
第 9 章

はじめての CUI プログラム

絵を描かずに,入力と計算と表示だけでプログラムを作ります.

ここまでの 6 回は,ずっとかめに絵を描かせてきました. 今回はかめを休ませて,タートルを 1 行も使わないプログラムを書きます. 画面に出るのは文字だけ,操作はキーボードだけ. このようなプログラムをCUI プログラムといいます.

絵がない代わりに,仕様(しよう)があります. どの課題にも「どんな入力を受け取り,何を計算し,何を表示するのか」が 文章で書いてあります.その文章を読んで,自分でプログラムに翻訳する ——これが,今回の中心になる練習です.実際の仕事では,こうして 「日本語で書かれた注文」からプログラムを起こします.

もう 1 つ,今回は変数の型をきちんと意識します. 絵を描くときは「数」でひとまとめにしていられましたが, 入力と計算だけのプログラムでは, 整数なのか,小数なのか,文字列なのかを取り違えると, そのまま結果が狂います.

この章でできるようになること
  • CUI プログラムとは何かを説明できる
  • input()print() だけで,「入力 → 処理 → 出力」の形のプログラムが書ける
  • 整数(int)・小数(float)・文字列(str)・真偽値(boolの4 つの型を区別できる
  • int()float()str()型を変えてから計算・表示できる.型変換に失敗したときのエラーも読める
  • モジュールとは何かを説明できる.random で乱数を作り,毎回結果の変わるプログラムが書ける
  • 仕様書を読んで,「入力」「処理」「出力」に分けて整理できる
  • 仕様どおりに動く CUI プログラムを,自分で組み立てられる
この章の進め方
  • 課題は「概要」「機能」「エラー処理」「プログラム設計条件」の4 つに分けて書いてあります.まず全部読んでから,書き始めてください.
  • 「▶ この課題を開く」を押すと,右側に出発点のプログラムが読み込まれます.入力を受け取るところまでは書いてあるので,計算と表示を自分で書き足してください.
  • input() を使う課題には,右下のコンソールの入力行にあらかじめ値が入っています.値を書き換えて,何度も実行して確かめてください.
  • コンソールの入力行を空にして実行すると,実行中に画面で 1 つずつ聞かれます.
  • できあがったら「⤓ 保存」で .py ファイルとして手元に保存します.
繰り返しの注意 この教材はブラウザの中で Python を動かしています. while True:(ずっと繰り返す)は書かないでください. 止める手立てがないので,ブラウザごと固まります. 「何回か繰り返す」ときは for i in range(10): のように 回数を決めてください. 「どうなるまで繰り返す」ときは, while 残高 > 0 and 年 < 50: のように 必ず終わる条件をもう 1 つ付け足してください.

9.1 文字だけで作るプログラム

CUI(Character User Interface)とは, ユーザへの情報の表示を文字だけで行い, すべての操作をキーボードで行うユーザインタフェースのことです. ここまでの回でずっと使ってきた input()print() が, そのまま CUI プログラムの道具になります.

タートルのプログラムCUI のプログラム
出力画面に絵を描く(fdltコンソールに文字を出す(print
入力キーやマウス(第 12 章)キーボードから 1 行(input
使う道具from turtle import * が要る何も読み込まなくてよい(乱数のときだけ import random
向いていること形・模様・動き計算・判定・集計

まずは,いちばん短い CUI プログラムです. 入力を受け取って,そのまま返すだけの「おうむ返し」です.

echo.py
# おうむ返しのプログラム

print("開始しました")

text = input("好きな言葉を入力してください > ")
print(f"あなたが入力したのは「{text}」ですね")

print("終了しました")
「開始しました」「終了しました」 最初と最後の print に注目してください. 今回の課題では,どれも 「開始しました」で始め,「終了しました」で終えることになっています. 絵が出ないプログラムでは,動いたのかどうかが見た目で分かりません. 始まりと終わりを自分で知らせるのは,CUI プログラムの作法です.

このおうむ返しは短いですが,CUI プログラムの骨組みがそのまま入っています. どんなに長い CUI プログラムも,結局は次の 3 つでできています.

  1. 入力input() で,人から値を受け取る
  2. 処理:受け取った値を使って,計算したり条件で分けたりする
  3. 出力print() で,結果を文字にして見せる

おうむ返しには「処理」がほとんどありません. ここに計算や if を書き足していけば, BMI 計算にも,占いにも,数あてゲームにもなります. 今回の課題は,すべてこの 3 つを埋める作業だと思ってください.

9.2 ここまでの道具のおさらい

今回の課題で使うのは,第 3 章から第 6 章までに習ったものだけです. 忘れていたら,ここで思い出してください.

書き方すること出てくる回
input("案内 > ")キーボードから 1 行受け取る.結果は必ず文字列第 3 章
int(input(…))入力を整数として受け取る第 3 章
float(input(…))入力を小数として受け取る第 3 章
f"…{x}…"文字と数をまぜて表示する第 3 章
// %割った商と余り.お金・個数の計算に使う第 3 章
int(x * 10 + 0.5) / 10小数第 2 位で四捨五入する第 3 章
random.randint(a, b)a 以上 b 以下の整数を 1 つ第 3 章
if elif else条件で処理を分ける第 5 章
and or not条件を組み合わせる第 5 章
for i in range(n):n 回繰り返す第 6 章
break繰り返しを途中でやめる第 6 章
第 3 章にある課題 0.1 を 10 回足す0.125 を 8 回足す四捨五入割り勘計算機は, すでに第 3 章で扱っています. まだ解いていない人は,先にそちらを済ませてください.

9.2.1 変数の型 — 整数・小数・文字列・真偽値

絵を描いているうちは,変数の中身はほとんど「数」でした. CUI プログラムでは,ここをはっきり区別する必要があります. 変数に入っているデータの種類のことを 型(かた)といいます.

読み何を表すか書き方の例
intイント整数.人数・個数・年・点数7 -3 2026
floatフロート小数.身長・体重・利率・平均1.72 0.05 3.0
strストリング文字列.名前・メッセージ"ももたろう" "開始しました"
boolブール真偽値.条件が成り立つかどうかTrue False

4 つめの bool は,第 5 章で習ったものです. TrueFalse2 つしか値がありませんif bmi < 18.5: と書いたときの bmi < 18.5 の部分は, 計算すると TrueFalse になります. つまり if は,bool 型の値を見て分かれているのです.

型がずれていると,見た目は似ていても結果がまったく違います. "3" + "4""34"(文字をつなげる)ですが, 3 + 47(足し算)です.

types.py
# 型を確かめるプログラム

print("開始しました")

a = 7            # 整数
b = 1.72         # 小数
c = "ももたろう"  # 文字列
d = (a > 5)      # 真偽値(条件を計算した結果)

print(a, type(a))
print(b, type(b))
print(c, type(c))
print(d, type(d))

print("3 + 4 は", 3 + 4)          # 足し算になる
print('"3" + "4" は', "3" + "4")  # つながってしまう

print("終了しました")
input() の結果は必ず文字列 いちばんつまずくのがここです. input() が返すのは,いつでも文字列(strです. 数を打ち込んだつもりでも,受け取った時点では "170" という文字の並びでしかありません. そのまま足し算をすると,つながってしまうか,エラーになります.

そこで,受け取ったあとに型を変えてから使います. 型を変えたいときは,型の名前をそのまま命令として使います.

書き方すること
int(x)整数に直す.小数部分は切り捨てint("170")170int(3.9)3
float(x)小数に直すfloat("1.72")1.72
str(x)文字列に直す.つなげて表示するときに使うstr(7)"7"
入力を受け取る定型.型に合わせて int / float で包む
sei = int(input("身長を cm で入力してください > "))     # 整数として受け取る
taiju = float(input("体重を kg で入力してください > "))  # 小数として受け取る
namae = input("名前を入力してください > ")               # 文字列はそのまま

ただし,どんな文字列でも数に直せるわけではありませんint() に渡せるのは数として読める文字列だけです. 次の例題は,わざと失敗させてエラーを見るためのものです.

cast_error.py
# 型変換が失敗する様子を見るプログラム

print("開始しました")

print(int("170"))       # 170    数として読める文字列は整数に直せる
print(float("1.72"))    # 1.72   小数も同じ

# ここから下は,わざと失敗させています
# エラーが出るとそこで止まるので,1 行ずつ # を付けたり外したりして試してください
print(int("3.5"))       # ← エラー.小数の文字列は int では読めない
print(int("abc"))       # ← エラー.数として読めない
print("1" + 1)          # ← エラー.文字列と整数は足せない

print("終了しました")
ValueError と TypeError int("3.5")int("abc")ValueError(値がおかしい), "1" + 1TypeError(型がおかしい)になります. エラーが出ると,プログラムはその行で止まります. 下の行も見たいときは,上の行を # でコメントにしてから実行してください. エラーの名前は,どこを直せばよいかの手がかりです. ValueError なら入力された中身を, TypeError なら変数の型を疑ってください. "3.5" のような小数の文字列を整数にしたいときは, int(float("3.5")) と 2 段階で直します.
仕様書の「エラー処理」とのつながり 今回の課題の仕様書には,どれも 「文字など処理不可能な値が入力されたときの処理は行っていない」 と書いてあります.つまり,上のようなエラーが出る入力は 考えなくてよいということです. そのかわり,動かすときは入力欄に素直に数を書いてください. 変な入力に備える書き方(try)は第 20 章で扱います.
int() は切り捨て int()四捨五入ではなく切り捨てです. int(3.9)4 ではなく 3 になります. 四捨五入したいときは,先に 0.5 を足してから切り捨てます. 小数第 1 位までにしたいなら int(x * 10 + 0.5) / 10 です.
小数には誤差がある 小数(float)には誤差があります. 0.1 を 10 回足しても,ぴったり 1.0 にはなりません. コンピュータが 2 進法で計算しているためで,Python に限った話ではありません. お金や個数は整数で扱う小数どうしを == で比べないと覚えておいてください.
くわしくは第 3 章に 型・型変換・小数の誤差については, 第 3 章の 3.6 節・3.7 節でくわしく説明しています. ここではもう一度必要になったので,要点だけをまとめました. 忘れていたら,そちらに戻って確かめてください.

9.2.2 乱数を出す

10 から 20 までの整数を,実行するたびに違う値で出します. 乱数を使うときは,プログラムの先頭に import random と書きます.

モジュールとは random のように,便利な命令をひとまとめにした箱モジュールといいます. Python には初めからたくさんのモジュールが用意されていて, import モジュール名 と書くとその箱が使えるようになります. 箱の中の命令を呼ぶときは random.randint(…) のように, 「箱の名前.命令の名前」と書きます. random. を書き忘れると NameError(そんな名前は知りません)になるので気をつけてください.
random のほかの道具 random の箱には randint 以外の道具も入っています. random.random()0.0 以上 1.0 未満の小数を返すので, if random.random() < 0.3: と書けば 「30% の確率で起こること」が作れます. いくつか並べたものから 1 つ選ぶ random.choice や, 順番をまぜる random.shuffle もありますが, これらはリストを習ってから使うので,第 16 章で扱います. import の 3 つの書き方(from ○○ import △△ など)は 第 20 章で整理します.
random_generator.py
# 乱数を出すプログラム

import random

print("開始しました")

d1 = random.randint(10, 20)        # 10 以上 20 以下
print(f"1 つめの数は {d1} です")

d2 = random.randint(0, 10) + 10    # こう書いても同じ範囲になる
print(f"2 つめの数は {d2} です")

print("終了しました")
範囲の両端に注意 random.randint(10, 20)10 以上 20 以下(両端を含む)ですが, random.randrange(10, 20)10 以上 20 未満(20 を含まない)です. 端をどこまで含むかは命令によって違うので, そのつど確かめる習慣をつけてください.

9.2.3 数を数えながら判定する

for% を組み合わせると, 「3 の倍数のときだけ何かする」といったことができます. このあとの課題 7「世界の○○」のもとになる例題です.

count15.py
# 3 の倍数と 5 の倍数に印をつけながら数える

print("開始しました")

for i in range(1, 16):
    kotae = str(i)               # 数を文字列にする

    if i % 3 == 0:
        kotae = kotae + " バカ"

    if i % 5 == 0:
        kotae = kotae + " 犬っぽく"

    print(kotae)

print("終了しました")
if を並べるか elif にするか if を 2 つ並べて書いているところがみそです. elif にしてしまうと,15 のように 3 の倍数でも 5 の倍数でもある数のときに, 片方しか付きません. 「どちらも起こりうる」ときは if を並べ, 「どれか 1 つだけ」のときは elif を使います.
虫食い虫食い 9-A 小数で入力を受け取る

身長と体重を受け取ります.どちらも 170.5 のような 小数で入力されます. ____ に入る命令は intfloatstr のどれでしょうか.

fill_a_input.py
print("開始しました")

# 身長は cm,体重は kg.どちらも小数で受け取る
height = ____(input("身長を cm で入力してください > "))
weight = ____(input("体重を kg で入力してください > "))

print(f"身長 {height} cm,体重 {weight} kg ですね")

print("終了しました")
虫食い虫食い 9-B 範囲で判定する

BMI 指数の値で,体型を 4 つに分けます. 18.5 未満=やせ,18.5 以上 25 未満=標準, 25 以上 35 未満=肥満,35 以上=高度肥満です. ____ を埋めてください. bmi >= 18.5 and bmi < 25 と書かなくてよい理由も考えてみましょう.

fill_b_elif.py
bmi = float(input("BMI 指数を入力してください > "))

if bmi ____ 18.5:
    print("やせています")
____ bmi < 25:
    print("標準的です")
____ bmi < 35:
    print("肥満です")
____:
    print("高度肥満です")
虫食い虫食い 9-C 入力された数まで数える

入力された数まで数え,3 の倍数のときだけ印をつけます. ____ を埋めてください. range の終わりの値に注意してください. range(1, n) では n が出てきません.

fill_c_count.py
print("開始しました")

n = int(input("いくつまで数えますか > "))

for i in range(1, ____):        # n まで数えたい
    kotae = str(i)

    if i ____ 3 == 0:           # 3 で割った余りが 0 なら 3 の倍数
        kotae = kotae + " バカ"

    print(kotae)

print("終了しました")
虫食い虫食い 9-D さいころの当たりはずれ

さいころを 1 回振り,出た目が 1・2・3 のときは「当たり」それ以外のときは「はずれ」と表示します. ____ を埋めてください. 目は 1 から 6 までです.me == 1 or me == 2 or me == 3 と 書かなくても済む条件を考えてみましょう.

fill_d_dice.py
import random

print("開始しました")

me = random.____(1, 6)       # 1 以上 6 以下の整数を 1 つ
print(f"さいころの目は {me} です")

if me ____ 3:                # 1・2・3 なら当たり
    print("当たり")
else:
    print("はずれ")

print("終了しました")
乱数を使ったら何度も動かす この虫食いは,実行するたびに結果が変わります. 1 回動かしただけでは正しいかどうか分かりません. 何度も実行して,当たりとはずれが両方出ること, 目が 1 より小さくならず 6 より大きくならないことを確かめてください. 乱数を使ったプログラムは,こうして何度も動かして確かめます.

9.2.4 文字列を数に変える

名前などの文字列から数を作ると,占いのプログラムが書けます. Python では ord() という命令で, 1 文字を数(文字コード)に変えることができます. for c in 文字列: と書くと, 文字列の中身を1 文字ずつ取り出せます.

ord で文字を数にする
print(ord("A"))      # 65
print(ord("a"))      # 97
print(ord("あ"))     # 12354

for c in "かめ":
    print(c, ord(c))
hash() は占いに使えない Python には hash() という似た命令がありますが, 文字列に対する hash()実行するたびに違う値を返すことがあります (セキュリティ上の理由でそうなっています). 占いは同じ名前なら必ず同じ結果でなければ興ざめですから, 今回は hash() ではなく ord() を使います.
虫食い虫食い 9-E 名前を数にする

入力された名前を 1 文字ずつ数に直して足し合わせ, 最後に 0 〜 99 の範囲に収めます. ____ を埋めてください. 「ある範囲に収める」ときに使う演算子は何でしたか.

fill_d_ord.py
name = input("名前を入力してください > ")

value = 0
for c in name:
    value = value + ____(c)     # 1 文字を数に直して足す

print(f"{name} の数は {value} です")
print(f"0 〜 99 に収めると {value ____ 100} です")

9.3 仕様書の読み方

ここから先の課題は,すべて仕様書の形で書いてあります. 4 つの見出しには,それぞれ役割があります.

見出し何が書いてあるか読むときに考えること
概要そのプログラムが何をするものか,一言で誰が,どんなときに使うのか
機能入力・処理・出力の中身.いちばん大事受け取るのは何個か.どの型か.何を計算するのか
エラー処理変な入力が来たときにどうするか「行っていない」と書いてあれば,考えなくてよい
プログラム設計条件作り方の約束ごと使う命令が指定されていないか
仕様からプログラムへ 仕様を読んだら,いきなり書き始めずに,まず 「入力」「処理」「出力」の 3 つに分けて紙に書き出すとうまくいきます.
  1. 入力:何を,いくつ,どの型で受け取るか(intfloat? 文字列?)
  2. 処理:受け取った値から何をどう計算するか(式を日本語で書いてみる)
  3. 出力:何を,どんな文で表示するか
この 3 つが決まれば,あとは Python に翻訳するだけです. 出発点のプログラムには,「入力」の部分だけが書いてあります.

9.4 基本課題

入力を受け取り,計算し,条件で分けて表示する——という CUI プログラムの基本形を身につけます.

課題課題 1 体型評価プログラム

■ 概要

このプログラムは,身長と体重の入力を実数で受け付け, その入力をもとに BMI 指数と, その値から評価されたコメントを出力します.

■ 機能

  1. プログラムの起動時および終了時に,その旨をユーザに伝えるメッセージを出力する.起動時出力:「開始しました」,終了時出力:「終了しました」(適宜変えてよい).
  2. 身長と体重の入力を受け取り,BMI 指数と,その値から評価されたコメントを出力する.
    入力:体重(kg) と身長(cm) の実数値
    出力:BMI 指数(小数第 2 位で四捨五入することが望ましい),およびコメント
  3. BMI 指数は体重(kg) を身長(m) の 2 乗で割った数値である(身長の単位に注意.入力は cm なので,100 で割って m に直す).
  4. BMI 指数から体型を次のように評価し,コメントとする(18.5 未満=やせ,18.5 以上 25 未満=標準,25 以上 35 未満=肥満,35 以上=高度肥満).

■ エラー処理

文字など処理不可能な値が入力されたときの処理は,行っていない.入力欄には素直に数を書くこと.

■ プログラム設計条件

  • 入出力は起動したコンソールから行う(CUI プログラムである).
  • 身長と体重の入力には float(input(…)) を使用する.
  • コメントの文面は各自工夫してよい.
ヒント 四捨五入は第 3 章の復習です. int() が切り捨てであることを利用して, int(bmi * 10 + 0.5) / 10 と書くと小数第 2 位で四捨五入できます. 条件の分け方は虫食い 9-B が答えそのものです.

発展:標準体重(BMI が 22 になる体重)も計算して, 「あと何 kg」と表示してみましょう. 身長を m ではなく cm のまま計算するとどうなるかも,一度試してみてください.

課題課題 2 恋愛占いプログラム

■ 概要

このプログラムは,男女の名前を入力すると, その恋愛成就確率を百分率で判定し,コメント付きで出力します.

■ 機能

  1. プログラムの起動時および終了時に,その旨をユーザに伝えるメッセージを出力する.起動時出力:「開始しました」,終了時出力:「終了しました」(適宜変えてよい).
  2. 男女の名前の入力を受け取り,恋愛成就確率をコメント付きで出力する.
    入力:男女の名前(姓名をつなげたもの)
    出力:恋愛成就確率(0 〜 100%.実数でも整数でもよい),コメント
  3. 成就確率を求める手順は自由でよいが,必ず 0 〜 100 の範囲に収まるようにする.
  4. コメントも自由でよい.楽しめるように工夫すること
  5. 同じ名前を入れたら,何度実行しても同じ結果になること(乱数で決めてはいけない.占いにならないため).

■ エラー処理

文字など処理不可能な値が入力されたときの処理は,行っていない.入力欄には素直に数を書くこと.

■ プログラム設計条件

  • 入出力は起動したコンソールから行う(CUI プログラムである).
  • 男女の名前の入力には input(…) を使用する.
  • 文字列を数に直すには ord() を使う(9.2.4 を参照).
ヒント 0 〜 100 に収めるのがこの課題の山場です. 文字コードを足し合わせた数は,名前が長いほど大きくなります. % 101 とすれば,どんなに大きな数でも 0 〜 100 になります. 「100 より大きい間,10 で割り続ける」といった手もありますが, % を使えば 1 行で済みます.

発展:名前の長さ(len(name))や, 2 人の名前に同じ文字が含まれるかどうかも混ぜて, もっと「それらしい」占いにしてみましょう. 相性の段階に応じて,アドバイスの文も変えてみてください.

課題課題 3 単位取得状況評価プログラム

■ 概要

このプログラムは,あなたの単位取得状況の入力を受け取り, それを評価し,卒業するためのコメントを出力します.

■ 機能

  1. プログラムの起動時および終了時に,その旨をユーザに伝えるメッセージを出力する.起動時出力:「開始しました」,終了時出力:「終了しました」(適宜変えてよい).
  2. 経過した学期数と現在取得した単位数の入力を受け取り,その値から評価されたコメントを出力する.
    入力:経過した学期数(0 〜 7)の整数値,取得済みの単位数の整数値
    出力:今後 1 学期あたりにとらねばならない単位数(CPS:Credit Per Semester),およびコメント
  3. 最終的に取得すべき単位数などの規則は学則に従うものとする(自分の学科の卒業要件単位数を調べて書くこと).
  4. CPS =(卒業に必要な単位数 − 取得済みの単位数)÷(残りの学期数).4 年間の学期数は 8 とする.
  5. コメントは自由に考えてよい.

■ エラー処理

文字など処理不可能な値が入力されたときの処理は,行っていない.入力欄には素直に数を書くこと.

■ プログラム設計条件

  • 入出力は起動したコンソールから行う(CUI プログラムである).
  • 単位数・学期数の入力には int(input(…)) を使用する.
ヒント 卒業要件単位数を sotsugyo = 124 のように 変数にして先頭に書いておくと, 学科によって数が違っても 1 か所直すだけで済みます.第 3 章でやったとおりです.
0 で割らないように 経過した学期数に 8 を入れると,残りの学期数が 0 になり, 0 で割ることになってエラーZeroDivisionError)になります. 仕様では「エラー処理は行っていない」ことになっていますが, if で先に確かめて「もう卒業です」と出すようにできれば上出来です.

発展:1 学期にとれる単位数には上限(履修登録の上限)があります. CPS がその上限を超えていたら「このままでは卒業できません」と警告しましょう. 取得済み単位数が卒業要件を超えている場合の表示も考えてみてください.

9.5 発展課題

ここからは繰り返しが入ってきます. 仕様も長くなりますが,あわてずに「入力」「処理」「出力」に分けて読んでください.

課題課題 4 脳トレ

■ 概要

ユーザが計算問題を解くことで脳を鍛えるソフトウェアである. このプログラムは,足し算の計算問題を自動生成して 何問か出題し,そのつど答えあわせをします.

■ 機能

  1. プログラムの起動時および終了時に,その旨をユーザに伝えるメッセージを出力する.起動時出力:「開始しました」,終了時出力:「終了しました」(適宜変えてよい).
  2. 足し算の計算問題を生成する.
    出力:問題(例:3 + 4 = ?
    各数字の桁数は1 桁の整数である(答えは任意の桁数の整数とする).
  3. 出題し,答えあわせをする.
    入力:回答
    出力:答えあわせの結果(正解か,不正解か.不正解のときは正答を添える)
  4. 2) と 3) を連続で 10 回行い,最後に正答率を出力する.

■ エラー処理

文字など処理不可能な値が入力されたときの処理は,行っていない.入力欄には素直に数を書くこと.

■ プログラム設計条件

  • 入出力は起動したコンソールから行う(CUI プログラムである).
  • 回答の入力には int(input(…)) を使用する.
  • 繰り返しには for i in range(10): を使う(while True: は使わないこと).
ヒント 正解の数を数える変数(たとえば seikai)を, 繰り返しの外0 にしておくのを忘れないでください. 中で 0 にすると,毎回リセットされてしまいます. 10 問なので,正答率は 正解数 * 10 でパーセントになります.

発展:足し算だけでなく,引き算・かけ算も乱数で選んで出題する, 2 桁の問題にする,正答率によって「段位」を出す, 何問目でつまずいたかを表示する,などを考えてみましょう.

課題課題 5 マイホーム大作戦

■ 概要

マイホームローンの返済計算を行うプログラムである. ユーザは家を買うときに利用することを想定する. 家の値段と利率,月々の返済金額を入力として受け取り, 返済が終わるまでにかかる期間総返済金額を計算し, コメントとともに出力します.

■ 機能

  1. プログラムの起動時および終了時に,その旨をユーザに伝えるメッセージを出力する.起動時出力:「開始しました」,終了時出力:「終了しました」(適宜変えてよい).
  2. 家の値段,利率,月々の返済金額を入力として受け取り,返済が終わるまでにかかる期間,総返済金額を計算し,コメントとともに出力する.
    入力:家の値段(整数.万円単位だと使いやすい),利率(百分率の実数),月々の返済金額(整数)
    出力:かかる期間(○年),総返済金額,コメント
  3. 返済方法は元利均等方式(借入元金と借入利息を合わせて,月々同じ金額を返済する方式)とし,利息は年単位で複利計算を行う.
    たとえば 10000 円を利率 5% で借り,月々の返済金額が 100 円の場合,1 年目の返済が終了すると 10000 + 500 − 1200 = 9300 円の借入元金が残る.
  4. 1 円未満は切り捨てとする(利息は小数で計算して,1 年ごとに int() で切り捨てる).
  5. コメントは各自工夫してよい(100 万円:ちょっと安すぎる家では? 50 年:長すぎるのでは? など).

■ エラー処理

文字など処理不可能な値が入力されたときの処理は,行っていない.入力欄には素直に数を書くこと.

■ プログラム設計条件

  • 入出力は起動したコンソールから行う(CUI プログラムである).
  • 家の値段・月々の返済金額の入力には int(input(…)),利率の入力には float(input(…)) を使用する.
  • 返せない場合は繰り返しが終わらなくなるので,事前に確かめること.また while には「50 年まで」のような必ず終わる条件を必ず付け足すこと.
考え方 1 年ぶんの計算は,次の 1 行です.
python
zandaka = int(zandaka * (100 + riritsu) / 100)   # 利息がつく(1 円未満切り捨て)
zandaka = zandaka - maitsuki * 12                # 1 年ぶん返す
これを残高が 0 以下になるまで繰り返し, その章数が「かかる年数」です. 1 年に返す金額が利息より少ないと,残高は永遠に減りません. だから先に if で確かめておく必要があります.

発展:月単位で計算する, 「あと何年で返し終わるか」を 5 年ごとに途中経過として表示する, 利率を変えると総返済額がどれだけ変わるかを比べる,などを試してみましょう.

課題課題 6 ザ・バイナリサーチ

■ 概要

このプログラムは「数あてゲーム」である. システムはまず,1 〜 1000 までの整数をランダムに選ぶ(表示しない). ユーザはこの数をなるべく少ない回答で当てるのが目的である. ユーザは推測した数を入力し,システムは数が当たっていたら 当たったことを知らせて終了,外れていたら 大きすぎるのか,小さすぎるのかを知らせて再入力を求めます.

■ 機能

  1. プログラムの起動時および終了時に,その旨をユーザに伝えるメッセージを出力する.起動時出力:「開始しました」,終了時出力:「終了しました」(適宜変えてよい).
  2. 整数をランダムに選ぶ.
    1 〜 1000 までのランダムな整数を 1 つ選び,画面には出さない
  3. 回答の入力を受けつけ,答えあわせをする.
    プロンプト:「私が選んだ数を当ててみてね」
    入力:回答(整数)
    正解時:「正解です.おめでとう!」と出力して終了する.
    不正解時:「ちがいます」の後,大きすぎるか,小さすぎるかを出力する.
  4. 回答は10 回までとし,10 回で当たらなければ正解を教えて終わる.

■ エラー処理

文字など処理不可能な値が入力されたときの処理は,行っていない.入力欄には素直に数を書くこと.

■ プログラム設計条件

  • 入出力は起動したコンソールから行う(CUI プログラムである).
  • 回答の入力には int(input(…)) を使用する.
  • while True: は使わないこと.for i in range(10): で 10 回に限り,正解したら break で抜ける.
なぜ「バイナリサーチ」なのか この課題の名前は「バイナリサーチ(二分探索)」です. 1 〜 1000 の中から数を当てるとき, まん中の 500 を答えるのが最善手です. 「大きすぎる」と言われたら 1 〜 499 に, 「小さすぎる」と言われたら 501 〜 1000 に, 候補が半分に減るからです. 1000 → 500 → 250 → 125 → … と半分にしていけば, 10 回で必ず当たります(2 の 10 乗が 1024 だから). 作ったら,自分で遊んで確かめてください. アルゴリズムの威力が実感できます.これは第 17 章で改めて習います.

発展:何回で当てたかによって「天才」「まあまあ」などと評価する, 範囲(1 〜 1000)を最初に入力してもらう, 「残りあと何回」を毎回表示する, 入力が範囲の外だったら注意する,などを加えてみましょう.

課題課題 7 世界の○○

■ 概要

このプログラムは,芸人のマネをするソフトウェアである. 任意の自然数を受け取り,その数だけ数を数える

■ 機能

  1. プログラムの起動時および終了時に,その旨をユーザに伝えるメッセージを出力する.起動時出力:「開始しました」,終了時出力:「終了しました」(適宜変えてよい).
  2. 自然数の入力を受け取り,その数まで数える.3 の倍数のときにバカになり,5 の倍数のときには犬っぽくなる(数えるごとに改行すること).
  3. 出力例:
    1
    2
    3(;.゚Д゚.;)ノ
    4
    5^U)┬┬~
    6(;.゚Д゚.;)ノ
    7
  4. 3 がつく数のときもバカになるとなおよい(が,これを作るのは結構難しい).

■ エラー処理

文字など処理不可能な値が入力されたときの処理は,行っていない.入力欄には素直に数を書くこと.

■ プログラム設計条件

  • 入出力は起動したコンソールから行う(CUI プログラムである).
  • 入力には int(input(…)) を使用する.
  • 繰り返しには for i in range(1, n + 1): を使う.
ヒント 3 の倍数でも 5 の倍数でもある数(15 や 30)のときは, 両方が起こります.elif ではなく, if2 つ並べて書いてください(例題 T-5 を参照). 「3 がつく数」は,1 の位だけなら i % 10 == 3 で調べられます. 10 の位なら i // 10 % 10 == 3 です. すべての位を調べるには,数を文字列にして if "3" in str(i): と書く手もあります.

発展:7 の倍数では別のことをする, 100 まで数えても飽きないように途中で合いの手を入れる, 何回バカになったかを最後に集計する,などを加えてみましょう.

課題課題 8 素因数分解プログラム

■ 概要

このプログラムは,入力された整数を素因数分解し, 得られた素因数をすべて出力します. 60 と入力したら 60 = 2 × 2 × 3 × 5 と表示する, というものです.

■ 機能

  1. プログラムの起動時および終了時に,その旨をユーザに伝えるメッセージを出力する.起動時出力:「開始しました」,終了時出力:「終了しました」(適宜変えてよい).
  2. 整数の入力を受け取り,その数の素因数をすべて出力する.
    入力:2 以上の整数
    出力:素因数を小さい順に並べたもの
  3. 同じ素因数が何回も出てくるときは,その章数だけ出力する8 なら 2 × 2 × 212 なら 2 × 2 × 3).
  4. 入力された数が素数のときは,その数自身が 1 つだけ出力される(13 なら 13).

■ エラー処理

文字など処理不可能な値が入力されたときの処理は,行っていない.入力欄には素直に数を書くこと.

■ プログラム設計条件

  • 入出力は起動したコンソールから行う(CUI プログラムである).
  • 入力には int(input(…)) を使用する.
  • 割る数を 2 から 1 つずつ大きくしていき,割り切れるあいだは同じ数で割り続けること.
  • 繰り返しには while を使う.while True: は使わないこと.割る数が残りの数を超えたら終わる,という条件にする.
考え方 「小さい数に分解する」のですから, 2 から順に割ってみるのが素直なやり方です.
  1. 割る数 waru2 から始める.
  2. 割り切れたら,その waru は素因数なので書きとめ,残りの数を waru割った値に更新する(割る数はそのまま.同じ数で何度でも割れるから).
  3. 割り切れなかったら,割る数を 1 つ大きくする.
  4. 割る数が残りの数より大きくなったら終わり.
60 でたどってみましょう. 60 ÷ 2 = 3030 ÷ 2 = 15, 15 は 2 で割れないので割る数を 3 にして 15 ÷ 3 = 5, 5 は 3 でも 4 でも割れず,割る数が 5 になって 5 ÷ 5 = 1. こうして 2, 2, 3, 5 が得られます. 割り算は //(商)を使ってください. / だと答えが小数になってしまいます.
なぜ必ず終わるのか この繰り返しは,必ず終わります. 割り切れたときは残りの数が小さくなり, 割り切れなかったときは割る数が大きくなるので, どちらに転んでも 2 つの数は近づいていくからです. while True: を使わなくてよいのは,このためです. ただし,大きすぎる数を入れると時間がかかります. 2 から順に試していくので,7 桁の素数などを入れると待たされます. はじめは 60360 のような 2 〜 3 桁で試してください.

発展:素因数が 1 つだけだったら「この数は素数です」と表示する, 2 × 2 × 2 ではなく 2 の 3 乗 の形でまとめて表示する, 2 から 100 までの数を順に素因数分解して並べる,などを考えてみましょう.

自由課題 9 独自の観点で CUI プログラムを作ろう

■ 概要

独自の観点で,CUI プログラムを作りなさい. 何を作るかは自由です. ただし,自分で仕様書を書いてから作ること.

■ 機能

  1. プログラムの起動時および終了時に,その旨をユーザに伝えるメッセージを出力する.起動時出力:「開始しました」,終了時出力:「終了しました」(適宜変えてよい).
  2. 入力・処理・出力がそろっていること.入力を 1 つ以上受け取り,それを使って何かを計算し,結果を表示する.
  3. 条件分岐(if)か繰り返し(for)のどちらかを必ず使うこと.
  4. プログラムの先頭に,自分で書いた仕様書をコメントで入れること(概要・機能・エラー処理・設計条件の 4 つ).

■ エラー処理

処理不可能な値が入力されたときの処理を行うかどうかは,各自で決めて仕様書に書くこと.

■ プログラム設計条件

  • 入出力は起動したコンソールから行う(CUI プログラムである).
  • 入力には input(…)int(input(…))float(input(…)) のいずれかを使用する.
  • while True: は使わないこと.
  • ファイルの先頭のコメントに,題名・氏名・日付を書くこと.
題材のヒント
  • おつり計算機:代金と預かり金から,硬貨の枚数を //% で求める(出発点のプログラムはこれです)
  • おみくじ:名前を入れると運勢が出る(ord を使えば同じ名前で同じ結果になる)
  • 西暦・和暦の変換:西暦を入れると和暦を返す
  • 九九の練習:乱数で問題を出して,10 問答えあわせ(課題 4 の応用)
  • 身長から適正体重:いくつかの計算式で比べて表示する(課題 1 の応用)
  • アルバイト代の計算:時給と時間と深夜割増から給料を求める
  • カロリー計算:食べたものを何個か入力して,合計と運動時間に換算する
  • 暦の計算:西暦を入れると,うるう年かどうかを判定する(4 で割り切れ,かつ 100 で割り切れない.ただし 400 で割り切れればうるう年)
いきなり書き始めない 先に仕様書を書いてください. 「作りながら考える」と,たいてい途中で行き詰まります. 「何を入力し」「何を計算し」「何を出すのか」を日本語で書き切ってから, Python に翻訳するほうが,結局は速く終わります.

9.6 作品にするときのきまりと見直しの観点

どの課題も,仕様を満たしていることがいちばん大事です. そのうえで,次の点を見ます.

観点見るところ
仕様の充足「機能」に書かれたことが,すべてできているか
入力の型整数は int(input(…)),小数は float(input(…)) になっているか
変数名ax ではなく,意味の分かる名前がついているか
コメント先頭に題名・氏名・日付があり,処理の区切りに説明があるか
表示f 文字列を使い,読んで意味の分かる文になっているか
独自の工夫仕様にない工夫(コメントの文面,追加の表示,発展課題)があるか
よくある減点 「開始しました」「終了しました」を忘れないでください. これは仕様に書いてある機能の 1 つです. 仕様書に書いてあることを 1 つでも落とすと, 実際の仕事では「できていない」ことになります. 仕様書を最後にもう一度読み返して,指さし確認をしてから仕上げてください.

まとめ

  • CUI プログラムは,文字だけで入出力するプログラム.input()print() があれば作れる.
  • 課題は仕様書の形で与えられる.「概要」「機能」「エラー処理」「プログラム設計条件」を全部読んでから書き始める.
  • 仕様を読んだら,「入力」「処理」「出力」の 3 つに分けて整理する.
  • 変数の型は int(整数)・float(小数)・str(文字列)・bool(真偽値)の 4 つ.int()float()str()型を変えられる
  • 数として読めない文字列int() に渡すと ValueError型の違うもの+ でつなぐと TypeError になる.
  • input() が返すのは必ず文字列.入力の型を間違えないこと.整数は int(input(…)),小数は float(input(…))
  • int()切り捨て.小数には誤差があるので,お金や個数は整数で扱う.
  • モジュールは,便利な命令をまとめた箱.import random で箱を開け,random.randint(a, b) のように「箱の名前.命令の名前」で呼ぶ.
  • 割り切れるあいだ同じ数で割り続けると,素因数分解ができる.割る数か残りの数のどちらかが必ず近づくので,繰り返しはいつか終わる.
  • 範囲で分けるときは ifelifelse両方起こりうるときは if を並べる.
  • ある範囲に収めたいときは % が使える.x % 101 は必ず 0 〜 100 になる.
  • while True: は書かない.回数を決めた for か,必ず終わる条件を付けた while にする.
  • 始まりと終わりを print で知らせるのは,CUI プログラムの作法.

今回の課題は,絵が出ない代わりに, 「書いてあるとおりに作る」「自分で仕様を決める」という, プログラミングのもう一つの側面を練習するものです. タートルの回で身につけた iffor・変数は, そのままここでも働きます.道具は同じで,使い道が違うだけです.

次の回からは,またタートルに戻ります. 今度は絵を動かしますontimer という命令を使って 「少し動かして,少し待って,また少し動かす」を繰り返させると, 第 8 章までに描いた絵がアニメーションになります.