「はじめに」から引用する。
この本は、有名なカードゲーム「ポーカー」の作成を通して、 複数のモジュールで構成されるプログラムを JavaScript で「組み立てる力」を学ぶ本です。
以下はただの粗探しである。
p.215 のコードブロックでカードの図柄
というコメントがある。
前のページの本文やコードではカードの絵柄
となっている。
そのため、p.215 もカードの絵柄にするのがいいと思う。
本書は最後に、トランプのゲームとして有名なポーカーを実装することで、 設計から実装までの多くを解説している。さて、ポーカーは、役の強さによって勝ち負けを決める。 役の強さは、手札のカードの絵柄(スート)と数字(ランク)の組合せで決まる。 この強さを計算するために、本書ではさまざまなメソッドが実装されている。 たとえば、役を構成するカードのランクの合計をもとめるために、Util クラスの sum というメソッドが実装されている。 sum は次のようにして使う。ここで cards は手札のカードを表すオブジェクトの長さ 5 の配列だ。cards には rank というプロパティがあり、 数字を表している。
this.#rank = Util.sum(cards[0].rank, cards[1].rank, cards[2].rank,
cards[3].rank, cards[4].rank);
やっていることはわかるのだが、ループでもできそうなところをわざわざ引数を複数使っているのはもったいないような気がする。 さて、sum メソッドは次のようにして実装している。p.197 から引用する。
export default class Util {
・・・中略・・・
static sum = (...numbers) => {
let sum = 0;
numbers.forEach((e) => {
sum + e;
});
return sum;
};
}
本書で解説されているスプレッド構文 (pp.124-126) を使っている。なるほど。ただ、配列を崩しているのが惜しい、と思う。
私にはいい案がない。ひとつの考えとしては、sum メソッドを作るのをやめて、直接配列の和を求める手続きを書くことが考えられる。 そこで、foreach よりさらに簡素な式で和を求めることができないかを考える。 さいわい、配列にはこのような場合に都合のいい reduce メソッドがある(本書では未解説)。 これをを使って合計を求める式はこうなる。
s = numbers.reduce( (p, c) => p + c, 0);
p は previous を、c は current を表している。まず p を 0 に初期化して、numbers[0] の値を c にいれ、 p + c を計算し、この値を新たに p とする。これを c を number[0] から number[number.length - 1] まで繰り返し、最終的に p を返す。返された p として配列 numbers の和が得られる。
この1行を書けばいいからわざわざメソッドにしなくてもいいだろう。カードのランクの合計を求める式はこうなる。
this.#rank = cards.reduce( (p, c) => p + c.rank, 0);
今は cards の要素すべての和を使ったが、部分配列の和を求めるには slice を使えばいい。たとえば、 numbers[1] から numbers[4] までの配列の和を求めるには次のようにする。
s = numbers.slice(1, 5).reduce( (p, c) => p + c, 0);
対象となる配列の終わりの要素は number[4] であること、slice メソッドの第二引数に 5 を指定していることに注意する。
ポーカーの役の中にフラッシュがある。フラッシュとは、手札の5枚がすべて同じスートである役である。 p. 226-227 では、フラッシュかどうかをを次のような if 文で判断している。
if ( cards[0].suit === cards[1].suit && cards[0].suit ===
cards[2].suit && cards[0].suit === cards[3].suit &&
cards[0].suit === cards[4].suit)
もう少し、コード量が少なくなる方法はないのだろうか。一案としては、配列の
every メソッドを使うことが考えられる。 every
メソッドは次のサイトに解説がある。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/every
コードは次のようになるだろう。
if ( cards.every((e) => e.suit === cards[0].suit))
e は cards[0] から cards[cards.length-1] まで走る。e が cards[0] のときは判定の等号文が確実に成り立つので内部のループが一回ムダに走るが、コードの簡潔さのほうが優ると思う。
ポーカーの役の中にストレートがある。5枚のカードのランクが連続(隣接)している役である。 pp.227-228 では、ストレートかどうかを次のような if 文で判断している。ここで cards[i].rank は昇順にソーティングされていることが前提である。
if ( cards[0].rank + 1 === cards[1].rank && cards[1].rank + 1 ===
cards[2].rank && cards[2].rank + = 1 === cards[3].rank &&
cards[3].rank + 1 === cards[4].rank)
これも every メソッドを使えば完結に書けると期待できるが、どうか。
if ( cards.every((e, i) => e.rank === cards[0].rank + i))
e は cards[0] から cards[cards.length - 1] まで走り、i は 0 から cards.length -1 まで走る。この場合も e が cards[0] のときは判定の等号文が確実に成り立つので内部のループが一回ムダに走るが、やはりコードの簡潔さのほうが優ると思う。
場所 | 誤 | 正 |
---|---|---|
p.47 コードブロック最終行 | console.log(apple.mede_in.length()); |
console.log(apple.made_in.length); |
書名 | 図解! JavaScriptのツボとコツがゼッタイにわかる本 プログラミング実践編 |
著者 | 中田亨 |
発行日 | 2022 年 8 月 22 日 第 1 版 第 1 刷 |
発行元 | 秀和システム |
定価 | 2500 円(本体) |
サイズ | A5 判 ページ |
ISBN | 978-4-7980-6724-7 |
その他 | 草加市立図書館で借りて読む |
まりんきょ学問所 > コンピュータについて > コンピュータの本 > JavaScript, altJS > 中田亨:図解! JavaScriptのツボとコツがゼッタイにわかる本 プログラミング実践編