この記事の詳しい内容には毎日新聞の「魚の取りすぎをふせぐ」ページから有料記事に進むことで読めます。
目次
概要
魚つりをするロボットがいます。このロボットは、魚の取りすぎをふせぐため、ルールにしたがってつった魚を海に返します。
ルール:
- つった魚が1ぴきだけの日は、海に返さずに持ち帰る
- つった魚が2ひき以上だったときは、1ぴきを海に返して残りを持ち帰る
たとえば、4ひきつった日にには、1ぴきを海に返し、残りの3びきを持ち帰ります。
ここで問題です。ロボットは5日間で次の数だけ魚をつりました。持ち帰った魚の数は合わせて何びきになるでしょう?
1日め | 2日め | 3日め | 4日め | 5日め |
---|---|---|---|---|
2ひき | 2ひき | 3ひき | 1ひき | 1ひき |
論理を考える
ルールを見ながら日別に計算すると、1 + 1 + 2 + 1 + 1 = 6 となり、答えは6ぴきです。
疑似コード
ルールを日本語の疑似コードで置き換えると、次のようになります。
持ち帰る魚の数 = 0;
もしつった魚の数が1なら、
持ち帰る魚の数 = 1
そうでなく、 つった魚の数が2以上なら
持ち帰る魚の数 = つった魚の数 - 1
簡易的なコードでは次のように記述できます。
fishNum = 3 // つった魚の数
catchNum = 0 // 持ち帰る魚の数、最初は0
releaseNum = 1 // 海に返す魚の数はつねに1
if (fishNum === 1) {
catchNum = 1
}
else if (fishNum >= 2) {
catchNum = fishNum - releaseNum
}
つった魚の数は変化するので、ルールを関数化し、つった魚の数をパラメータで定義すると汎用的になります。
関数化
次のコードは関数の例です。この関数は、つった魚の数をパラメータで受け取り、持ち帰る魚の数を返します。
// つったったさかなの数から海に返す数と持ち帰る数を計算し、
// 持ち帰る数を返す
function catchAndRelease(fishNum) {
print('つった数: ' + fishNum);
const releaseNum = 1; // 海に返す数はつねに1
let catchNum = 0; // 持ち帰る数、最初は0
// つった数が1なら
if (fishNum === 1) {
// それは持ち帰る数
catchNum = 1;
// そうでなく、つった数が2以上なら
}
else if (fishNum >= 2) {
print('海に返す数: ' + releaseNum);
// 持ち帰る数はつった数から海に返す数を引いた数
catchNum = fishNum - releaseNum;
}
print('持ち帰る数: ' + catchNum);
print('---------------');
// 持ち帰る数を返す
return catchNum;
}
この関数は次のように使用できます。この関数はその日につった魚の数を引数にとり、そのたびに持ち帰る魚の数を返すので、前もって0で初期化したlet 変数を用意しておいて、それに足していきます。
let totalCatch =0;
totalCatch += catchAndRelease(2); // 1日め 2ひきつった
totalCatch += catchAndRelease(2); // 2日め 2ひきつった
totalCatch += catchAndRelease(3); // 3日め 3ひきつった
totalCatch += catchAndRelease(1); // 4日め 1ひきつった
totalCatch += catchAndRelease(1); // 5日め 1ひきつった
print('持ち帰った数の合計' + totalCatch);
上記コードを実行すると、[コンソール]に下図の結果が表示されます。
これで論理は完成です。
視覚化
ロボットや魚のイメージをロードし、視覚化します。次のコードは、画面のマウスプレスでスタートするプログラムの例です。
let coolerBox = [];
let fishImage, robotImage;
let isStart = false;
// 日別のつったさかなの数
let fishNumList = [2, 2, 3, 1, 1];
// 持ち帰りの合計
let total = 0;
function preload() {
robotImage = loadImage('images/robot.png');
fishImage = loadImage('images/fish.png');
}
function setup() {
createCanvas(400, 300);
noStroke();
}
// 画面のマウスプレスでスタート
function mousePressed() {
if (!isStart) {
isStart = true;
let cnt = 0; // catchAndRelease()の呼び出し回数をカウント
let timerID;
if (isStart) {
timerID = window.setInterval(() => {
if (cnt < fishNumList.length) {
// 持ち帰りの数を配列に追加 => [1,1,2,1,1]
coolerBox.push(catchAndRelease(fishNumList[cnt]));
// 配列要素の値を合計 1+1+2+1+1 = 6
total = coolerBox.reduce((sum, element) => {
return sum + element;
}, 0);
}
else {
window.clearInterval(timerID);
}
cnt++;
}, 2000);
}
}
}
function draw() {
background(229, 236, 185);
// イメージを描画
image(robotImage, 100, 150);
// 手前の海を描画
fill(113, 138, 194);
rect(0, 270, width, 30);
// 奥の台を描画
fill(170, 140, 94);
rect(20, 70, 250, 30);
// 持ち帰り合計分だけさかなを描画
for (let i = 0; i < total; i++) {
image(fishImage, 30 + 40 * i, 50);
}
}
function catchAndRelease(fishNum) {
let catchNum = 0;
const releaseNum = 1;
if (fishNum === 1) {
catchNum = 1;
}
else if (fishNum >= 2) {
catchNum = fishNum - releaseNum;
}
return catchNum;
}
画面のマウスプレスで、持ち帰る魚が台の上に描画されます。