JavaScript製のオセロです、そこそこ強いです。
先手、後手と白、黒から始めるからを選びStartを押して始めてください。
あとは普通のオセロと同じです。
<body onload="AllReset()">
<script type="text/javascript" charset="Shift_JIS">
/////////////////////////////////////
/* オセロ Ver1.3 */
/* Programing by 月見 */
/* http://www.bc.wakwak.com/~cosa/ */
/////////////////////////////////////
//////////////////
/* フォーム作成 */
//////////////////
document.write("<form name='Othello' id='Othello'>"); //フォームの作成
Pcounter=0;
document.write("<div id='Xnum'>1 2 3 4 5 6 7 8</div>");
for(i=1;i<=8;i++){
document.write("<br />"+i+" ");
for(j=1;j<=8;j++){
document.write('<input type="text" size="1" name="P'+i+","+j+'" onclick="ReverCheck('+Pcounter+')" />');
Pcounter++;
}
}
document.write("</form>");
////////////////////////
/* グローバル変数宣言 */
////////////////////////
var flag1; //先手=1 後手=0
var flag2; //ループを抜けるためのフラグ
var flag3; //0ならばひっくり返す数値を返す
var flag4; //ひっくり返せる場所があるなら1
var flag5; //黒=1 白=0
var flag6; //スタートしたか?
var flag8; //割り込み禁止
var ChaCounter; //ひっくり返す枚数
var WriCheck; //駒の保存
var ComCheck; //COMの思考場所
var FAdd; //フルアドレス
var Max; //返す枚数が多い場所
var Xmax; //返す場所のX座標
var Ymax; //返す場所のY座標
var FMax; //返す場所のフルアドレス
var NowX; //置いた場所のX座標
var NowY; //置いた場所のY座標
var NoReverCount //両方とも返せる?
////////////////
/* 処理関数群 */
////////////////
function Start_Reset() //ゲーム開始
{
if(!flag6){
flag6=1;
document.Information.Msg.value="";
document.Setting.SorR.value="Reset";
WBNumber()
if(document.Setting.Color[0].checked){
flag5=1;
document.Information.Which.value="●の番です";
}else{
flag5=0;
document.Information.Which.value="○の番です";
}
if(document.Setting.Either[0].checked){
flag1=1;
}else{
flag1=0;
ComLogic();
ReverCheck(FMax);
}
}else{
flag6=0;
AllReset();
document.Setting.SorR.value="Start";
}
}
function AllReset() //すべて初期化 初期値代入
{
flag2=1;
flag3=1;
flag4=1;
flag6=0;
flag8=1;
ChaCounter=0;
WriCheck=new Array(64);
ComCheck=new Array(64);
Max=0;
Xmax=0;
Ymax=0;
FMax=0;
for(i=0;i<64;i++) WriCheck[i]="";
WriCheck[27]="○";
WriCheck[28]="●";
WriCheck[36]="○";
WriCheck[35]="●";
for(i=0;i<64;i++) document.Othello.elements[i].value=WriCheck[i];
document.Information.Com.value="";
document.Information.Which.value="";
document.Information.Msg.value="";
document.Information.White.value="";
document.Information.Black.value="";
}
function PlayerChage(FAdd) //プレイヤー交替とチェック
{
if(ChaCounter != 0){
WriCheck[FAdd]=NowPiece;
if(flag1 && flag4){
flag1=0;
WhichColor();
}else{
flag1=1;
WhichColor();
}
document.Information.Msg.value="";
}else{
document.Information.Msg.value="そこには置けない";
}
WBNumber();
for(i=0;i<64;i++) document.Othello.elements[i].value=WriCheck[i];
}
function WhichColor() //次はどっち?
{
if(flag1){
if(flag5)
document.Information.Which.value="●の番です";
else
document.Information.Which.value="○の番です";
}else{
if(flag5)
document.Information.Which.value="○の番です";
else
document.Information.Which.value="●の番です";
}
}
function WorB() //白と黒を切り替え、flag5がtrueなら先手は黒
{
if(flag1){
if(flag5)
{
NowPiece="●";
NexPiece="○";
}else{
NowPiece="○";
NexPiece="●";
}
}else{
if(flag5)
{
NowPiece="○";
NexPiece="●";
}else{
NowPiece="●";
NexPiece="○";
}
}
}
function NoReverCheck() //ひっくり返す場所があるかチェック
{
var RMax=0;
NoReverCount=0;
ChaCounter=0;
flag4=1;
WorB();
flag3=0;
for(j=0;j<64;j++){
if(WriCheck[j] == ""){
ChaCounter=0;
ReverNumber(j);
if(ChaCounter>RMax) RMax=ChaCounter;
}
}
flag3=1;
if(RMax == 0){ //ひっくり返す場所がない
document.Information.Msg.value="置く所がないのでパス";
flag4=0;
NoReverCount++;
if(flag1){
flag1=0;
WhichColor();
}else{
flag1=1;
WhichColor();
}
}
}
function ComTime() //時間差プログラム
{
clearTimeout(Com);
ReverNumber(FMax);
PlayerChage(FMax);
document.Information.Com.value="Comは("+Xmax+","+Ymax+")におきました";
}
function ReverCheck(PointAdd) //フォームクリックしたら動く
{
if(flag6 && flag8){
flag8=0;
FAdd=PointAdd; //グローバル変数に
if(WriCheck[FAdd] == ""){
NoReverCount=0;
NoReverCheck();
if(flag1 && flag6){
ReverNumber(FAdd);
PlayerChage(FAdd);
}
NoReverCheck();
if(!flag1 && flag6){
document.Information.Com.value="Com思考中";
ComLogic();
Com=setTimeout("ComTime()",800);
}
if(NoReverCount == 2)WBNumber();
}
flag8=1;
}else{
document.Information.Msg.value="Startを押してください";
}
WBNumber();
}
function ReverNumber(FAdd) //返す場所をチェック
{
NowX=FAdd_x(FAdd);
NowY=FAdd_y(FAdd);
ReverChange(1,FAdd); //→ 右
ReverChange(-1,FAdd); //← 左
ReverChange(8,FAdd); //↓ 下
ReverChange(-8,FAdd); //↑ 上
ReverChange(7,FAdd); //←↓ 左下
ReverChange(-7,FAdd); //←↑ 左上
ReverChange(9,FAdd); //→↓ 右下
ReverChange(-9,FAdd); //→↑ 右上
}
function ComLogic() //コンピューター思考
{
Max=1;
Xmax=0;
Ymax=0;
FMax=-1;
WorB();
// var RevPoint=new Array(30); //ランダム機能追加時 2行とも//をはずす
// for(j in RevPoint) RevPoint[j]="";
for(j in WriCheck) ComCheck[j]=WriCheck[j];
RevCounter=0;
flag7=1;
flag3=0;
flag8=1;
ComLoop();
function ComLoop(){
for(j=0;j<64;j++){
if(ComCheck[j] == ""){
ChaCounter=0;
ReverNumber(j);
if(String(j).match(/^0$|^7$|56|63/) && ChaCounter != 0){
flag8=0;
FMax=j;
Xmax=FAdd_x(j);
Ymax=FAdd_y(j);
break;
}
if(flag7 && String(j).match(/^1$|^6$|^8$|^9$|14|15|48|49|54|55|57|62/))continue;
//ランダム機能追加時 ここから下を5行削除
if(ChaCounter>=Max){
Max=ChaCounter;
FMax=j;
Xmax=FAdd_x(j);
Ymax=FAdd_y(j);
}
//ここまで
/* 置く場所をランダムに。 処理速度が極端に落ちるので保留 (追加時 /* */をはずす)
if(ChaCounter>=Max){
Max=ChaCounter;
RevPoint[RevCounter]=j;
for(j=0;j<RevCounter;j++){
ran=Math.floor(Math.random()*(RevCounter+1))
Back=RevPoint[j];
RevPoint[j]=RevPoint[ran];
RevPoint[ran]=Back;
}
RevCounter++;
}
*/
}
}
}
if(FMax == -1){
flag7=0;
ComLoop();
}
flag7=1;
flag3=1;
// ランダム機能追加時 ここから下5行//をはずす
// if(flag8){
// FMax=RevPoint[0];
// Xmax=FAdd_x(RevPoint[0]);
// Ymax=FAdd_y(RevPoint[0]);
// }
}
function WBNumber() //白と黒の数をカウント
{
var WhiCounter=0; //白が何枚
var BlaCounter=0; //黒が何枚
for(i=0;i<64;i++) if(WriCheck[i].indexOf("○") != -1) WhiCounter++;
for(i=0;i<64;i++) if(WriCheck[i].indexOf("●") != -1) BlaCounter++;
document.Information.White.value=WhiCounter;
document.Information.Black.value=BlaCounter;
if(WhiCounter+BlaCounter == 64 || WhiCounter == 0 || BlaCounter == 0 || NoReverCount == 2){
flag6=1;
document.Information.Which.value="";
document.Information.Com.value="";
if(WhiCounter > BlaCounter)
document.Information.Msg.value="白の勝ち";
else if(WhiCounter < BlaCounter)
document.Information.Msg.value="黒の勝ち";
else if(NoReverCount == 2)
document.Information.Msg.value="引き分け";
}
}
function ReverChange(FulPos,FAdd) //ひっくり返す(flag3がfalseならば返す枚数だけを返す)
{
flag2=0;
var RevCounter=FulPos; //フルアドレスをコピー
var OldY=NowY; //ひとつ前のY座標
while(0 <= FAdd+RevCounter && FAdd+RevCounter < 64){
if(WriCheck[FAdd+RevCounter] == "") break;
NexX=FAdd_x(FAdd+RevCounter);
NexY=FAdd_y(FAdd+RevCounter)
if(FulPos == 1 || FulPos == -1){
if(NowY != NexY) break;
}else{
if(OldY == NexY) break;
}
if(FulPos == 7 || FulPos == -9)if(NowX < NexX) break;
if(FulPos == 9 || FulPos == -7)if(NowX > NexX) break;
if(WriCheck[FAdd+RevCounter] == NowPiece){
flag2=1;
break;
}
OldY=FAdd_y(FAdd+RevCounter);
RevCounter+=FulPos;
}
if(flag2){
if(FulPos<0){
for(i=FulPos;i>RevCounter;i+=FulPos){
if(flag3)WriCheck[FAdd+i]=NowPiece;
ChaCounter++;
}
}else{
for(i=FulPos;i<RevCounter;i+=FulPos){
if(flag3)WriCheck[FAdd+i]=NowPiece;
ChaCounter++;
}
}
}
return(ChaCounter);
}
function FAdd_x(FulAdd) // FAdd → x 変換
{
y=(FulAdd%8 == 0)? 1:(FulAdd%8)+1;
return(y);
}
function FAdd_y(FulAdd) // FAdd → y 変換
{
x=Math.floor(FulAdd/8)+1;
return(x);
}
function xy_FAdd(xP,yP) //x,y → FAdd 変換
{
FulAdd=(((yP-1)*8)+xP)-1;
return(FulAdd);
}
</script>
意外に苦戦しましたよ。ルールが単純明快なんですぐできるとタカをくくっていたのが間違い。 ひっくり返すのをやるアルゴリズムをつくるのに苦戦...
今までの反省を活かして、プログラム作成中にメモをところどころ入れています。 多少はいままでよりプログラムがみやすくなっています。