//==================================================
// Web-time Playing Board System for Renju
//
// JS function for PLAY-GAMEs only
// 2007/03/02~03/08
//==================================================
/*
*/
var UNDO_LINE = "";
//=================================
// make caption
//=================================
function makeCaption ( getGame ){
with( getGame ){
var Black = BLACK != MASK_NAME ? BLACK : "黒";
var White = White != MASK_NAME ? WHITE : "白";
}
with( getGame ){
var onGoing = STATUS;
}
if( onGoing != 'P' ){
if( onGoing.match( /[BbwW]/ ) ){
return "
「@」の勝ち
".replace( /@/, getShowName( onGoing.match( /[Bb]/ ) ? Black : White ) ) +
"♠ 勝った人は、局後検討の後でこの譜をOVER-GAMEsへ納譜して下さい。
";
}else{
return "満局です
";
}
}
//------------------------- each turn
with( getGame ){
var GemLine = GEM_LINE;
var request = REQUEST;
var grade = FLAGs.match( /L/ ) ? ( Math.floor( GRADE / 10 ) - GRADE % 10 ) : 0;
}
var lastMove = getLastMove( GemLine );
var lastestMove = getLastMove( GemLine.replace( /!\-\-\-/, "" ) );
var modeUndo = GemLine.match( /@\-/ );
var modeExtra = GemLine.match( /@\+/ );
var modeSwap = GemLine.match( /\$[X|=]/ );
var captionString = "";
captionString = "" +
"「@」の手番です。".replace( /@/, getShowName( ( lastestMove & 1 ) ? getGame.WHITE : getGame.BLACK ) ) +
"
";
if( lastestMove < 4 && !modeSwap && grade ){
captionString += "♠ この局は梯子打ちです。@には、+PLUSのハンデが題数に加算されます。
".replace( /@/g, getShowName( grade < 0 ? White : Black ) ).replace( /PLUS/, Math.abs( grade ) );
}
if( modeUndo ){
captionString += "♠ @が「待った」を申請しています
* 受諾…「着珠ボタン」を押す
* 拒否…盤をクリックしてからキーボードの「↑キー」を押し、それから「着珠ボタン」を押す
".replace( /@/, getShowName( ( lastMove & 1 ) ? White : Black ) );
}
if( modeExtra ){
captionString += "♠ @が「代打ち」しています
* 拒否…「着珠ボタン」を押す
* 受諾…盤をクリックしてからキーボードの「↑キー」を押し、それから「着珠ボタン」を押す
".replace( /@/, getShowName( ( lastMove & 1 ) ? Black : White ) );
}
if( modeUndo || modeExtra ){
return captionString;
}
if( getGame.REQUEST.match( /[Dd]/ ) ){
captionString += "♠ 「@」が引き分けを提案しています
".replace( /@/, getShowName( getGame.REQUEST == 'D' ? Black : White ) );
}
if( getGame.REQUEST.match( /[Cc]/ ) ){
captionString += "♠ 「@」が破棄を提案しています
".replace( /@/, getShowName( getGame.REQUEST == 'C' ? Black : White ) );
}
switch( lastMove ){
case 0:
captionString += "♠ 珠型と題数分のベタ珠を打って「着珠ボタン」を押して下さい
";
break;
case 1: case 2:
break;
case 3:
if( modeSwap ){ break; }
captionString += "♠ 黒番か白番かを選んで下さい" + "
* 黒選択…「着珠ボタン」を押す" + "
* 白選択…白4を打ってから「着珠ボタン」を押す
";
break;
case 4:
captionString += "♠ 五珠をベタ珠の題数分打って「着珠ボタン」を押して下さい
";
break;
default:
}
return( captionString );
}
//=======================================
// submit play-games
//=======================================
function submitPLAY_GAMEs( callMode ){
var Fobj = document.getElementById( 'FORM_PLAY' );
//----------------------------- waiting
if( Fobj.getAttribute( 'WAITing' ) ){
alert( WAIT_MESSAGE );
return;
}
var mineID = getCookie( 'ID' );
//-------------------------- has right
if( !mineID ){
alert( "この部屋を使う権利がありません" );
return;
}
//-------------------------- no game
if( GAME_SERIAL == 0 || !GAME_LIST.PLAY[ GAME_SERIAL ] ){
alert( "対局が指定されていません。" );
return;
}
if( callMode == 'message' ){
if( !Fobj.MESSAGE.value.match( /[^\s \n]/ ) ){
alert( "メッセージが空です。" );
return;
}
}else{
var thisGame = GAME_LIST.PLAY[ GAME_SERIAL ];
var ImBlack = thisGame.BLACK == mineID;
var ImWhite = thisGame.WHITE == mineID;
//------------------------- I am player
if( !ImBlack && !ImWhite ){
alert( "対局権がありません。" );
return;
}
if( thisGame.STATUS.match( /[BbDwW]/ ) ){
if( callMode.match( /move|draw|resign|won|time|cancel/ ) ){
alert( "終局しています。" );
return;
//----------------------- save
}else if( callMode == 'save' ){
if( thisGame.STATUS.match( ImBlack ? /[Ww]/ : /[Bb]/ )
&& ( new Date() ).getTime() < ( ( thisGame.DATE_LAST + 3600 * 24 * 7 ) * 1000 )
){
alert( "納譜権利がありません。\n終局から7日経過すると、権利が発生します。"
/*
+ "\n" +
( new Date( thisGame.DATE_LAST + 3600 * 24 * 1 ) * 1000 ).toLocaleString() + "\n" + ( new Date() ).toLocaleString()
*/
);
return;
}
if( !confirm( "この局をOVER-GAMEsへ「納譜」しますか?" ) ){
return;
}
}
}else if( thisGame.STATUS == 'P' ){
//----------------------- limit time
var getLimit = thisGame.LIMIT * 3600 * 24;
// if( getLimit && getLimit <= thisGame[ ImBlack ? "TIME_BLACK" : "TIME_WHITE" ] ){
if( getLimit &&
getLimit <= ( thisGame[ ImBlack ? "TIME_BLACK" : "TIME_WHITE" ] +
( ( getNextTurn( thisGame.GEM_LINE ) ? ImBlack : ImWhite )
? getAddTime( thisGame.DATE_LAST )
: 0
)
)
){
alert( "タイムオーバーなので打てません。" );
return;
}
if( callMode == 'save' ){
alert( "対局中です" );
return;
}else if( callMode == 'move' ){
callMode = checkGamePlayMove(); // 'move'/'swap'/false
if( !callMode ){
document.applets[ 0 ].setGemLineString( thisGame.GEM_LINE );
return;
}
}else{
if( !checkGamePlayMode( callMode ) ){
return;
}
if( callMode == 'won' && !wonGame( thisGame.GEM_LINE, ImBlack ) ){
if( ( getLastMove( thisGame.GEM_LINE ) & 1 ) == ( ImBlack ? 1 : 0 ) ){
alert( "五連が並んだときか、相手が禁手を打ったときに押して下さい" );
return;
}else{
callMode = 'pass';
}
}
}
}else{
alert( "未知のコマンドです" );
return;
}
}
//------------------ call WtPBS by iframe
callWtPBS( callMode, GAME_SERIAL );
//alert( callMode + "\n" + GAME_SERIAL );
//------------------ team match member's name check
Fobj.setAttribute( 'WAITing', true );
}
//=======================================
// input check [game play]
//=======================================
function checkGamePlayMode( callMode ){
var mineID = getCookie( 'ID' );
var thisGame = GAME_LIST.PLAY[ GAME_SERIAL ];
var ImBlack = thisGame.BLACK == mineID;
var ImWhite = thisGame.WHITE == mineID;
var getLimit = thisGame.LIMIT * 3600 * 24;
var UrTimeOver = ( getLimit &&
getLimit <= ( thisGame[ ImBlack ? "TIME_WHITE" : "TIME_BLACK" ] +
( ( getNextTurn( thisGame.GEM_LINE ) ? ImWhite : ImBlack )
? getAddTime( thisGame.DATE_LAST )
: 0
)
)
);
//----------------------- reset time
if( callMode == 'time' ){
if( UrTimeOver ){
return( confirm( "相手に時間を与えますか?" ) );
}else{
alert( "相手はタイムオーバーではありません" );
return false;
}
}
//----------------------- reset time
if( callMode == 'cancel' ){
if( UrTimeOver ){
return( confirm( "相手がタイムオーバーになってます。\nあなたは、直ちにこの局を破棄する権利を持っています。\nこの局を「破棄」しますか?" ) );
}
if( thisGame.REQUEST == ( ImBlack ? "C" : "c" ) ){
return confirm( "この局の「破棄」提案を取り消しますか?" );
}else if( thisGame.REQUEST == ( ImBlack ? "c" : "C" ) ){
return confirm( "この局の「破棄」に同意しますか?" );
}else{
return confirm( "この局の「破棄」を提案しますか?" );
}
}
//----------------------- game over [ resign/draw/won ]
var thisLastMove = getLastMove( thisGame.GEM_LINE );
if( callMode == 'resign' || callMode == 'draw' || callMode == 'won' ){
if( thisLastMove < 10 ){
alert( "10珠以内では「投了」と「満局提案」と「勝局」を使えません" );
return false;
}
}
if( callMode == 'resign' ){
return confirm( "投了しますか?" );
}
if( callMode == 'draw' ){
if( thisGame.REQUEST == ( ImBlack ? "D" : "d" ) ){
return confirm( "この局の「満局」提案を取り消しますか?" );
}else if( thisGame.REQUEST == ( ImBlack ? "d" : "D" ) ){
return confirm( "この局の「満局」に合意しますか?" );
}else{
return confirm( "満局提案しますか?" );
}
}
if( callMode == 'won' ){
var getGemLine = thisGame.GEM_LINE;
if( getGemLine.match( /@[\+\-]/ ) ){
alert( "「待った」と「代打ち」があるときは、勝局ボタンを押せません。" );
return false;
}
if( ImBlack ){
if( ( getLastMove( getGemLine ) & 1 ) == 1 ){
return true;
}
alert( "最後の珠があなたの手ではありません" );
return false;
}else{
return(
( getLastMove( getGemLine ) & 1 ) == 0 ||
confirm( "黒の最後の珠が禁手でない場合、白の手番をパスしたことになります" )
);
}
}
alert( "error mode [" + callMode + "]" );
return false;
}
//=======================================
// input check [game play]
//=======================================
function checkGamePlayMove(){
var thisGame = GAME_LIST.PLAY[ GAME_SERIAL ];
var gemLineOld = thisGame.GEM_LINE;
var gemLineNew = "" + document.applets[ 0 ].getGemLine();
var cutGemLineOld = gemLineOld.replace( /!---/, "" );
var cutGemLineNew = gemLineNew.replace( /!---/, "" );
//-------------------------------------------- Illegal change [ old --> new ]
if( cutGemLineOld != "" &&
cutGemLineOld.indexOf( cutGemLineNew ) == -1 &&
cutGemLineNew.indexOf( cutGemLineOld ) == -1
){
alert( "譜が改竄されました。\\n送信を中止します。" );
return false;
}
var mineID = getCookie( 'ID' );
var ImBlack = mineID == thisGame.BLACK;
var ImWhite = mineID == thisGame.WHITE;
var pointerMoveOld = getLastMove( gemLineOld.replace( /!---.*$/, "" ) );
var pointerMoveNew = getLastMove( gemLineNew.replace( /!---.*$/, "" ) );
var lastestMoveOld = getLastMove( cutGemLineOld );
var lastestMoveNew = getLastMove( cutGemLineNew );
//-------------------------------------------- move mode check [ Undo/Extra/Accept ]
var hasUndo = gemLineOld.match( /@\-/ );
var hasExtra = gemLineOld.match( /@\+/ );
//=====================================================================
// undo check [ has no new moves ]
//=====================================================================
if( lastestMoveOld == lastestMoveNew && pointerMoveNew < pointerMoveOld ){
if( !thisGame.FLAGs.match( /U/ ) ){
alert( "この局には「待った」が設定されていません" );
return false;
}
//-------------------------------------------------------------------
// back to opponent [ request undo or accept part extra ]
//-------------------------------------------------------------------
if( ( pointerMoveNew & 1 ) == ( ImBlack ? 1 : 0 ) ){
alert( "待ったミス\n最後を相手の珠にして下さい。" );
return false;
}
if( pointerMoveNew < 3 ){
alert( "珠型までしか戻せません" );
return false;
}
document.applets[ 0 ].setGemLineString( setUndo( gemLineNew.replace( /@\+.+.*$/, "" ) ) );
return "move";
}
//========================================================================
// accept part extra / accept part Undo [ has no new moves ]
//========================================================================
if( lastestMoveOld == lastestMoveNew && pointerMoveOld < Math.max( pointerMoveNew, lastestMoveOld ) ){
//-------------------- old pointer <> new pointer
if( ( pointerMoveOld & 1 ) != ( pointerMoveNew & 1 ) && pointerMoveNew < lastestMoveNew ){
if( hasUndo ){
alert( "待った同意ミス\n最後を相手の珠にして下さい" );
}else{
alert( "代打ち移動ミス\n最後を自分の珠にして下さい" );
}
return false;
/*
if( hasUndo && pointerMoveNew < lastestMoveNew ){
alert( "待った同意ミス\n最後を相手の珠にして下さい" );
return false;
}
alert( "代打ち移動ミス\n最後を自分の珠にして下さい" );
return false;
*/
}
//-------------------- old new pointer = mine
if( ( pointerMoveOld & 1 ) == ( ImBlack ? 1 : 0 ) ){
if( hasExtra ){
if( pointerMoveNew == lastestMoveNew ){
alert( "代打ち移動してません" );
return false;
}
if( gemLineNew.match( /@\+..(.*)!\-\-\-/ ) ){
var cutExtraGems = RegExp.$1;
document.applets[ 0 ].setGemLineString(
gemLineOld.replace( /!\-\-\-.*$/, "!---" + cutExtraGems ).replace( /@\+..!\-\-\-$/, "" )
);
}else{
document.applets[ 0 ].setGemLineString(
gemLineOld
);
}
return "trim";
}
if( hasUndo ){
document.applets[ 0 ].setGemLineString(
trimGemLine(
gemLineNew.replace( /@\-../, "" ),
thisGame.FLAGs.match( /L/ ) ? thisGame.GRADE : 0
)
// gemLineNew.replace( /@\-../, "" ).replace( /!\-\-\-.*$/, "" )
);
if( pointerMoveNew < lastestMoveNew ){
if( gemLineNew.match( /!---(.*)$/ ) ){
UNDO_LINE = RegExp.$1;
status = UNDO_LINE;
}
return confirm( "待ったを受諾しますか?" ) ? "trim" : false;
}else{
return "trim";
}
}
}else if( hasUndo ){
if( pointerMoveOld < pointerMoveNew ){
document.applets[ 0 ].setGemLineString( setUndo( gemLineNew ) );
return 'trim';
}else{
alert( "待った移動してません" );
return false;
}
}else if( hasExtra ){
document.applets[ 0 ].setGemLineString( gemLineNew.replace( /@\+../, "" ).replace( /!\-\-\-.*$/, "" ) );
return 'trim';
}
}
// hereafter, proof [ pointerMove = lastestMove ]
//-----------------------------------------------------------------
// my turn @ opening 5th ?
//-----------------------------------------------------------------
var isNotMyTurn = false;
if( lastestMoveOld == 5 ){
if( ImBlack ){
if( gemLineNew.match( /@_../ ) && !gemLineNew.match( /A5../ ) ){
document.applets[ 0 ].setGemLineString( trimGemLine( gemLineNew, thisGame.FLAGs.match( /L/ ) ? thisGame.GRADE : 0 ) );
return 'move';
}
isNotMyTurn = true;
}
}else if( lastestMoveOld < 5 ){
if( ( lastestMoveOld & 1 ) == ( ImBlack ? 1 : 0 ) ){
isNotMyTurn = true;
}
}else if( lastestMoveOld + 1 == lastestMoveNew ){
if( ( lastestMoveOld & 1 ) == ( ImBlack ? 1 : 0 ) ){
isNotMyTurn = true;
}
}else if( gemLineOld == gemLineNew && !hasUndo && !hasExtra ){
alert( "次の珠を打って下さい。" );
return false;
}
if( isNotMyTurn ){
alert( "あなたの手番ではありません" );
return false;
}
//-----------------------------------------------------------------
// right move ?
//-----------------------------------------------------------------
switch( lastestMoveOld ){
case 1:
case 2:
alert( "データが壊れています。\n管理人に報告して下さい" );
return false;
case 0:
if( ImBlack ){
var errorOpening = isRightOpening( gemLineNew );
if( errorOpening ){
alert( errorOpening ); //XXXXXXXXXXXXXXXXXXXX
return false;
}
}
return "move";
case 3:
if( pointerMoveNew == 3 && !gemLineOld.match( /\$=/ ) ){
return 'swap';
}
if( pointerMoveNew != 4 ){
alert( "4珠目を打って下さい。" ); //XXXXXXXXXXXXXXXXXXXX
return false;
}
return "move";
case 4:
if( isSymmetrical5th( gemLineNew ) == 1 ){
alert( "同じ形になる五珠は、同時に打てません" ); //XXXXXXXXXXXXXXXXXXXX
return false;
}
var matching5thMessage = isLegal5th( gemLineNew );
if( matching5thMessage ){
alert( matching5thMessage );
return false;
}
return "move";
case 5:
if( !gemLineNew.match( /a6/ ) ){
alert( gemLineNew.match( /A5/ )
? "六珠目を打って下さい"
: "五珠目を指定して下さい"
);
return false;
}else if( ( lastestMoveOld & 1 ) == ( ImBlack ? 1 : 0 ) ){
alert( "五手目では、代打ちの追加はできません" );
return false;
}
break;
default:
break;
}
if( ( lastestMoveNew & 1 ) == ( ImBlack ? 0 : 1 ) ){
alert( "最後の珠が自分の珠じゃない" );
return false;
}
//-----------------------------------------------------------------
// with EXTRA moves ?
//-----------------------------------------------------------------
if( lastestMoveOld + 1 < lastestMoveNew ){
if( !thisGame.FLAGs.match( /E/ ) ){
alert( "この局には「代打ち」が設定されていません" );
return false;
}
var getNewGem = cutGemLineNew.substring( cutGemLineOld.length );
var extraGemLine;
//--------------------------- not my turn
if( ( lastestMoveOld & 1 ) == ( ImBlack ? 1 : 0 ) ){
extraGemLine = ( hasExtra ? gemLineOld : ( cutGemLineOld + "@+hh!---" ) ) + getNewGem;
//--------------------------- my turn
}else{
var cutMove = ( lastestMoveOld == 5 && gemLineOld.match( /@_/ ) ) ? 8 : 4;
extraGemLine = cutGemLineOld.replace( /@[\+\-]../, "" ) + getNewGem.substr( 0, cutMove ) + "@+hh!---" + getNewGem.substring( cutMove );
}
document.applets[ 0 ].setGemLineString( transGemLine4send( extraGemLine ).replace( /@\-../, "" ) );
return "move";
}else{
document.applets[ 0 ].setGemLineString( cutGemLineNew.replace( /@[\+\-]../, "" ) );
}
return 'move';
}
//===============================================================================================
// set undo
/*
//----------------------------- 2008/01/29
document.applets[ 0 ].setGemLineString( setUndo( gemLineNew.replace( /@\+(.+.*)$/, "" ) ) );
UNDO_LINE = RegExp.$1;
*/
//===============================================================================================
function setUndo ( gemLine ){
var gotoMove = getLastMove( gemLine );
switch( gotoMove ){
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
// alert( gotoMove );
// return gemLine;
// break;
default:
gemLine = gemLine.replace( /(@[\+\-]..)/, "" ).replace( /!---/, "@-hh!---" );
return gemLine.replace( /@\-hh!---$/, "!---" );
}
return gemLine;
}
//===============================================================================================
// trim undo/extra
// switch by pointer move
//===============================================================================================
function trimGemLine ( gemLine, thisGrade ){
var gotoMove = getLastMove( gemLine );
var gradePlus = Math.max( 0, Math.floor( thisGrade / 10 ) - thisGrade % 10 );
//--------------------------------------- back to before 5th
switch( gotoMove ){
case 5:
var count5th = 0;
for( var pos=0; pos @_
}else if( 1 < count5th ){
// }else if( 1 < count5th && !gemLine.match( /a6[A-P]{2}/ ) ){
gemLine = gemLine.replace( /a6[A-P]{2}.*$/, "" );
while( gemLine.match( /(A5..)/ ) ){
var A5XY = RegExp.$1.substr( 2, 2 ).toLowerCase();
gemLine = gemLine.replace( new RegExp( RegExp.$1 ), "@_" + RegExp.$1.substr( 2, 2 ).toLowerCase() );
}
}
break;
case 4:
case 3:
var count5th = 0;
for( var pos=0; pos @_
// }else if( 1 < count5th ){
}else if( 0 < count5th ){
gemLine = ( gemLine
.replace( /(@-..)|(A5..)/g, "" )
.replace( /!---.*$/,
( "A0nOA0nNA0nMA0nL".substr( 0, gradePlus * 4 ) +
"A0oOA0oNA0oMA0oLA0oKA0oJA0oIA0oHA0oGA0oFA0oEA0oDA0oCA0oBA0oA" ).substr( 0, 4*count5th ) + "!---"
)
);
}
break;
}
//--------------------------------------- cut after pointer
gemLine = gemLine.replace( /(@[\+\-]..)*!---.*$/, "" );
if( gemLine.match( /(@[\+\-]..)/ ) ){
return gemLine.replace( /@[\+\-]../, RegExp.$1 + "!---" );
}else{
return gemLine;
}
}
/*
function gem2num (gem){
if(isNaN(parseInt(gem,36))){
return(-1);
}
return((parseInt(gem.substr(0,1),36)-10)*10+parseInt(gem.substr(1,1)));
}
*/
//================================================
// equal 5th = suggested
//================================================
function isLegal5th ( GemLine ){
var countGem = [];
countGem.A0 = 0;
countGem.A5 = 0;
for( var pos=0; pos