こんにちは。ばーんです。
今回はJSで分数の計算をしていきます!
はじめに
出会いは唐突でした…(↓ドンッ)
これをjsで解けと会社の上司に言われたんですが全然わからん。
— ケイセイ@JavaScriptと仲良くなりたい (@keisei_otsuka) February 2, 2020
誰かわかります?笑 pic.twitter.com/ZM6VmigaVQ
これは仕方ない…もぅめっちゃ楽しそうやん‼️
(前回のズンドコキヨシの記事書いてまもなくのツイートで、やりたくてうずうずしてましたw)
思い立ったらやらずにいらRenta!
前回の振り返り
そもそもこういう時にどのような思考回路で進めたらいいのか?の答えをメンターと擦り合わせてました。それがこちら↓
1. 仕様を理解する
↓
2. 構成要素を分解する
↓
3. コードのメインの処理の流れを書く(完全に実装するのではなく、コメントと関数名で全体の流れがわかれば良い)
↓
4. 実際に動くコードにする
↓
5. リファクタリングする
なんとなくわかる気がする。なんとなく(知らんけど)
それじゃこれも踏まえてやってみますか!
仕様把握〜構成要素の分解
今回少し難しいのが、問題文の捉え方かなって第一印象で感じました。
例えば4/12(十二分の四)を認めちゃうと相当な種類のパターンが出てくるので。
ですので、切り分けて考えます。
1、分数を計算するJS
2、計算結果を判定して=1ならtrue
3、数字を当てはめていき全部のOKパターンを出すJS
(もしくは、数値を打ち込んで真偽値を返す)
そして、1からやっていきますがここでも思いつくのが何通りか。
A、純粋に分数を計算する(簡単なもので試す)
B、小数点で乗り切る
Bは今回の例だと98/99 = 1はダメで、1/3 + 1/3 + 1/3 = 1はOKなので、
98 ÷ 99 = 0.9898~ なので0.99~1ならOKということであればいける!(というか多分一瞬)
ただまぁB面白くなさそうなのでAの純粋に分数で計算にします。
1、分数を計算するJS
「JS 分数」っと……まぁないですね(ライブラリあったけど本筋から逸れるので却下)
というか分数の計算ってどうすんだっけ?w
いや、簡単な計算はできるんすよ? 1/2 + 1/2 = 1 とかは流石に。
ただ約分はともかく通分のアルゴリズムを覚えていないので検索します。
(約分は分子分母を共通の1〜2桁素数で割っていって、割れなくなったらループ抜けでいけるはず)
ん〜ん〜また出てきたな…最初公倍数とかすだれ算とか。
もっと原始的な方法でできないかな…
と模索してたらできました。
ぼくがかんがえたさいきょうのあるごりずむ!
はいこれをコードに起こしていきまーす。
コードのメインの処理の流れを書く
まずは、ざっくりの大枠を作っていきます。
// molecule分子,denominator分母。数値は後でランダムに変更
const molecule1 = 2;
const molecule2 = 3;
const molecule3 = 1;
const denominator1 = 5;
const denominator2 = 5;
const denominator3 = 1;
// 関数を定義する。通分のアルゴリズム。
let tsubun = (moleculeAnswer,denominatorAnswer) => {
}
console.log(tsubun);
// 後で使う。ループ回すよう
while(moleculeAnswer == denominatorAnswer){
}
ざっくりこんな感じのはず。まずは通分を動かしてみましょー!
実際に動くコードにする
最初に動くコード書こうとしますが…
// // 関数を定義する。通分のアルゴリズム。
let tsubun = (moleculeAnswer,denominatorAnswer) => {
moleculeAnswer = (molecule1 * denominator2) +
(molecule2 * denominator1);
denominatorAnswer = denominator1 * denominator2;
}
console.log(tsubun[1,2]);
あーダメダメ。なんか違うのはわかる。
というかあれですね。基礎を思い出さないと。まずは、超簡単なコードを出力させます。
console.log(molecule2);
そうそうそう。こういうのでいいんすよ。
よし。心が潤った。まずは細かく分けます(ドンっ)
function moleculeCalculator(){
console.log((molecule1 * denominator2) + (molecule2 * denominator1));
}
moleculeCalculator();
よき。これで分子を計算する関数はできたので、同じ容量で分母も(アロー関数についでに書き換え)。
let moleculeCalculator = () => {
console.log((molecule1 * denominator2) +
(molecule2 * denominator1));
}
let denominatorCalculator = () => {
console.log(denominator1 * denominator2);
}
moleculeCalculator();
denominatorCalculator();
よし。これで分子と分母は計算できましたね。あとは、
1、この値を比較する(テスト)
2、正常に動けばループに組み込む
1、この値を比較する(テスト)
簡単そうに見えたんですが…
// 実装コード
if(moleculeCalculator() - denominatorCalculator() == 0){
console.log("OK");
} else {
console.log("NG");
}
// 動作確認
if(10 - 9 == 0){
console.log("OK");
} else {
console.log("NG");
}
あってそうなんですが上のコードだとチェックできない…
あれ?ifって計算結果で比較できないっけ?と思って下のコード書いたらこっちは正常に動いてます。
つまり数値の計算結果は判断してくれます。が、上のコードだと数値は返ってきてないということになります。
んー戻り値はifで比較できないのか…
とここで過去学んだこと振り返っていると、テストコードのお話が出てきました。
(https://qiita.com/ysktsuna/items/6b8b824e444030070754)
引数ならワンチャン…?と思って試すと…
// molecule分子,denominator分母。数値は後でランダムに変更
const molecule1 = 2;
const molecule2 = 3;
const molecule3 = 1;
const denominator1 = 5;
const denominator2 = 5;
const denominator3 = 1;
// 関数を定義する。通分のアルゴリズム。
let moleculeCalculator = (molecule1,molecule2,denominator1,denominator2) => {
return ((molecule1 * denominator2) +
(molecule2 * denominator1));
}
let denominatorCalculator = (denominator1,denominator2) => {
return (denominator1 * denominator2);
}
// 実装コード
if(moleculeCalculator(molecule1,molecule2,denominator1,denominator2) - denominatorCalculator(denominator1,denominator2) === 0){
console.log("OK");
} else {
console.log("NG");
}
できた!
2、ループを作る
ここで最初の方に悩んでた、「約分の場合は」とか、「叩いた数値を判定するのか?」を決めました。
ランダムに数値を出力していき、正解の時に止まるでいこうかなと思います。
※問題の解釈間違えてたらすいません
ですので、前回同様ランダムの値を入れていきます。参考はこちら。
そして、↑で書いたコードの正解・不正解の出力を分かりやすく修正したのがこちら↓
ランダムもうまく書けたので、後は
・全部の数値をランダムに(分子は一桁、分母は二桁)
・3つの分数にアルゴリズムを書き換える
●最後はループの中に入れる
で完成のはず!
上2つはパパっといけました(ドヤっ)
ループがちょっと躓きました…(1hぐらい)
前回で学習したので、ちょっとイキって「while」使おうとしたら…
つまったToT
言ってても仕方ないのでズンドコの時に使ったループを当てはめると…
for(;;){
const molecule1 = Math.floor( Math.random() * 8 ) + 1;
const molecule2 = Math.floor( Math.random() * 8 ) + 1;
const molecule3 = Math.floor( Math.random() * 8 ) + 1;
const denominator1 = Math.floor( Math.random() * 88 ) + 10;
const denominator2 = Math.floor( Math.random() * 88 ) + 10;
const denominator3 = Math.floor( Math.random() * 88 ) + 10;
// 関数を定義する。通分のアルゴリズム。
let moleculeCalculator = (molecule1,molecule2,molecule3,denominator1,denominator2,denominator3) => {
return ((molecule1 * denominator2 * denominator3) +
(molecule2 * denominator1 * denominator3)
+(molecule3 * denominator1 * denominator2));
}
let denominatorCalculator = (denominator1,denominator2,denominator3) => {
return (denominator1 * denominator2 * denominator3);
}
if(moleculeCalculator(molecule1,molecule2,molecule3,denominator1,denominator2,denominator3) - denominatorCalculator(denominator1,denominator2,denominator3) == 0){
console.log("正解!" + denominator1 + "分の" + molecule1 + "たす"
+ denominator2 + "分の" + molecule2 + "たす"
+ denominator3 + "分の" + molecule3 + "は「1」です!");
break;
}
}
(一応)できた!
リファクタリングする
※先に言います。リファクタリングはできませんでしたToT
ここでいろいろ悩んだのですが、リファクタリングどうしていいのかさっぱり分からん…
このままだと処理落ちしそうなので、メンターとわくわく会にご教授いただきました。以下がその内容。
・まず、関数化しよう。処理の流れが見えづらい。
・分母と分子を持つclassを定義したらいいと思う。
・letとconstの使い方調べた方がいい。
・これそもそも「1〜9の数字被りなしじゃない?」
・moleculeは化学の方の分子です。分数の方はnumerator
and more...
ちょっとまって溺れる(というかFBの海に沈んだ)
ということであれですね。そもそも仕様の理解が間違ってましたねToT
そして、その後画面共有しながら実際に解説付きでコード書いて頂きました。
(こんな神イベント無料で行ってるわくわく会に感謝です!)
ちなみに、正解の一例はこちら↓
(https://codesandbox.io/embed/thirsty-ptolemy-quc1h?codemirror=1)
割り算なので小数点出ますが、割り切れるんや…
さいごに
最後までやり切りたかったですが、自身の都合もあるのでここで投稿させて頂きます。
今回の学びは、
・ズンドコの時と違い2hでできた!(ズンドコは10hぐらいw)
・アルゴリズム考えるのがすごく楽しい
・class(オブジェクト指向)が全然理解できていない
という点でした。
なので、次回JSに取り掛かる時はclass(オブジェクト指向)を使ってやっていきたいと思います!
最後までご覧いただきありがとうございました!
ばーんm_ _m