//================================================== // 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