プログラミングは立ってする事が通常の、ユゲタです。
通常は椅子に座って行うプログラミングですが、人が椅子に座るという事は、逆に体に負荷を与えているという一面もあるので、なるべく立って行えるように作業テーブルの上に、パソコンスタンドをおいて作業してます。
人は、座っているよりも立っている方が、体に負担がかからない自然な姿勢なので、腰痛や膝痛などの軽減にもつながるそうですよ。
本日のIT謎掛け
「パソコン作業」と、かけまして・・・
「大人の男性の正装」と、ときます。
そのココロは・・・
タイピン(typingとネクタイピン)が欠かせません。
アルゴリズム検討
見た目はほぼ完成した「三目並べ」ですが、ちゃんとしたゲームになっていません。
まずは、三目並べでそれぞれが、コマ(マーク)をおいた時に、その都度コマが3つ並んでいるかどうかの判定を行って、3つ並んでいた方の勝ち(○か×)を判定しなければいけません。
三目並べは最初の2手で、勝ち負けがほぼ決まってしまうらしいのですが、難易度の設定はまあまあ難しくなりそうなので、今回は省きます。
参考 :
https://ja.wikipedia.org/wiki/%E4%B8%89%E7%9B%AE%E4%B8%A6%E3%81%B9
ソースコード
(function(){
var LIB = function(){};
LIB.prototype.event = function(target, mode, func , flg){
flg = (flg) ? flg : false;
if (target.addEventListener){target.addEventListener(mode, func, flg)}
else{target.attachEvent('on' + mode, function(){func.call(target , window.event)})}
};
LIB.prototype.construct = function(){
switch(document.readyState){
case "complete" : new MAIN();break;
case "interactive" : this.event(window , "DOMContentLoaded" , (function(){new MAIN()}).bind(this));break;
default : this.event(window , "load" , (function(){new MAIN()}).bind(this));break;
}
};
var MAIN = function(){
// 棋譜格納用のバッファ
this.buffer = [];
this.drawBase();
this.setEvent();
};
MAIN.prototype.drawBase = function(){
var ctx = document.getElementById("mycanvas").getContext("2d");
// 背景
ctx.fillStyle = "#14bdac";
ctx.fillRect(0,0,400,200);
// 枠線
ctx.strokeStyle = "#0da192";
ctx.lineWidth = 6;
ctx.beginPath();
ctx.moveTo(170,20);
ctx.lineTo(170,180);
ctx.stroke();
ctx.fill();
ctx.beginPath();
ctx.moveTo(230,20);
ctx.lineTo(230,180);
ctx.stroke();
ctx.fill();
ctx.beginPath();
ctx.moveTo(120,70);
ctx.lineTo(280,70);
ctx.stroke();
ctx.fill();
ctx.beginPath();
ctx.moveTo(120,130);
ctx.lineTo(280,130);
ctx.stroke();
ctx.fill();
};
MAIN.prototype.setEvent = function(){
var ctx = document.getElementById("mycanvas");
new LIB().event(ctx , "click" , (function(e){this.clickCtx(e)}).bind(this));
};
MAIN.prototype.clickCtx = function(e){
var canvas = e.currentTarget;
// canvas内のクリックされた座標
var posX = e.clientX - canvas.getBoundingClientRect().left;
var posY = e.clientY - canvas.getBoundingClientRect().top;
// 座標から枠判定 [1-9]
var cell = this.checkCell(posX , posY);
if(!cell){return;}
// バッファに登録(登録済みのセルの場合は、処理しない)
if(this.buffer.indexOf(cell) !== -1){return;}
this.buffer.push({
mark : 0,
num : cell
});
// 記号を表示する
this.drawBuffer();
// 判定
if(this.judgement()){return;}
// 続けてコンピュータの手
this.turnComputer();
// 判定
if(this.judgement()){return;}
// 打つ手が無くなったら終了
if(this.buffer.length >= 9){
this.draw();
this.finish();
}
};
MAIN.prototype.checkCell = function(posX , posY){
if(118 <= posX && posX <= 118 + 47
&& 18 <= posY && posY <= 18 + 47){
return 1;
}
if(177 <= posX && posX <= 177 + 47
&& 18 <= posY && posY <= 18 + 47){
return 2;
}
if(236 <= posX && posX <= 236 + 47
&& 18 <= posY && posY <= 18 + 47){
return 3;
}
if(118 <= posX && posX <= 118 + 47
&& 76 <= posY && posY <= 76 + 47){
return 4;
}
if(177 <= posX && posX <= 177 + 47
&& 76 <= posY && posY <= 76 + 47){
return 5;
}
if(236 <= posX && posX <= 236 + 47
&& 76 <= posY && posY <= 76 + 47){
return 6;
}
if(118 <= posX && posX <= 118 + 47
&& 134 <= posY && posY <= 134 + 47){
return 7;
}
if(177 <= posX && posX <= 177 + 47
&& 134 <= posY && posY <= 134 + 47){
return 8;
}
if(236 <= posX && posX <= 236 + 47
&& 134 <= posY && posY <= 134 + 47){
return 9;
}
return null;
};
MAIN.prototype.drawBuffer = function(){
var canvas = document.getElementById("mycanvas");
var ctx = canvas.getContext("2d");
// 描画をクリアする
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 基盤を表示
this.drawBase();
// バッファ全ての座標を指定
for(var i=0; i<this.buffer.length; i++){
var num = this.buffer[i].num;
// 奇数番
if(i % 2 === 0){
this.drawMark_0(num);
}
// 偶数
else{
this.drawMark_1(num);
}
}
};
// player-mark @ [0:○ , 1:×]
MAIN.prototype.drawMark_0 = function(cell){
var ctx = document.getElementById("mycanvas").getContext("2d");
var x = y = null , r=16;
switch(cell){
case 1:
x = 118 + 24;
y = 18 + 24;
break;
case 2:
x = 177 + 24;
y = 18 + 24;
break;
case 3:
x = 236 + 24;
y = 18 + 24;
break;
case 4:
x = 118 + 24;
y = 76 + 24;
break;
case 5:
x = 177 + 24;
y = 76 + 24;
break;
case 6:
x = 236 + 24;
y = 76 + 24;
break;
case 7:
x = 118 + 24;
y = 134 + 24;
break;
case 8:
x = 177 + 24;
y = 134 + 24;
break;
case 9:
x = 236 + 24;
y = 134 + 24;
break;
}
if(x === null && y === null){return;}
ctx.strokeStyle = "white";
ctx.beginPath();
ctx.arc(x,y,r, 0/180*Math.PI , 360/180*Math.PI);
ctx.stroke();
};
// com-mark @ [0:○ , 1:×]
MAIN.prototype.drawMark_1 = function(cell){
var ctx = document.getElementById("mycanvas").getContext("2d");
var x1 = y1 = x2 = y2 = null , size1 = 8 , size2 = 38;
switch(cell){
case 1:
x1 = 118 + size1;
y1 = 18 + size1;
x2 = 118 + size2;
y2 = 18 + size2;
break;
case 2:
x1 = 177 + size1;
y1 = 18 + size1;
x2 = 177 + size2;
y2 = 18 + size2;
break;
case 3:
x1 = 236 + size1;
y1 = 18 + size1;
x2 = 236 + size2;
y2 = 18 + size2;
break;
case 4:
x1 = 118 + size1;
y1 = 76 + size1;
x2 = 118 + size2;
y2 = 76 + size2;
break;
case 5:
x1 = 177 + size1;
y1 = 76 + size1;
x2 = 177 + size2;
y2 = 76 + size2;
break;
case 6:
x1 = 236 + size1;
y1 = 76 + size1;
x2 = 236 + size2;
y2 = 76 + size2;
break;
case 7:
x1 = 118 + size1;
y1 = 134 + size1;
x2 = 118 + size2;
y2 = 134 + size2;
break;
case 8:
x1 = 177 + size1;
y1 = 134 + size1;
x2 = 177 + size2;
y2 = 134 + size2;
break;
case 9:
x1 = 236 + size1;
y1 = 134 + size1;
x2 = 236 + size2;
y2 = 134 + size2;
break;
}
if(x1 === null && y1 === null
&& x2 === null && y2 === null){return;}
ctx.strokeStyle = "white";
ctx.beginPath();
ctx.moveTo(x1,y1);
ctx.lineTo(x2,y2);
ctx.stroke();
ctx.fill();
ctx.strokeStyle = "white";
ctx.beginPath();
ctx.moveTo(x1,y2);
ctx.lineTo(x2,y1);
ctx.stroke();
ctx.fill();
};
MAIN.prototype.turnComputer = function(){
// 打つ手が無くなったら終了
if(this.buffer.length >= 9){return;}
// 現在の盤から、空きセルを検索
var emptyCells = this.getEmptyCells();
// 場所を決める
var cellNum = this.getComPlace(emptyCells);
this.buffer.push({
mark : 1,
num : cellNum
});
// 記号を表示する
this.drawBuffer();
};
MAIN.prototype.getEmptyCells = function(){
var arr = [];
for(var i=1; i<=9; i++){
if(this.containNum(i)){continue;}
arr.push(i);
}
return arr;
}
MAIN.prototype.containNum = function(num){
for(var i in this.buffer){
if(this.buffer[i].num === num){
return this.buffer[i];
}
}
};
MAIN.prototype.getComPlace = function(emptyCells){
var num = Math.floor(Math.random() * emptyCells.length);
return emptyCells[num];
}
MAIN.prototype.finish = function(){
console.log("Finish !");
};
// mark @ 対象のコマ(マーク)[0:○ , 1:×] : int
// return @ 3つ並んだら並んでいるマーク(0:○ , 1:×):int を返す , それ以外はnull
MAIN.prototype.judgement = function(){
if(this.buffer.length < 3){return 0;}
// プレイヤーの勝ち
if(this.judgement_player(0)){
return this.win(0);
}
// コンピュータの勝ち
else if(this.judgement_player(1)){
return this.win(1);
}
return 0;
}
MAIN.prototype.judgement_player = function(mark){
// 横一列判定
for(var i in win_pattern){
// [0-2]
var cnt = 0;
for(var j in win_pattern[i]){
var res = this.containNum(win_pattern[i][j])
// bufferに含まれていなければ、NG
if(!res){break;}
// 違うプレイヤーであれば、NG
if(res.mark !== mark){break;}
cnt += 1;
}
if(cnt === 3){
return true;
}
}
}
// 勝ち配列
var win_pattern = [
[1,2,3],
[4,5,6],
[7,8,9],
[1,4,6],
[2,5,8],
[3,6,9],
[1,5,9],
[3,5,7]
];
MAIN.prototype.win = function(mark){
if(mark !== 0 && mark !== 1){return null;}
var user = mark === 0 ? "あなた" : "コンピュータ";
var ctx = document.getElementById("mycanvas").getContext("2d");
// window表示
ctx.fillStyle = "red";
ctx.fillRect(100,50,200,100);
// 文字
ctx.fillStyle = "white";
ctx.font = "bold 16px sans-serif";
ctx.textAlign = "center";
ctx.fillText(user + "の勝ち", 200, 100 , 200);
return 1;
};
MAIN.prototype.draw = function(){
var ctx = document.getElementById("mycanvas").getContext("2d");
// window表示
ctx.fillStyle = "blue";
ctx.fillRect(100,50,200,100);
// 文字
ctx.fillStyle = "white";
ctx.font = "bold 16px sans-serif";
ctx.textAlign = "center";
ctx.fillText("引き分け", 200, 100 , 200);
return 1;
}
new LIB().construct();
})();
解説
勝ちパターンの判定は、3目並べの場合は、縦横ななめの合計8パターン存在します。
これを配列で持っておいて、プレイヤーサイドと、コンピュータサイドの登録された結果データで全てに配置されている場合は、3つ並んだという判定をするようにしました。
ビット計算方式で、もう少し簡潔なコードも書くことは可能ですが、初期版はシンプルアルゴリズムで行うことにしますね。
ちなみに、前回までのプログラムでは、this.bufferに、打ち込んだコマの番号だけを順番に登録していたんですが、どちらのプレイヤーが打ったコマなのかを判断しなければいけないことに気が付き、その点を改修しています。
今のバージョンだと、コンピュータがランダムだけなので、アホすぎるので、次回は、もう少し打つ手を考えるようにしてみたいと思います。
0 件のコメント:
コメントを投稿