はじめに
2, 3か月前にこんなゲームを作りました。
「Easy Yathzee」(イージーヤッツィー)という名前にしていますが、元ネタとして「Yathzee」というゲームがあります。
BGAというサイトで遊ぶことができるので興味のある方は以下のリンクで遊んでみてください。
また、switchのアソビ大全では「ヨット」という名前であった気がします。(間違えていたらすみません。)
このゲームをより簡単に遊べるようにしたものが私が作ったゲームです。
本題の前に
綴りを間違えていました。
×「Yathzee」
〇「Yahtzee」
Githubやソースコード内、すべてでYathzee
と記述しておりました^^;許してください
まだ未完全な状態での公開となっております。
数字を変えて役が成立した場合、本来なら数字が変わってからalert()
で役名を表示したいのですが、先にalert()
されてしまい変えた後の数字が見えないまま次のターンに進んでしまいます。
また、本来はPlayer 2ではなくCPUを実装したいのですがまだやっておりません。別言語でCPUと対戦出来るものを作ってあるので、もし興味があればそちらで遊んでください。
VS CPU C言語
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include <unistd.h>
int main(void){
int a, b, c, i, j, r, s=0, t=0, score, bonus;
int acpu, bcpu, ccpu, jcpu, scpu=0, tcpu=0, cs, cb;
int arr[100];
int ca[100];
printf("ヤッツィーを始めますか?\n始めるならEnterを押してください。\n");
getchar();
/*たまにある getchar(); は、プレイヤーの好きなタイミングで次の動作を進めるためのもの。
Enterで次に進む。*/
printf("ルールを説明します!!\n"
"1~3の乱数を出します。\n"
"1回につき1個まで乱数を振り直すことができます。\n"
"それらの数字で役を作れた場合、ボーナス点を獲得できます。\n"
"乱数3つの合計点に、ボーナス点を加算したものが1回の得点となります!\n\n"
"これを3回繰り返し、3回の合計点を競います。\n\n"
"~ボーナス~\n"
"・ ヤッツィー ・・・ 全て同じ目が出た場合。10 点\n"
"・ ストレート ・・・ 全て異なる目が出た場合。5 点\n"
"・ リゴール ・・・ 最小の目または最大の目のみを出した場合。3 点\n"
"※なお、ボーナスは重複しません。複数のボーナスに該当する場合、"
"最もボーナス点の高いものだけが適用されます。\n\n"
"このゲームを進行するためには、Enterを押してください。\n\n");
getchar();
srand((unsigned int)time(NULL));
for(i=0;i<=2;i++){
//プレイヤーの処理
printf("プレイヤーの%d回目の挑戦!\n\n", i+1);
for(j=0;j<=2;j++){//3個の乱数を発生させる
arr[j] = rand()%3+1;
printf("%d ", arr[j]);//発生した乱数を出力
}
printf("\n\n");
printf("振り直すなら何番目を振り直すか(1,2,3)、振り直さないなら0を入力!!\n入力→ ");
scanf("%d", &r);
if(r==0){//振り直さない場合
a = arr[0];
b = arr[1];
c = arr[2];
printf("振り直しませんでした。\n%d, %d, %d\n\n", a, b, c);
}
if(r!=0){//振り直す場合
arr[r-1] = rand()%3+1;//r番目を振り直す
a = arr[0];
b = arr[1];
c = arr[2];
printf("振り直した結果 → ");
getchar();
printf("%d %d %d\n\n", a, b, c);
}
score = a + b + c;
if(a==b && b==c){//ヤッツィーの処理
bonus = 10;
printf("ヤッツィー!!!10点獲得!!!\\\\\\\\おめでとう////\n\n");
}
else if(a!=2 && b!=2 && c!=2){//ヤムスの処理
bonus = 3;
printf("リゴール!3点獲得!\n\n");
}
else if(a!=b && b!=c && c!=a){//ストレートの処理
bonus = 5;
printf("ストレート!!5点獲得!!\n\n");
}
else {bonus =0;}//無役の処理
getchar();
s = score + bonus;
printf("合計点=%d点\n\n", s);
t += s;
getchar();
printf("CPU の%d回目の挑戦\n\n", i+1);
getchar();
for(jcpu=0;jcpu<=2;jcpu++){//3個の乱数を発生させる
ca[jcpu] = rand()%3+1;
printf("%d ", ca[jcpu]);//発生させた乱数の出力
}
getchar();
printf("\n\n");
//役がある場合、CPUは振り直さない。役がない場合、最も得点が高くなる可能性がある方法で振り直す。
if(ca[0]==ca[1] && ca[1]==ca[2]){//ヤッツィーの処理。全て同じ。
printf("CPU は振り直しませんでした。\n\n");
}
else if(ca[0]!=ca[1] && ca[1]!=ca[2] && ca[2]!=ca[0]){//ストレートの処理。全て異なる。
printf("CPU は振り直しませんでした。\n\n");
}
else if(ca[0]!=2 && ca[1]!=2 && ca[2]!=2){//リゴールの処理。
printf("CPU は振り直しませんでした。\n\n");
}
else if(ca[0]+ca[1]+ca[2]==7){//2,2,3の場合。else ifなので、1,3,3は除外。
printf("CPU は3が出ている目を振り直します。\n\n");
if(ca[0]==3){
ca[0] = rand()%3+1;
}
if(ca[1]==3){
ca[1] = rand()%3+1;
}
if(ca[2]==3){
ca[2] = rand()%3+1;
}
printf("振り直した結果・・・%d %d %d\n\n", ca[0],ca[1],ca[2]);
}
else if(ca[0]+ca[1]+ca[2]==5){//2,2,1の場合。else ifなので1,1,3は除外。
printf("CPU は1が出ている目を振り直します。\n\n");
if(ca[0]==1){
ca[0] = rand()%3+1;
}
if(ca[1]==1){
ca[1] = rand()%3+1;
}
if(ca[2]==1){
ca[2] = rand()%3+1;
}
printf("振り直した結果・・・%d %d %d\n\n", ca[0],ca[1],ca[2]);
}
else if(ca[0]+ca[1]+ca[2]==4){//1,1,2の場合。
printf("CPU は2が出ている目を振り直します。\n\n");
if(ca[0]==2){
ca[0] = rand()%3+1;
}
if(ca[1]==2){
ca[1] = rand()%3+1;
}
if(ca[2]==2){
ca[2] = rand()%3+1;
}
printf("振り直した結果・・・%d %d %d\n\n", ca[0],ca[1],ca[2]);
}
else if(ca[0]+ca[1]+ca[2]==8){//3,3,2の場合。
printf("CPU は2が出ている目を振り直します。\n\n");
if(ca[0]==2){
ca[0] = rand()%3+1;
}
if(ca[1]==2){
ca[1] = rand()%3+1;
}
if(ca[2]==2){
ca[2] = rand()%3+1;
}
printf("振り直した結果・・・%d %d %d\n\n", ca[0],ca[1],ca[2]);
}
acpu = ca[0];//[]打つのがめんどくさいので
bcpu = ca[1];
ccpu = ca[2];
if(acpu==bcpu && bcpu==ccpu){//ヤッツィーの処理
cb = 10;
}
else if(acpu!=bcpu && bcpu!=ccpu && ccpu!=acpu){//ストレートの処理
cb = 5;
}
else if(acpu!=2 && bcpu!=2 && ccpu!=2){//リゴールの処理
cb = 3;
}
else{//無役の処理
cb = 0;
}
if(cb==0){
printf("CPU はボーナスを獲得しませんでした。\n\n");
}
else{
printf("CPU はボーナスとして%d点を獲得しました。\n\n", cb);
}
getchar();
cs = acpu + bcpu + ccpu;//出た目の合計
scpu = cs + cb;//出た目の合計 + ボーナス点
printf("CPUの %d回目の挑戦・・・%d点\n\n\n", i+1, scpu);
tcpu += scpu;//i回目までの合計点
getchar();
}
printf("結果はっぴょう!!Enterを押してください。");
getchar();
printf("\n\n");
printf("あなたの得点は %d 点です!!!\n\n\n", t);
printf("そして、CPUの得点は %d 点です。\n\n\n", tcpu);
getchar();
//勝敗
if(t>tcpu){
printf("おめでとうございます!!\n%d点差であなたの勝ちです!!\n", t-tcpu);
if(t-tcpu>=10){//大差で勝利した場合のみ特別演出
printf("圧勝だね!!\n\n");
}
}
else if(t==tcpu){
printf("同点でした。次は勝てるかな?\n\n");
}
else if(t<tcpu){
printf("残念でした。\n%d点差であなたの負けです。次は頑張って^^\n", tcpu-t);
}
printf("遊んでくれてありがとう!!");
getchar();
getchar();
return 0;
}
コードが汚いのは許してください。昔何の知識も持たずに作ったものをそのまま載せます。
解説
HTML
HTMLソースコード
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Easy Yathzee</title>
<script src="main.js"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<table id="diceTable">
<tr>
<td id="dice1" class="touchable"></td>
<td id="dice2" class="touchable"></td>
<td id="dice3" class="touchable"></td>
</tr>
</table>
<button id="decide">変更しない</button>
<table id="scoreTable">
<thead>
<tr>
<th></th>
<th>Player 1</th>
<th>Player 2</th>
</tr>
</thead>
<tr>
<th>1回目</th>
<td class="scoreTd" class="myScore"></td>
<td class="scoreTd" class="cpuScore"></td>
</tr>
<tr>
<th>2回目</th>
<td class="scoreTd" class="myScore"></td>
<td class="scoreTd" class="cpuScore"></td>
</tr>
<tr>
<th>3回目</th>
<td class="scoreTd" class="myScore"></td>
<td class="scoreTd" class="cpuScore"></td>
</tr>
<tr id="resultRow">
<th>結果</th>
<td id="playersScore"></td>
<td id="CPUsScore"></td>
</tr>
</table>
</body>
</html>
解説することがないかもしれません。
id名がmyScore
, cpuScore
となっているのはCPU対戦機能を付けたかった名残です。
CSS
CSSソースコード
body {
padding-top: 10px;
}
#diceTable {
display: inline;
border-spacing: 30px 0px;
}
#diceTable td {
border: 2px solid black;
margin-right: 50px;
width: 100px;
height: 100px;
text-align: center;
font-size: 300%;
border-radius: 50px;
}
button {
background-color: honeydew;
border-radius: 5px;
}
button:hover {
background-color: rgb(220, 255, 220);
}
#scoreTable {
border: 2px solid black;
margin-top: 30px;
margin-left: 30px;
}
#resultRow {
background-color: rgb(255, 224, 85);
}
#scoreTable td , th {
border: 1px solid black;
width: 120px;
height: 60px;
font-size: 150%;
text-align: center;
}
.touchable {
background-color: rgb(206, 255, 132);
}
.touchable:hover {
background-color: rgb(190, 255, 93);
}
.scoreTd {
background-color: rgb(214, 214, 214);
}
工夫した点は、
#diceTable td {
border-radius: 50px;
}
でダイスの目が表示されるところを丸くしたところ、
button:hover {
background-color: rgb(220, 255, 220);
}
.touchable:hover {
background-color: rgb(190, 255, 93);
}
の2行では、マウスを上に持ってきたときに背景色が少し変わるようにし、プレイヤーが操作したいマスをわかりやすくしたところ、などです。
JavaScript
JavaScriptソースコード
window.onload = () => {
const dice1 = document.querySelector("#dice1");
const dice2 = document.querySelector("#dice2");
const dice3 = document.querySelector("#dice3");
const diceBoxes = [dice1, dice2, dice3];
const decideBut = document.querySelector("#decide");
const scoreTds = Array.from(
document.querySelectorAll('.scoreTd')
);
let dices = [];
let copyDices = [];
let turn = 1;
const play = () => {
dices = [];
copyDices = [];
for(let i=0;i<=2;i++){
dices.push(random(1,3));
}
copyDices = [...dices];
diceBoxes.forEach((element, index)=>{
element.innerText = copyDices.shift();
element.removeEventListener('click', changeDice);
element.addEventListener('click', changeDice, false);
})
decideBut.removeEventListener('click', noChangeDice);
decideBut.addEventListener('click', noChangeDice, false);
}
const changeDice = (index) => {
let elmIdx = index.srcElement.id.slice(-1)-1;
let changedNum = random(1,3);
console.log(turn, elmIdx, dices[elmIdx]);
console.log(dices);
dices[elmIdx].innerText = changedNum;
dices[elmIdx] = changedNum;
writeScore(dices);
}
const noChangeDice = () => {
writeScore(dices);
}
const writeScore = (dices) => {
let sum = 0;
dices.forEach((element)=>{
sum += element;
});
let score = sum + bonus(dices);
switch(score-sum){
case 10:
alert('YATHZEE !!!');
break;
case 5:
alert("Straight !!");
break;
case 3:
alert("Regoll !");
break;
}
scoreTds[turn-1].innerText = score;
if(turn<6){
turn+=1;
play();
}else{
result();
}
}
const bonus = (dices) => {
let bonusPoints = 0;
const dice1 = dices[0];
const dice2 = dices[1];
const dice3 = dices[2];
if(dice1==dice2 && dice2==dice3){
bonusPoints+=10;
}else if(dice1!==dice2 && dice2!==dice3 && dice3!==dice1){
bonusPoints+=5;
}else if(dice1!==2 && dice2!==2 && dice3!==2){
bonusPoints+=3;
}
return bonusPoints;
}
const result = () => {
const myScore = document.querySelector('#playersScore');
const cpusScore = document.querySelector('#CPUsScore');
const scores = Array.from(document.querySelectorAll('.scoreTd'));
let myPoints = Number(scores[0].innerText) + Number(scores[2].innerText) + Number(scores[4].innerText);
let cpuPoints = Number(scores[1].innerText) + Number(scores[3].innerText) + Number(scores[5].innerText);
myScore.innerText = myPoints;
cpusScore.innerText = cpuPoints;
decideBut.disabled = true;
dice1.innerText = 'お';
dice2.innerText = 'わ';
dice3.innerText = 'り';
diceBoxes.forEach((element)=>{
element.removeEventListener('click', changeDice);
element.style.backgroundColor = 'white';
})
decideBut.innerText='また遊んでね';
}
const random = (min, max) => {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max-min+1)+min);
}
play();
}
順に解説していきます。
window.onload = () => {
}
これは、HTMLのheadタグにscriptタグを挿入したため、必要となった記述です。
これがないとbodyタグの中より先に
const dice1 = document.querySelector("#dice1");
const dice2 = document.querySelector("#dice2");
const dice3 = document.querySelector("#dice3");
などが読み込まれてしまい、そんなタグは存在しませんとエラーが発生します。
const dice1 = document.querySelector("#dice1");
const dice2 = document.querySelector("#dice2");
const dice3 = document.querySelector("#dice3");
const diceBoxes = [dice1, dice2, dice3];
const decideBut = document.querySelector("#decide");
この部分は、ゲームの得点や進行に関わるノードを取得しています。
4行目では、3つのダイスを操作しやすいように1つの配列に格納しています。
実際のプレイ画面ではここにあたります。
const scoreTds = Array.from(
document.querySelectorAll('.scoreTd')
);
この記述は、クラス名がscoreTd
のノードをすべて取得し、配列にしています。
実際のプレイ画面では、この灰色のtd
6つです。
ちなみに、Array.from()
でくくらずに
const scoreTds = document.querySelectorAll('.scoreTd');
とすると、scoreTds
には配列風オブジェクトが取得され、push()
などの配列用の操作ができません。
初見は躓くと思います。
let dices = [];
let copyDices = [];
ここでは、下のplay
関数で繰り返し使うための配列が宣言されています。
const
での宣言でよかったかもしれません。
let turn = 1;
ターンの宣言、初期化です。
play
関数ではこれが6未満のとき、turn
に1
加算してplay
関数を呼び出すようにしています。
中心部分に入っていきます。
const play = () => {
dices = [];
copyDices = [];
for(let i=0;i<=2;i++){
dices.push(random(1,3));
}
copyDices = [...dices];
diceBoxes.forEach((element, index)=>{
element.innerText = copyDices.shift();
element.removeEventListener('click', changeDice);
element.addEventListener('click', changeDice, false);
})
decideBut.removeEventListener('click', noChangeDice);
decideBut.addEventListener('click', noChangeDice, false);
}
play
関数です。
dices = [];
copyDices = [];
ここでは先ほどと同様初期化を行い、
for(let i=0;i<=2;i++){
dices.push(random(1,3));
}
ここでは、配列dice
に1~3の乱数を3つ格納しています。
copyDices = [...dices];
ここでは、配列dices
をディープコピーしたものを配列copyDices
に格納しています。
もし
copyDices = dices
としてしまうと、シャローコピーとなり、配列dices
の値を変更すると配列copyDices
の値も同時に変更されてしまいます。参照先の異なる別のオブジェクトとしてcopyDices
を作りたかったので、スプレッド演算子を用いてこのようにしています。
詳しくはこちらをご覧ください。
diceBoxes.forEach((element, index)=>{
element.innerText = copyDices.shift();
element.removeEventListener('click', changeDice);
element.addEventListener('click', changeDice, false);
})
ここでは、配列diceBoxes
の各要素に配列copyDices
の中身(1~3の数字3つ)を順に設定し、関数changeDice
があれば取り除き、その後関数changeDice
を設定しています。
remove
してやらないと何度も関数changeDice
が呼び出されてしまいます。しかし、そもそももっと良い書き方があったと思います。関数play
のなかに書かなければこんな処理は必要なかったんじゃないかと今になって思いました。
decideBut.removeEventListener('click', noChangeDice);
decideBut.addEventListener('click', noChangeDice, false);
ここでは、「変更しない」ボタンに関数noChangeDice
が設定されていれば取り除き、その後設定しています。
上と同様にもっと良い方法があったと思います。
続いて、関数changeDice
です。
const changeDice = (index) => {
let elmIdx = index.srcElement.id.slice(-1)-1;
let changedNum = random(1,3);
dices[elmIdx].innerText = changedNum;
dices[elmIdx] = changedNum;
writeScore(dices);
}
まず、引数index
はconsole.log(index)
としてみると、
と表示されます。
展開してみると、下のほうに
とあり、index.srcElement
とはクリックされたtd
要素であることが分かります。
続いて.id
でそのid名を取得し、slice(-1)
でid名の最後の文字(1~3の文字)を取得し、-1
で1引いています。
まとめると、クリックされたダイス(td)の番号(0~2)を取得するための記述です。
あまりにも無理やりですね。
コードを見ただけでは何が取得できているのか分かりづらいですし、この引数名index
はdiceBoxes.forEach((element, index)=>{};
のindex
と混同されかねないです。
とりあえず、これで取得できたダイスの番号(0~2)が変数elmIdx
に取得されます。
let changedNum = random(1,3);
では、新しいダイスの目を決定しています。
この2つを用いて、クリックされたtdの目を変更しているのが次の記述です。
dices[elmIdx].innerText = changedNum;
これはあくまで表示上の数値を変えただけです。
得点計算のために内部の数値も変える必要があります。
dices[elmIdx] = changedNum;
そして変更まで終わった配列dices
を引数として関数writeScore
を呼び出します。
関数writeScore
の記述の前に、ダイスを振り直さなかった場合(変更しないボタンを押した場合)に呼ばれる関数noChangeDice
の記述があります。
const noChangeDice = () => {
writeScore(dices);
}
関数writeScore
です。
const writeScore = (dices) => {
let sum = 0;
dices.forEach((element)=>{
sum += element;
});
let score = sum + bonus(dices);
switch(score-sum){
case 10:
alert('YATHZEE !!!');
break;
case 5:
alert("Straight !!");
break;
case 3:
alert("Regoll !");
break;
}
scoreTds[turn-1].innerText = score;
if(turn<6){
turn+=1;
play();
}else{
result();
}
}
let sum = 0
ここで1回あたりの合計点に用いる変数の初期化を行っています。
dices.forEach((element)=>{
sum += element;
});
ここでは、単純なダイスの目の合計を求め、先程初期化した変数sum
としています。
let score = sum + bonus(dices);
ここでは、sum
にbonus(dices)
を加え、1回あたりの得点を求めています。
関数bonus
に関しては後程説明します。
switch(score-sum){
case 10:
alert('YATHZEE !!!');
break;
case 5:
alert("Straight !!");
break;
case 3:
alert("Regoll !");
break;
}
ここでは、score-sum
(=bonus得点)に応じて、alert()
しています。
score-sum
という周りくどい書き方が気になるので、
let score = sum + bonus(dices);
switch(score-sum){
case 10:
alert('YATHZEE !!!');
break;
case 5:
alert("Straight !!");
break;
case 3:
alert("Regoll !");
break;
}
を
let bonusPoint = bonus(dices)
let score = sum + bonusPoiunt;
switch(bonusPoint){
case 10:
alert('YATHZEE !!!');
break;
case 5:
alert("Straight !!");
break;
case 3:
alert("Regoll !");
break;
}
のようにした方がよさそうです。
また、sum
, score
という名前もどの合計なのか、どの時点でのスコアなのかなど分かりづらいため、改善の余地がありそうです。
続いて、
scoreTds[turn-1].innerText = score;
この記述で、求めたscore
を画面上に表示しています。
if(turn<6){
turn+=1;
play();
}else{
result();
}
ここでは、変数turn
が6未満なら1足して関数play
を呼び出す、変数turn
が6以上なら関数result
を呼び出しています。
関数bonus
に関しての説明です。
const bonus = (dices) => {
let bonusPoints = 0;
const dice1 = dices[0];
const dice2 = dices[1];
const dice3 = dices[2];
if(dice1==dice2 && dice2==dice3){
bonusPoints+=10;
}else if(dice1!==dice2 && dice2!==dice3 && dice3!==dice1){
bonusPoints+=5;
}else if(dice1!==2 && dice2!==2 && dice3!==2){
bonusPoints+=3;
}
return bonusPoints;
}
まず、
let bonusPoints = 0;
ここで初期化をしています。
const dice1 = dices[0];
const dice2 = dices[1];
const dice3 = dices[2];
ここで、配列dices
の各要素を新しい変数に格納しています。
これは記述を減らしたかったからだと思うのですが、それほど記述量が変わっていないどころか増えてそうなので、不要だと思いました。
if(dice1==dice2 && dice2==dice3){
bonusPoints+=10;
}
これは、全ての値が同じ⇔役ヤッツィーが出たときの処理です。
else if(dice1!==dice2 && dice2!==dice3 && dice3!==dice1){
bonusPoints+=5;
}
これは全ての目が異なる⇔役ストレートが出たときの処理です。
ダイスの数が3つのときしか成り立たない記述で直感的でないため、こちらも配列のメソッドを使うなどして改善の余地がありそうです。
else if(dice1!==2 && dice2!==2 && dice3!==2){
bonusPoints+=3;
}
これは全ての目が2でない⇔役リゴールが出たときの処理です。
リゴールの条件は最小の目または最大の目が出ることですので、ダイスの数が3つであればこれで成立しますが、改善の余地がありそうです。
return bonusPoints;
求めたbonusPoint
を返しています。
最後に、関数result
に関する説明です。
const result = () => {
const myScore = document.querySelector('#playersScore');
const cpusScore = document.querySelector('#CPUsScore');
const scores = Array.from(document.querySelectorAll('.scoreTd'));
let myPoints = Number(scores[0].innerText) + Number(scores[2].innerText) + Number(scores[4].innerText);
let cpuPoints = Number(scores[1].innerText) + Number(scores[3].innerText) + Number(scores[5].innerText);
myScore.innerText = myPoints;
cpusScore.innerText = cpuPoints;
decideBut.disabled = true;
dice1.innerText = 'お';
dice2.innerText = 'わ';
dice3.innerText = 'り';
diceBoxes.forEach((element)=>{
element.removeEventListener('click', changeDice);
element.style.backgroundColor = 'white';
})
decideBut.innerText='また遊んでね';
}
まず、
const myScore = document.querySelector('#playersScore');
const cpusScore = document.querySelector('#CPUsScore');
const scores = Array.from(document.querySelectorAll('.scoreTd'));
ここでは、上図の灰色の部分を左上から右上、左中...の順に取得しています。
let myPoints = Number(scores[0].innerText) +
Number(scores[2].innerText) + Number(scores[4].innerText);
let cpuPoints = Number(scores[1].innerText) +
Number(scores[3].innerText) + Number(scores[5].innerText);
取得した灰色の部分について、偶数番目の要素のinnerText
の合計をmyPoints
に、奇数番目の合計をcpuPoints
に格納しています。
myScore.innerText = myPoints;
cpusScore.innerText = cpuPoints;
求めた合計得点を画面上に表示させています。
decideBut.disabled = true;
ゲームが終わったため、変更しないボタンを使えないようにしています。
dice1.innerText = 'お';
dice2.innerText = 'わ';
dice3.innerText = 'り';
diceBoxes.forEach((element)=>{
element.removeEventListener('click', changeDice);
element.style.backgroundColor = 'white';
})
decideBut.innerText='また遊んでね';
ちょっとした遊び心と、ダイスを振り直せないようにする処理です。
ゲームが終わると下のようになり、視覚的にゲームが終わったと分かりやすくしています。
最後に、関数random
です。
const random = (min, max) => {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max-min+1)+min);
}
1~3の乱数を得るための関数です。こちらを参考にしました。
本当の最後に
play();
で1度目の関数play
の実行です。
全体的な改善点、問題点
- 変数
turn
の値が奇数ならPlayer 1、偶数ならPlayer 2のターンとしているところが直感的でないと感じた。記述は増えるが改善すべきだと思う。 - id名、クラス名が、
myScore
,cpuScore
,playersScore
,CPUsScore
など、 統一感がない。 - 気分で関数を分けたが、これで良いのか?どう分けるのか知識を身に付けた方が良さそう。
- そもそも設計してない、知識がないからできない。
- 文字列を数値に暗黙に変換してて気持ち悪い。
最後に
ここまでちゃんと自分のコードを振り返るのは初めてだった。自分に足りない知識など気付くことが多くあった。
リファクタリングの知識、設計の知識をもっとつけたい。
そしてどうやったらバグは直るんだT^T
TypeScriptで書いたらひどいことになりそう。そっちもやる