/********************************************************************************************************** Version 1.0j 12.6.2016: Bugfixing and TeamHeader as new feature. * in Firefox with GetFontSize (thanks to Frank Jäger) * NoButton is selected it worked only with one board (thanks to Frank Jäger) * Fix Bug in Firefox: does not update games, after a browser reaload button. * Introduce TeamHeader: A comma separated list displays a header above each row.(idea and patch by Frank Jäger. Version 1.0i 03.01.2016 : Bugfixing (index.html, demo mode did not work), rebuild the core chessboard from tables to divs, adjustment of the css file. Version 1.0h 14.11.2015 : minor changes, switch from ichess to Eitschess Versoin 1.0g 3.8.2013: add in index.html in order to force IE10 into compatibility mode, otherwise the pieces are not displayed !! No changes in the .js file Versoin 1.0f 7.6.2013: Add arrow keys (keyboard) to forward/backward moves, if not in live mode, if more than one board, the first board is taken, which is not in live mode. Version: 1.0e 3.7.2012: Correct count down for dgt boards, when actual time is not provided via *{h:mm:sec}, until 1.0d the clock is set to last moves clock every time an (unchanged) update occurs. with this version, an update only occurs if the loaded data have been changed. Version: 1.0d 28.8.2011: Remove a small bug, that messed up the time count down some times if the time is not cleanly entered. Version: 1.0c 16.8.2011: Eliminate NaN:NaN:NaN in clock display when clock went below 0 Bug:Disable posting.html loading when no posting is present Version: 1.0b 15.8.2011: Add Id to the Table Cells of each Game, in the form of "BoardCell-", this allows to shift entire boards to a different position (thanks to Frank Jaeger). Bug: Remove bug in proc ModifyTOMA, where now any carriage return is replaced by a ' ' space rather than an empty character ScrollIntoView now obsolete, replaced by a reliable function in RefreshBoard Bug: Replace in Procedure: UpdateFile ..imeout("UpdateFile(0)",200).. instea ..imeout("UpdateFile(1)",200), which leads to an endless load-loop when load time exceeds 1 sec. Version: 1.0a 20.6.2011: Remove small bug in GetFontSize() when multiple .css files are present w/o Font defintion an Error occurs. Version: 1.0 14.5.2011: Include DGT-TOMA pgn time tag format (thanks for input from Christian Eichner christian@liveschach-schau.de and Michail Prevenios, mprevenios@gmail.com) 15.5.2011: Introduce a AlterateColor Variable, which allows to automatically rotate boards at the beginning by defining a comma separated list named AlternateColors (based on input from Michail Prevenios) Remove Bug in IE (all versions), which results in reload does not properly clean up the sleeping tasks, and therefore the count down is not re-initiated (can lead to long time waitng for first update) Improvement on the posting part (IE did not align properly), including some additions to the eitschess.css file Version: 1.0rc3b 15.3.2011: Remove Bug in function getHttpRequest: if (document.getElementById("Postings")) document.getElementById("Postings").innerHTML =.... (error when Posting is switched off) 19.3.2011: Remove Bug in RotateBoard: Time and Names were not properly reversed - corrected (hint by Christian Eichner) 21.3.2011: Bug in ichess(); IE calculates the widht of the chessboards as zero!!!!, corrected (15.5.2011 Ff). Version: 1.0rc3a * Remove Bug in AnalyzePGN which prevents proper stop of analysis, and caused an error if there were more boards than games * Change Display of boards to only max. games (other boards are empty). Version: 1.0rc3 * Add Preset Games Variable * Modify default of ScrollIntoView variable to be true for single games and false otherwise (input from Danilo Peruš) * Add CookiesAllowed variable to switch off cookies, which can cause instable display of games when unstable upload conditions occur. Version: 1.0rc2a add "if (Parts[ii].length != 2) continue;" in Line 1318 Safari on iPad gives an error if there is nothing after "]" closing bracket *************************************************************************************************************/ var EitschessVersion = "1.0j"; // Version var cssFileName = "css/eitschess.css" var PgnFileName = "pgn/ichess.pgn"; // PGN FileName to work with; var PostingFileName = "posts/posts.html"; // File containing actual postings var AddPostsFileName = "posts/posts.php"; // File which writes new postings on the server var UpdateInterval = 5; // Read frequency of the pgn file in seconds, not recommended to use less than aprox. 5 seconds! var InitialClock = "1:30:00"; // initial Clock settings var IsDemo = 0; // if Demo is set to 1, it seeks simulates a continous game by gradually cutting off some of the moves. // in the same directory as given in PgnFileName var AllowPostings = 1; // Defines if Postings are accepted or not var PieceName = "KQRBNP"; // the SAN notation in which the games are delivered (King,Queen,Rook,Bishop,Night,Pawn) var ShowPieceName = "KDTLSB"; // the SAN notation to be displayed var Scale = 0.6; // Scaling of the Board var Rows = 1; // Number of Rows var Cols = 2; // Number of Colums var TeamHeaders = ""; // Comma separated list, displays header information above each affected row, useful for team competions // var PresetGames = ""; // no preset of games, just follow the .pgn order var AlternateColors = ''; // 0 .white at the bottom (std), 1.. black at the bottom, so: var AlternateColors="1,0,1,0" starts with black on the bottom and alteranates the next four games var DisplayPostings = "n"; // values: l=left,r=right,t=top,b=bottom or anything else to disable var PostingHeight = 10; // Number of lines to display for Postings (if enabled) var Author =" Rev:"+EitschessVersion+" (cc)-by Felix Fuernhammer Eitschess.com "; var DisableURI = false; // URI input can be disabled, in order to prevent for instance manipulation on UpdateInterval variable var ScrollIntoView = false; // This defines, if the last move should be displayed when updated, it is a nuisance when the number of boards exceeds the page height. var TimeCountDown = true; // Timer for countdown during moves var OneMovePerLine = false; // Displays only one move per line in the pgn area, instead of as many as the width of the field and the fontsize allow var NoFooter = false; // Switches off the Footer, only allowed for local broadcasting due to licensing var NoButtons = false; // Switches off the Move-Buttons, used for local broadcasting var NoGameSelectForm = false; // Switches off the Games Select Form, mainly for local broadcasting var CookiesAllowed = false; // disable cookies by default, as it can lead to strange effect if the upload is not stable => Need future rework // the variables below normally dont need to be modified/changed var FontSize = 12; // Nominal FontSize in pt when Field Size ids 65 pixel, is modified by .css entry in #iChess (font-size) var Size = 56; // Size of the Pieces in the original png grapics, use Scale for modification var TimeOut = 400; // in msec for screen refreshes, etc. (this is not the pgn update interval) increase on old machines var gImagePath = "png/"; // Path for images var SkipRefresh = 0; var IsLoading = 0; // set to 1 if file is loaded var gImagePathOld = "-"; var gPostingName = "Name"; var gLastGameSelCont = 0; var MaxMove=300, isInit=false, isMoving=false, isCalculating=false, i; var King=0, Queen=1, Rook=2, Bishop=3, Night=4, Pawn=5, OOO=6, OO=7, NullM=8; var ShowTimeInPGN = false; // true/false to show clock information in pgn section (format in ichess.css #pgn t) var CorrectPadding = 0; var gPics = new Array('1x1.png', 'k.png', 'q.png', 'r.png', 'b.png', 'n.png', 'p.png'); var isIE = CheckIE(); PieceCode = new Array(6); for (i=0; i<6; i++) PieceCode[i] = PieceName.charCodeAt(i); // the following four arrays contain the pgn data PgnMoveText = new Array(); // GameText = new Array(); //FenText = new Array(); //SanText = new Array(); var MvCount = new Array(); var LastMove = new Array(); var MvTyp = new Array(); var IsLive = new Array(); var Brd = new Array(); var Tags = new Array(); var Piece = new Array(); var PosX = new Array(); var PosY = new Array(); var PMovs = new Array(); var HTime = new Array(); var HPiece = new Array(); var HTyp = new Array(); var HPosX = new Array(); var HPosY = new Array(); var ActiveGames = new Array(); var PostingFeedback = "Post sent, please be patient"; var textPosts= new Array("Posting deactivated!", "Post Comment (viewable by everybody)!", "Posts selectively enabled!", "Send Post!", "Currently no postings!"); var IsFirstPass = 0; // a variable to compensate for a bug in Firefox (after reload button, the content is not properly displayed; function sign(nn) { if (nn>0) return(1); if (nn<0) return(-1); return(0); } function getKeyCode(event) { var BNr, ll=IsLive.length; event = event || window.event; Key = event.keyCode; for (BNr=0; BNr < IsLive.length; BNr++) { // document.formular.ausgabe.value = BNr + ": getKeyCode mit Dezimalwert " + Key + " gedrückt"; if (! IsLive[BNr]) { switch(Key){ case 37: MoveBack(BNr,1); break; case 39: MoveForward(BNr,1); break; default: break; } return event.keyCode; } } return event.keyCode; } function LoadCSS(cssFileName) { var e = document.createElement("link"); e.type = "text/css"; e.rel = "stylesheet"; e.href = cssFileName; document.getElementsByTagName("head")[0].appendChild(e); } function EvalUrlString() { var entry, llist, ii, jj, wert, url = window.location.search; if ((DisableURI) || (url == "")) return; url=url.substring(1, url.length); // strip the precedign ? off url=url.replace(/\|/g,'/'); // allow | instead of / for directory delimiter url=url.replace(/%7C/g,'/'); // slash representation url=unescape(url); // the URI is ususally "unescaped" i.e critical letters are hex represented llist = url.split("&"); for (ii=0; ii=0 ) return ActGame; return -1; } function WriteCookie() { // first delete old cookie if(document.cookie) { var cookie = document.cookie.split(";"); var a = new Date(); a.setTime(a.getTime() -(1000*60*60)); // one hour before; document.cookie = cookie[0]+'; expires='+a.toGMTString()+';'; } cookie = "Selection="; for (var BNr = 0; BNr < (Rows*Cols); BNr++) cookie +=GetActiveGame(BNr)+","; var a = new Date(); a = new Date(a.getTime() +1000*60*60); // coockie resides one hour var x = cookie; // +'; expires='+a.toGMTString()+';'; document.cookie = x; } function GetActiveGame(BNr) { // gets active game stored in ID 'fsel-X' of Board X var sel = ReadCookie(BNr); if ((sel < 0) || (sel >= PgnMoveText.length)) { if ((ActiveGames) && (ActiveGames.length>BNr)) sel = ActiveGames[BNr]; else { var x = document.getElementById('GameSel-'+BNr); if (x) { var sel = x.selectedIndex; } else { sel = BNr; }; } } return(sel%PgnMoveText.length); } function RotateBoard(BNr, Refresh) { // Called if Board rotation is clicked (black sq or numbering area) with (document) { var selObj = getElementById('isRotated-'+BNr),rot=GetIsRotated(BNr),bl, blObj,wh, whObj; if (selObj) selObj.value = (1 - rot); blObj=getElementById('Black-'+BNr); if (!blObj) return; whObj=getElementById('White-'+BNr); if (!whObj) return; bl=blObj.style.backgroundColor; wh=whObj.style.backgroundColor; with (blObj.style) { backgroundColor=wh; color=bl; } with (whObj.style) { backgroundColor=bl; color=wh; } with (getElementById('TimeBlack-'+BNr).style) { backgroundColor=wh; color=bl; } with (getElementById('TimeWhite-'+BNr).style) { backgroundColor=bl; color=wh; } } if (Refresh) RefreshBoard(BNr); } function CheckIE() { // check if Browser is IE5.5 or 6.0 for png bug correction var arVersion = navigator.appVersion.split("MSIE"); var version = parseFloat(arVersion[1]); if (isNaN(version)) return(0); else return(version); } function ExtendArrays(BNr) { // Extends all necessary arrays if an additional board is defined var i,j; if (Brd.length > BNr) return; Brd.push(new Array(8)); i=Brd.length-1; for (j=0; j<8; j++) Brd[i][j] = new Array(8); MvCount.push(0); LastMove.push(0); MvTyp.push(0); IsLive.push(1); Tags.push(new Array('White','Black','...')); Piece.push( new Array(new Array(16), new Array(16))); PosX.push( new Array(new Array(16), new Array(16))); PosY.push( new Array(new Array(16), new Array(16))); PMovs.push( new Array(new Array(16), new Array(16))); HTime.push( new Array(MaxMove)); HPiece.push(new Array(new Array(MaxMove),new Array(MaxMove))); HTyp.push( new Array(new Array(MaxMove),new Array(MaxMove))); HPosX.push( new Array(new Array(MaxMove),new Array(MaxMove))); HPosY.push( new Array(new Array(MaxMove),new Array(MaxMove))); } function GetFontSize() { // Checks if there is a font-size definition in any of the .css style sheets in rule #iChess var obj,i,j,l, FS=FontSize; with (document) { for (i=0;i< styleSheets.length;i++) { if (isIE > 0) obj= styleSheets[i].rules; else obj= styleSheets[i].cssRules; if (obj) { for (j=0; j < obj.length;j++) { if (obj[j].selectorText == "#ichess") { FS = obj[j].style.fontSize; if (FS != "") FontSize = parseInt(FS); } } } } } } function SetFontSize() { // Sets Fontsize to px getting the pixel per pt rate var div, s, px; with (document) { if(!createElement) return; div = createElement('div'); s = div.style; s.border = 'none'; s.padding = 0; s.width = FontSize+'pt'; body.appendChild(div); px = div.offsetWidth; body.removeChild(div); if (! px) px = FontSize * 4 / 3; // if offsetWidth does not work we assume 96 dpi screen resolution FontSize=Math.round(px/2+(px/2*Scale)); var padd = Math.round(FontSize/2) s.padding=padd+'px'; s.width = FontSize+"px"; body.appendChild(div); var px1 = div.offsetWidth; body.removeChild(div); if (px1) CorrectPadding = FontSize + 2*padd -px1; } } function DispPostings(Size) { with (document) { var w = 'auto'; // getElementById("Eitschess").offsetWidth write(""); write(""); write(""); write(""); write("
"); write("
"+textPosts[4]+"
"); } } function AddPosting() { var Name = document.getElementById("Name").value; var Post = document.getElementById("Post").value; if (Post == "") return; if (AllowPostings==0) { document.getElementById("Post").value=textPosts[AllowPostings]; return; } var FName = PgnFileName.split(".")[0]; var FName =FName+".php"; with (document) { var Name = getElementById("Name").value; var Post = getElementById("Post").value; getElementById("Post").value = PostingFeedback; getHttpRequest(AddPostsFileName,"?Name="+escape(Name)+"&Post="+escape(Post)); // Parameter: FileName, String, isPosting getHttpRequest(PostingFileName,"?T="+Math.random()); } } function Check4AlternateColors () { var curcol; // check for color preset in Variable AlterateColors '0,1'); etc. var acols = AlternateColors.split(','); for (var BNr=0; BNr<(Rows*Cols); BNr++) { if (acols.length > BNr) { curcol = GetIsRotated(BNr); if (curcol == (1-acols[BNr])) RotateBoard(BNr,0); } } } function iChess() { // main routine - displays the entire chess board, and initiates file updating var ii, jj,BNr; IsFirstPass = 1; LoadCSS(cssFileName); // loads the CSS style sheet, this allows easier control compared to direct placement // GetFontSize(); // FJ, 20160624 // Adjusts Fontsize from style sheet, this is necessary because there is no page jet //EvalUrlString(); // accounts for url strings in form of ?name1=val1&name2=val2.. SetFontSize(); // Scale the Fontsize to pixel if(typeof PresetGames != "undefined") ActiveGames = PresetGames.split(","); with (document) { write("
"); write("
"); if (DisplayPostings=='t') { DispPostings(PostingHeight+'em');write("
"); WriteGames(); } else if (DisplayPostings=='l') { DispPostings('100%');write(""); WriteGames(); } else if (DisplayPostings=='b') { WriteGames(); write("
");DispPostings(PostingHeight+'ex'); } else if (DisplayPostings=='r') { WriteGames(); write("");DispPostings('100%'); } else { WriteGames(); } write("
"); write(""); // stores the pgn file write(""); // stores UpdateTime write("
"); } if (AlternateColors) Check4AlternateColors(); // set colors along the variable AlternateColors ("comma separated zeros and ones"); setTimeout("UpdateFile(1)",TimeOut); // set remaining time 0 in order to refresh right after load document.onkeydown = getKeyCode; // react on keys } function WriteGames() { with (document) { write(""); for (var ii=0; ii < Rows; ii++) { var SubHeadArray = TeamHeaders.split(","); if ( SubHeadArray.length > ii ) { write(""); } write(""); for (var jj=0; jj < Cols; jj++) { BNr = ii*Cols+jj; write(""); // check if colors are preset (variable AlternateColors), and rotate board if not matched. } write(""); } if (! NoFooter) { write(""); } write("
"+SubHeadArray[ii]+"
"); ExtendArrays(BNr); WriteGame(BNr); write("
"); WriteFooter(); write("
"); } } function WriteGame(BNr) { // displays the entire Board including buttons and Names var BlWhW="width:"+Math.round(5*Size*Scale)+"px; "; var BlWhT="width:"+Math.round(2.5*Size*Scale)+"px; "; var padd = "padding:"+Math.round(FontSize/3)+"px; "; var H0 = "height:"+Math.round(FontSize*7/3)+"px; "; //CorrectPadding; var H1 = "height:"+Math.round(FontSize*2.25)+"px; "; //CorrectPadding; var H2 = "height:"+(Math.round(8.5*Size*Scale+4.5*FontSize))+"px; "; var W1 = "width:"+(Math.round(4*Size*Scale+FontSize*2/3))+"px; "; var FS= "font-size:"+Math.round(1.1*FontSize)+"px; "; var FS1="font-size:"+Math.round(FontSize)+"px; "; var top="vertical-align:top; "; var s = "style='"+(top+W1+H1)+"'"; with (document) { write(""); write(""); // PGN area - must be in
container in order to get the overflow right write("
"); write("
"); //write(""); write(" "); write(""); write( ""); write(""); write(""); write( ""); write(""); write("
"+Tags[BNr]["Black"]+"
"+InitialClock+"
"); WriteBoard(BNr); write("
"+Tags[BNr]["White"]+"
"+InitialClock+"
"); WriteButtons(BNr); write("
"); // Game Selection area write("
"); } } function WriteBoard(BNr) { // writes inner board table (w/o notation) var pic = gImagePath+"1x1.png" var i,j, k; var Size = 55; var nSize=Size*Scale; var nSize3 = nSize/3; var nSize4 = nSize/4; var ReSiz_iChessBrd =" style='width:" + nSize*8.34 +"px;height:" + nSize*8.34 +"px;'"; var ReSiz_iChessImg =" style='width:" + nSize*0.9 +"px; height:" + nSize*0.9 + "px; margin-left:" + nSize*0.05 + "px; margin-right:" + nSize*0.05 + "px;margin-top:" + nSize*0.05 + "px; margin-bottom:" + nSize*0.05 + "px;'"; var ReSiz_iChessRow =" style='height:" + nSize +"px;'"; var ReSiz_iChessSq =" style='width:" + nSize +"px; height:" + nSize + "px;'"; var ReSiz_iChessHNot =" style='width:" + nSize +"px; height:" + nSize3 + "px; line-height:" + nSize3 + "px; font-size:" + nSize4 + "px;'"; var ReSiz_iChessVNot =" style='width:" + nSize3 +"px; height:" + nSize + "px; line-height:" + nSize + "px; font-size:" + nSize4 + "px;'"; var ReSiz_iChessRevBrd =" style='width:" + nSize4 +"px; height:" + nSize4 + "px; margin-left:" + nSize*0.05 + "px; margin-top:" + nSize*0.05 + "px;'"; with (document) { write("
"); // Board outline for (i=0; i<8; i++) { write("
"); for (j=0;j<8;j++) { k = ((j%2 + i%2) == 1 ? " class='iChessSq BlSq'" : " class='iChessSq WhSq'") write("
"); write("
" ) } write("
" + (8-i) +"
"); write("
"); // div Row } for (i=0;i<8;i++) { write("
"+ 'abcdefgh'.charAt(i) + "
") } write("
"); write("
") } } function WriteButtons(BNr) { // writes buttons var ss = Math.round(Size*Scale); var styl=" style='width:"+ss+"px; font-size:"+FontSize+"px;' "; var bIsLive = "live!"; if (UpdateInterval == 0 ) bIsLive=">I"; with (document) { write(""); write(""); write("
"); if (! NoButtons) { write(""); write(""); write(""); write(""); write(""); write(""); write("
"); } write("
"); write(""); write(""); write(""); // only to allow css defintion of the highlighted Move } } function SetLiveButton(BNr,live) { // Sets the live button, (turns to yellow if live but analzed) IsLive[BNr] = live; var lv = "live!"; if ((UpdateInterval==0)||(live==0)) lv = ">I"; with (document) { var obj = getElementById('btnLive'+BNr); if (obj) { if ((live==0) && ( UpdateInterval > 0)) obj.style.background = '#FFCF90' else obj.style.background=getElementById('btnInit'+BNr).style.background; obj.value=lv; } } } function ButtonAction(BNr,no) { // function for Button actions such as MoveForward(1), MoveBack(1), ... switch (no) { case 0 : MoveBack(BNr,MaxMove); SetLiveButton(BNr,0); break; case 1 : MoveBack(BNr,1); SetLiveButton(BNr,0); break; case 2 : MoveForward(BNr,1); SetLiveButton(BNr,0); break; default : MoveForward(BNr,MaxMove); SetLiveButton(BNr,1); break; } } function WriteTime(BNr,rot) { // writes time according to HistTime array var w=InitialClock,b=InitialClock; var mv = MvCount[BNr]-1; mv_1 = mv - 1; if ( HTime[BNr][mv] ) w = HTime[BNr][mv]; else if (mv > 0) w = " "; if ( HTime[BNr][mv_1] ) b = HTime[BNr][mv_1]; else if (mv > 0) b = " "; if ((MvCount[BNr]+rot) % 2 == 1 ) { TimeWh=w; TimeBl=b; } else { TimeBl=w; TimeWh=b; } // set actual Time if available GameNr = GetActiveGame(BNr); if ((Tags[GameNr]['ActTime']) && IsLive[BNr]) { var t = Tags[GameNr]['ActTime'] if (mv % 2) { TimeWh = t } else { TimeBl = t; } } var ID='TimeWhite-'+BNr; with (document) { if ( getElementById && (getElementById(ID))) { if (rot) getElementById(ID).className ="BW Black Time"; // set classes for player color else getElementById(ID).className ="BW White Time"; getElementById(ID).innerHTML = TimeWh; } ID='TimeBlack-'+BNr; if ( getElementById && (getElementById(ID))) { if (rot) getElementById(ID).className ="BW White Time"; // set classes for player color else getElementById(ID).className ="BW Black Time"; getElementById(ID).innerHTML = TimeBl; } } } function WritePlayer(ID, Pl, ToolTip, rot) { // generates the table for the player "Pl" with "Color" Black/White for.css with (document) { if (getElementById && (getElementById(ID))) { if (rot) getElementById(ID).className ="BW Black"; // set classes for player color else getElementById(ID).className ="BW White"; getElementById(ID).innerHTML = '
'+Pl+'
'; // set tool tip and player } } } function WriteBoardNumbers(BNr,rot) { // set Board numbering 1..8 and a..h var i,j; with (document) { if ((! getElementById) || (! getElementById('no_col_'+BNr+'-0'))) return; for (i=0; i<8; i++) { j=i*(1-rot)+(7-i)*rot; getElementById('no_col_'+BNr+'-'+i).innerHTML=8-j; getElementById('no_row_'+BNr+'-'+i).innerHTML='abcdefgh'.charAt(j); } } } function GetToolTips(BNr, Player) { if (Tags[BNr][Player+"Elo"]) return "Elo:"+Tags[BNr][Player+"Elo"]; return "Elo:not broadcasted!"; } function WriteInfos(BNr, rot) { // sets Players and board numbering a..h and 1..8 var sel = GetActiveGame(BNr); var Pl = new Array("White","Black"); // var ToolTips= GetToolTips(sel,"White"); WritePlayer("White-"+BNr, Tags[sel][Pl[rot]], GetToolTips(sel,"White"), rot ); WritePlayer("Black-"+BNr, Tags[sel][Pl[1-rot]], GetToolTips(sel,"Black"), 1-rot ); WriteTime(BNr,rot); WriteBoardNumbers(BNr,rot); } function WriteFooter() { // displays the footer for Author and elapsed time information with (document) { write(""); write(""); write(""); write(""); write(""); write(""); write(""); } } function WriteSelGames() { // generates pull down menue for the different games in the pgn file // first check if more than one game and if there is a tag existing if (! document.getElementById) return; var padd=Math.round(FontSize/3); var Styl1=" style='font-size:"+FontSize+"px; width:100%; padding:"+padd+"px; vertical-align:middle; ' "; var NrOfGames = PgnMoveText.length; if ((NrOfGames == 1) || (NoGameSelectForm)) return; var GameSelForm = "", ii,BNr, GameSelected; for (BNr=0; BNr<(Cols*Rows); BNr++) { if (BNr >= NrOfGames) break; GameSelected=GetActiveGame(BNr); GameSelForm+="
"; var len = GameSelForm.length; if (len == gLastGameSelCont) { return; } // write GameSelect into the
tagged area var ID = document.getElementById('IDGameSel-'+BNr); // ID.innerHTML = GameSelForm; if (ID) { if (ID.innerHTML != GameSelForm) ID.innerHTML = GameSelForm; } // else { ID.innerHTML = "noGames!"; } GameSelForm=""; } gLastGameSelCont = len; var W1 = 4*Size*Scale+FontSize; var x=document.getElementsByTagName("GameSel"); for (var i = 0; i < x.length; i++) { if (x[i].className == "GameSel") { x[i].style.width = (W1)+"px"; x[i].style.padding= Math.round(FontSize/3)+"px"} } } function RestorePos(BNr,ii,bw,Mv,ind) { // Restores a Position in function MoveBack() var x=PosX[BNr][bw][ii], y=PosY[BNr][bw][ii]; var hx0=HPosX[BNr][ind][Mv], hy0=HPosY[BNr][ind][Mv]; Brd[BNr][x][y]=0; Brd[BNr][hx0][hy0]=(HTyp[BNr][ind][Mv]+1)*(1-2*bw); } function RestorePiece(BNr,ii,bw,Mv,ind) { // Restores a Piece in function MoveBack() var hx0=HPosX[BNr][ind][Mv], hy0=HPosY[BNr][ind][Mv]; Piece[BNr][bw][ii]=HTyp[BNr][ind][Mv]; PosX[BNr][bw][ii]=hx0; PosY[BNr][bw][ii]=hy0; PMovs[BNr][bw][ii]--; } function MoveBack(BNr,NrMvs) { // move NrMv Halfmoves back var ii, jj, Mv,bw,x,y,hx1,hy1; isMoving=true; for (jj=0; ((jj 0)); jj++) { MvCount[BNr]--; Mv=MvCount[BNr]; MvTyp[BNr]=1-MvTyp[BNr]; bw = MvTyp[BNr]; ii=HPiece[BNr][1][Mv]; if ((0<=ii)&&(ii<16)) { RestorePos(BNr,ii,bw,Mv,1); } // we must do this here because of Chess960 castling // Restore regular move ii=HPiece[BNr][0][Mv]; RestorePos(BNr,ii,bw,Mv,0); // restore index 0 RestorePiece(BNr,ii,bw,Mv,0); // restore index 0 ii=HPiece[BNr][1][Mv]; if ((0<=ii)&&(ii<16)) { RestorePiece(BNr,ii,bw,Mv,1) } // restore additional piece (such as rook in 0-0 ii-=16; if (0<=ii) { // captured opponents piece RestorePiece(BNr,ii,1-bw,Mv,1) hx1=HPosX[BNr][1][Mv]; hy1=HPosY[BNr][1][Mv]; Brd[BNr][hx1][hy1]=(HTyp[BNr][1][Mv]+1)*(2*bw-1); } } if (isCalculating) { isMoving=false; return; } RefreshBoard(BNr); // HighlightMove(BNr,MvCount[BNr]); isMoving=false; } function MoveForward(BNr,nn) { // moves nn Halve Moves forward, max until end of moves var ii, ffst=0, llst, ssearch, ssub, ffull, mmove0="", mmove1=""; isMoving=true; var GameNr = GetActiveGame(BNr); ffull=Uncomment(PgnMoveText[GameNr]); for (ii=0; (ii=0)&&(MvCount[BNr]=0) { ffst+=ssearch.length; if (llst<0) ssub=ffull.substring(ffst); else ssub=ffull.substring(ffst, llst); mmove0=GetMove(ssub,MvTyp[BNr]); if (mmove0!="") { if (ParseMove(BNr, mmove0)>0) { mmove1=mmove0; MvCount[BNr]++; MvTyp[BNr]=1-MvTyp[BNr]; } else { if (MvTyp[BNr]==1) { ssub=Math.floor(MvCount[BNr]/2+1); ssearch=ssub+"...."; ffst=ffull.indexOf(ssearch); if (ffst<0) { ssearch=ssub+". ..."; ffst=ffull.indexOf(ssearch); } if (ffst<0) { ssearch=ssub+". .."; ffst=ffull.indexOf(ssearch); } if (ffst<0) { ssearch=ssub+" ..."; ffst=ffull.indexOf(ssearch); } if (ffst<0) { ssearch=ssub+"..."; ffst=ffull.indexOf(ssearch); } if (ffst<0) { ssearch=ssub+" .."; ffst=ffull.indexOf(ssearch); } if (ffst>=0) { ffst+=ssearch.length; if (llst<0) ssub=ffull.substring(ffst); else ssub=ffull.substring(ffst, llst); mmove0=GetMove(ssub,0); if (mmove0!="") { if (ParseMove(BNr, mmove0)>0) { mmove1=mmove0; MvCount[BNr]++; MvTyp[BNr]=1-MvTyp[BNr]; } else ffst=-1; } } } else ffst=-1; } } else ffst=-1; } } if (isCalculating) { isMoving=false; return; } RefreshBoard(BNr); // HighlightMove(BNr, MvCount[BNr]); isMoving=false; } function SetImg(BNr, ii,src) { // copies images located in 'img' to document.images[ii], takes care of IE5.5/6.0 issues var i = 'i'+BNr+'-'+ii; with (document) { // FJ, 20160724: nach oben verschoben if (!getElementById(i)) return; if (getElementById(i).src == src) { if ((isIE > 0) && (isIE < 7.0)) getElementById(i).style.filter = ""; return; } if (isIE==0) { getElementById(i).src = src; return }; // use AlphaImageLoader filter for IE 6.0 and IE5.5,as it cannot handle pgn transparency ! getElementById(i).style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + src + "', sizingMethod='scale')"; getElementById(i).src = gImagePath+gPics[0]; } } function RefreshBoard(BNr) { // updates graphics from array var ii=0, jj=0, kk,ll, mm, isRotated = GetIsRotated(BNr); WriteInfos(BNr, isRotated); // write all infos such as player, time and board annotation for (ii=0; ii<8; ii++) { // Update all fields according to the Brd variable. for (jj=0; jj<8; jj++) { if (isRotated) kk= 63-ii-(7-jj)*8; else kk = ii+(7-jj)*8 ; ll=Brd[BNr][ii][jj]; if (ll < 0) mm='b'; else { if (ll == 0 ) mm = ''; else mm='w'; }; SetImg(BNr,kk, gImagePath+mm+gPics[Math.abs(ll)]); } } if (IsLive[BNr]==1) { // 15.8.11 this replaces old ScrollIntoView var sdiv = document.getElementById('pgn-'+BNr); // this replaces old ScrollIntoView // FJ, 20160724 if ( sdiv ) { sdiv.scrollTop = sdiv.scrollHeight; // this replaces old ScrollIntoView } } HighlightMove(BNr,MvCount[BNr]); } function InitBoard(BNr) { // initializes the board variables var cc, ii, jj; for (ii=0; ii<2; ii++) { Piece[BNr][ii] = Array(0, 1, 2, 2, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5) PosX[BNr][ii] = Array(4, 3, 0, 7, 2, 5, 1, 6, 0, 1, 2, 3, 4, 5, 6, 7); PMovs[BNr][ii] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } PosY[BNr][0] = Array(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1); PosY[BNr][1] = Array(7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6); for (ii=0; ii<8; ii++) { for (jj=0; jj<8; jj++) Brd[BNr][ii][jj]=0; } for (ii=0; ii<2; ii++) { for (jj=0; jj<16; jj++) Brd[BNr][PosX[BNr][ii][jj]][PosY[BNr][ii][jj]]=(Piece[BNr][ii][jj]+1)*(1-2*ii); } MvCount[BNr]=0; MvTyp[BNr]=0; } function Init(BNr) { // initializes board variables, refreshes board and highlights move isInit=true; InitBoard(BNr); RefreshBoard(BNr); // while (HTime[BNr].length > 0 ) HTime[BNr].pop(); isInit=false; } function Uncomment(ss) { // strips a pgn game string off the comments {} and $ if (! ss) return(""); var ii, jj, llist=ss.split("{"), ll=llist.length, uu=llist[0], lla, llalen, kk, level=0; // first extract all {} comments for (ii=1; ii 0 )) uu+=lla[lla_len]; } // if (level != 0) DispError('Unbalanced brackets \{\}:'+level); // then extract all line comments beginning with $ llist=uu.split("$"); ll=llist.length; uu=llist[0]; for (ii=1; ii/g,''); txt=txt.replace(/\<\/html\>/g,''); txt=txt.replace(/\/g,''); txt=txt.replace(/\<\/head\>/g,''); txt=txt.replace(/\/g,''); txt=txt.replace(/\<\/body\>/g,''); txt=txt.replace(/\/g,''); txt=txt.replace(/\<\/pre\>/g,''); txt=txt.replace(/\/g,''); txt=txt.replace(/\
/g,''); //
txt=txt.replace(/\/g,''); //
txt=txt.replace(/\<\/xmp\>/g,''); txt=txt.replace(/"/g,'"'); txt=txt.replace(/</g,'<'); txt=txt.replace(/>/g,'>'); txt=" "+txt; return(txt); } function ApplySAN(ss) { // applies SAN from possible SAN tags in the pgn file if (ss.length != 6) return; for (var ii=0; ii<6; ii++) PieceCode[ii]=ss.charCodeAt(ii); } function GetMove(tt,nn) { // Cleans move var ii=0, jj=0, mm="", ll=-1, cc, ss=tt; while (ss.indexOf("
") > 0) ss=ss.replace("
",""); var len=ss.length; while ( ii < len) { cc=ss.charCodeAt(ii); if ((cc<=32)) { //||(cc==46)) //||(cc>=127)) if (ll+1!=ii) jj++; ll=ii; } else { if (jj==nn) { if ((cc==46)&&(!isNaN(mm))) { mm=""; ll=ii; } else mm+=ss.charAt(ii); } } ii++; } if ((nn==1)&&(mm=="")&&(ss.charAt(0)==".")) { ii=0; while (ii"); ll=0; while ((ii>=0)&&(jj>=0)&&(ii"); } } return(mm); } function CanCastleLong(BNr) { // check if O-O-O is allowed var bw = MvTyp[BNr]; if (PMovs[BNr][bw][0]>0) return(-1); var jj=0; while (jj<16) { if ((PosX[BNr][bw][jj]2) ff=2; while ((ff0) return(-1); var jj=0; while (jj<16) { if ((PosX[BNr][bw][jj]>PosX[BNr][bw][0])&& (PosY[BNr][bw][jj]==bw*7)&& (Piece[BNr][bw][jj]==2)&& (PMovs[BNr][bw][jj]==0)) jj+=100; else jj++; } if (jj==16) return(-1); jj-=100; Brd[BNr][PosX[BNr][bw][0]][bw*7]=0; Brd[BNr][PosX[BNr][bw][jj]][bw*7]=0; var ff=PosX[BNr][bw][jj]; if (ff<6) ff=6; while ((ff>PosX[BNr][bw][0])||(ff>=5)) { if (Brd[BNr][ff][bw*7]!=0) { Brd[BNr][PosX[BNr][bw][0]][bw*7]=1-2*bw; Brd[BNr][PosX[BNr][bw][jj]][bw*7]=(1-2*bw)*3; return(-1); } ff--; } Brd[BNr][PosX[BNr][bw][0]][bw*7]=1-2*bw; Brd[BNr][PosX[BNr][bw][jj]][bw*7]=(1-2*bw)*3; return(jj); } function IsInComment(ss, nn) { // checks if string is in comment var ii=-1, bb=0; do { ii=ss.indexOf("{",ii+1); bb++; } while ((ii>=0)&&(ii=0)&&(ii Txe3) if (ss=="") return(""); if ((ShowPieceName=="")||(ShowPieceName==PieceName)) return(ss); var jj, rr, tt=""; for (jj=0; jj=0) tt+=ShowPieceName.charAt(rr); else tt+=ss.charAt(jj); } return(tt); } function SetMove(BNr, mmove) { // sets moves position to a given move either forward or back SetLiveButton(BNr,0); if (isNaN(mmove)) return; var dd=mmove-MvCount[BNr]; if (dd<=0) MoveBack(BNr, -dd); else MoveForward(BNr, dd); } function GetTimeInPGN(BNr, ss,Mv) { // analyzes comments and extracts time tag if n:nn:nn format if (!ss) return(ss); var i,j, Comm; // if (! HTime[BNr][Mv] ) HTime[BNr][Mv] = " "; // presume no time tag existing for this move j=ss.indexOf("*"); //consider only comments up to the next move if (j > 0) Comm = ss.substring(0,j); else Comm=ss; j = Comm.indexOf("."); if (j>0) Comm=Comm.substring(0,j); i = Comm.indexOf("{"); if (i < 0) return(ss); j = Comm.indexOf("}"); if (j < 0) return(ss); Comm = Comm.substring(i+1,j); if (Comm.match(/[0-9]:[0-9][0-9]:[0-9][0-9]/) ) { if (Mv == 'ActTime') { Tags[GetActiveGame(BNr)]['ActTime']=Comm; return; } else if (Mv < 0 ) return; HTime[BNr][Mv] = Comm; if (ShowTimeInPGN) return(ss.substring(0,i)+" "+Comm+" "+ss.substring(j+1)); else return(ss.substring(0,i)+ss.substring(j+1)); } else return(""+ss+""); } function GetGameResult(BNr,ss,Mv) { // analyzes the result tag in the pgn file if (!ss) return(ss); var t = new Array(2); t=ss.split("1/2-1/2"); if (t.length > 1) { Tags[BNr]["Result"]="1/2-1/2"; return(t[0]+"
1/2 - 1/2
"); } t=ss.split("1-0"); if (t.length > 1) { Tags[BNr]["Result"]="1-0"; return(t[0]+"
1 - 0
"); } t=ss.split("0-1"); if (t.length > 1) { Tags[BNr]["Result"]="0-1"; return(t[0]+"
0 - 1
"); } t=ss.split("*"); if (t.length > 1) { if (t[1].indexOf(":") > 0) { GetTimeInPGN(BNr,t[1],'ActTime'); } return(t[0]+"
...
"); } return("{Parsing Error when trying to determine the game result}"); // ss); } function HighlightMove(BNr,Mv) { // highlights last move var obj, bg, last_mv, anch;; if (! document.getElementById) return; obj = document.getElementById('HlightMv'+BNr); if (obj) bg = obj.style.background; bg = 'silver'; // seems to be buggy ! if (obj) { last_mv=obj.value; obj.value=Mv; } else last_mv=""; anch='m-'+BNr+'-'+last_mv; with (document) { if (( last_mv >= 0) && (getElementById(anch)) ) { obj=getElementById(anch); obj.style.background=""; obj.style.borderWidth='0px'; obj.style.borderStyle='none'; } anch='m-'+BNr+'-'+Mv; if ( getElementById(anch) ) { obj=getElementById(anch); obj.style.background=bg; obj.style.borderWidth='1px'; obj.style.borderStyle='none'; } } } function GetHTMLMoveText(BNr) { // extracts moves out of pgn and cnoverts pgn to HTML format including links var MvTxt, GameNr, Mv, jj, uu="", uuu="", cc, vvariant=0; bb=0, bbb=0, ccommenttype=true; var ss="", sstart=0, ffst=0,llst,ssearch,ssub,ffull,mmove0="",mmove1="",MvCnt=MvCount[BNr]; isCalculating=true; Init(BNr); GameNr = GetActiveGame(BNr); MvTxt=PgnMoveText[GameNr]; ffull=Uncomment(MvTxt); // Strip all comments off for (var ii=0; (ii=0)&&(MvCount[BNr]=0) { // if there is a low move count ffst+=ssearch.length; if (llst<0) ssub=ffull.substring(ffst); else ssub=ffull.substring(ffst, llst); // cut the move out mmove0=GetMove(ssub,MvTyp[BNr]); // get Move Clean and only black or white if ((mmove0!="") && (ParseMove(BNr, mmove0)>0)) { // Build HistMove Array mmove1=mmove0; MvCount[BNr]++; MvTyp[BNr]=1-MvTyp[BNr]; } else ffst=-1; } // end if ffst>=0 if (mmove1!="") { sstart=-1; do sstart=MvTxt.indexOf(mmove1, sstart+1); while ((sstart>0)&&(IsInComment(MvTxt, sstart))); if (sstart>=0) { Mv=MvCount[BNr] ss+=GetTimeInPGN(BNr, MvTxt.substr(0,sstart),(Mv-2)); ss+=""; ss+=""+TransformSAN(mmove1)+""; if ( (MvTyp[BNr]==0) && (OneMovePerLine)) { ss+="
"; }; // insert new line MvTxt=MvTxt.substr(sstart+mmove1.length); } else ffst=-1; } else { MvTxt=GetTimeInPGN(BNr, MvTxt,(MvCount[BNr]-1)); MvTxt=GetGameResult(BNr,MvTxt,(MvCount[BNr]-1)); } } ss+=MvTxt; uu = MarkAllComments(ss); // set all comments to "grey" LastMove[BNr]=MvCount[BNr]; // store maximum move for usage in MoveForward isCalculating=false; // if islive then go to the end of the game if (IsLive[BNr]==1) MoveForward(BNr, MaxMove); else SetMove(BNr, MvCnt); return(uu); } function MarkAllComments(ss) { // sets all all comments to .. var MvTxt=ss.split("{"), ll=MvTxt.length, uu, ii; uu=MvTxt[0]; for (ii=1; ii=0)&&(x1<=7)&&(y1>=0)&&(y1<=7)) return(-1); // if no valid number check for castling if ((Mv.indexOf("O")>=0)||(Mv.indexOf("0")>=0)) { if ((Mv.indexOf("O-O-O")>=0)||(Mv.indexOf("0-0-0")>=0)||(Mv.indexOf("O-O-O")>=0)||(Mv.indexOf("0-0-0")>=0)) { if (EvalMove(BNr, -1 , 6, -1, -1, -1, x1, y1, 0, -1)) return(1); return(0); } if ((Mv.indexOf("O-O")>=0)||(Mv.indexOf("0-0")>=0)||(Mv.indexOf("O?O")>=0)||(Mv.indexOf("0?0")>=0)) { if (EvalMove(BNr, -1 , 7, -1, -1, -1, x1, y1, 0, -1)) return(1); return(0); } return(0); } if ((Mv.indexOf("---")>=0)||(Mv.indexOf("???")>=0)) { // Null-Move //if (Mv.indexOf("...")>=0) //is buggy if (EvalMove(BNr, -1 , 8, -1, -1, -1, x1, y1, 0, -1)) return(1); return(0); } return(0); } function ParseMove(BNr, Mv) { // parses a given move and extracts fields var ii, jj, ffrom="", ccapt=0, ll, Fig=Pawn, x0=-1, y0=-1, Fig2=-1, x1=-1, y1=-1; var rMv=MvCount[BNr]-1, bw = MvTyp[BNr], CanPass=-1; // find last valid field target field such as d4 ii=Mv.length-1; while (ii>0) { if (! isNaN(Mv.charAt(ii))) { x1=Mv.charCodeAt(ii-1)-97; y1=Mv.charAt(ii)-1; ffrom=Mv.substring(0, ii-1); jj=ii; break; } ii--; } // scan from the end until a number occurs // check for Castling and NullMoves ii = Check4Castling(BNr,Mv,x1,y1); if (ii >= 0) return(ii); ll=ffrom.length-1; // find piece (KQRBNP) at Position 0, Fig is initialized with Pawn if (ll>=0) { for (ii=0; ii<5; ii++) { if (ffrom.charCodeAt(0)==PieceCode[ii]) { Fig=ii; ffrom=ffrom.slice(1); ll--; } } } // check for capturing, last part for Smith Notation if (ll>=0) { if (ffrom.charAt(ll)=="x") { ccapt=1; ll--; } else { if ((ffrom.charAt(ll)=="-")||(ffrom.charAt(ll)=="?")) ll--;} } // get source field y such as R3xe8 if (ll>=0) { if (! isNaN(ffrom.charAt(ll))) { y0=ffrom.charAt(ll)-1; if ((y0<0)||(y0>7)) y0=-1; ll--; } } // get source field x such as Rexe8 if (ll>=0) { if (isNaN(ffrom.charAt(ll))) { x0=ffrom.charCodeAt(ll)-97; if ((x0<0)||(x0>7)) x0=-1; ll--; } } // check if pieces are captured, take care for En-Passent if (rMv >= 0 ) { ii=HPiece[BNr][0][rMv]; if ((HTyp[BNr][0][rMv]==Pawn)&&(Math.abs(HPosY[BNr][0][rMv]-PosY[BNr][1-bw][ii])==2)) CanPass=PosX[BNr][1-bw][ii]; } if (Brd[BNr][x1][y1] != 0) ccapt=1; else { if ((Fig==5)&&(x1==CanPass)&&(y1==5-3*bw)) ccapt=1; } // check for promotion such a e8=Q or e8Qc, accept only valid piece codes Fig2=Fig; ii=Mv.indexOf("="); if (ii>0) jj=ii; if ((jj>0)&& (jj < Mv.length-1)) { if (Fig==Pawn) { ii=Mv.charCodeAt(jj+1); for (ll=1;ll<5;ll++) { if (ii==PieceCode[ll]) Fig2=ll; } } } // Now check Moves for all 16 pieces, if there is a match for (ii=0; ii<16; ii++) { if (Piece[BNr][bw][ii]==Fig) { if (EvalMove(BNr, ii, Fig, x0, y0, Fig2, x1, y1, ccapt, CanPass)) return(1); } } return(0); } function EvalMove(BNr, ii, Fig, x0, y0, Fig2, x1, y1, ccapt, CanPass) { // evaluates parsed move, checks for validity var dx, dy, xx, yy, jj=-1, Fig_prom=-1; var bw = MvTyp[BNr], Xii=PosX[BNr][bw][ii], Yii=PosY[BNr][bw][ii]; var BRD=Brd[BNr], X=PosX[BNr][bw], Y=PosY[BNr][bw]; //O-O-O with Chess960 rules if (Fig==OOO) { jj=CanCastleLong(BNr); if (jj<0) return(false); if (StoreMove(BNr, 0, 0, 2, bw*7, jj, 2, 3, bw*7)) return(true); return(false); } //O-O with Chess960 rules if (Fig==OO) { jj=CanCastleShort(BNr); if (jj<0) return(false); if (StoreMove(BNr, 0, 0, 6, bw*7, jj, 2, 5, bw*7)) return(true); return(false); } // --- NullMove if (Fig==NullM) { if (StoreMove(BNr, 0, 0,PosX[BNr][bw][0], PosY[BNr][bw][0], -1, -1, -1, -1)) return(true); return(false); } if ((Xii==x1)&&(Yii==y1)) return(false); // No move at all // Check if captured pieces from opponent's color, and check for EnPassent if not ? if ((ccapt>0)&&(sign(BRD[x1][y1])!=(2*bw-1))) { if ((Fig!=Pawn)||(CanPass!=x1)||(y1!=5-3*bw)) return(false); } // wrong starting field X or Y if ( ((x0>=0)&&(x0!=Xii)) || ((y0>=0)&&(y0!=Yii)) ) return(false); // Valid Move for King ? if (Fig==King) { if ( (Math.abs(Xii-x1)>1) || (Math.abs(Yii-y1)>1) ) return(false); } // Valid Move for Queen? if (Fig==Queen) { if ( ((Math.abs(Xii-x1)!= Math.abs(Yii-y1))) && ((Xii-x1)*(Yii-y1)!=0)) return(false); } // Valid Move for Rook? if (Fig==Rook) { if ((Xii-x1)*(Yii-y1)!=0) return(false); } // Valid Move for Bishop? if (Fig==Bishop) { if (Math.abs(Xii-x1)!=Math.abs(Yii-y1)) return(false); } // Valid Move for Bishop? if (Fig==Night) { if (Math.abs(Xii-x1)*Math.abs(Yii-y1)!=2) return(false); } // There must not be any other piecee between start- and end position if ((Fig==Queen)||(Fig==Rook)||(Fig==Bishop)) { dx=sign(x1-Xii); dy=sign(y1-Yii); xx=Xii+dx; yy=Yii+dy; while ((xx!=x1)||(yy!=y1)) { if (BRD[xx][yy]!=0) return(false); xx+=dx; yy+=dy; } } // Valid Move for Pawn? if (Fig==Pawn) { if ( (Math.abs(Xii-x1) != ccapt) || ((y1==7*(1-bw))&&(Fig==Fig2)) ) return(false); // X=0 or +-1 if captured if (ccapt==0) { if (Yii-y1==4*bw-2) { // is it a two step pawn move if (Yii!=1+5*bw) return(false); // must come from initial position if (BRD[x1][y1+2*bw-1]!=0) return(false); // field in between is not empty } else {if (Yii-y1!=2*bw-1) return(false); } // must move exactly one field } else { if (Yii-y1!=2*bw-1) return(false); } // for captured exactly one step forward } // Check for valid Promotion if (Fig2!=Fig) { if ((Fig!=Pawn) || (Fig2>=Pawn) || (y1!=7-7*bw)) return(false); } // get opponents captured piece (only index is relevant) if ((Fig<=Pawn)&&(ccapt>0)) { jj=15; var wb = 1-bw; while (jj>=0) { if ((Piece[BNr][wb][jj]>0)&& (PosX[BNr][wb][jj]==x1)&& (PosY[BNr][wb][jj]==y1)) { Fig_prom=Piece[BNr][wb][jj]; break; } else jj--; } // if no piece then it must be en-passent if ((Fig_prom==-1)&&(Fig==Pawn)&&(CanPass>=0)) { jj=15; while (jj>=0) { if ((Piece[BNr][wb][jj]==5)&&(PosX[BNr][wb][jj]==x1)&&(PosY[BNr][wb][jj]==y1-1+2*bw)) { Fig_prom=Piece[BNr][wb][jj]; break; } else jj--; } } Fig_prom=-1; } // now move is correct, so store it if ( StoreMove(BNr, ii, Fig2, x1, y1, jj, Fig_prom, -1, -1) ) return(true); return(false); } function Save2Hist(BNr,Mv,bw,ind,ii,Adder) { // save Piece and Position to MoveHistory, used in StoreMove HPiece[BNr][ind][Mv] = ii+Adder; HTyp[BNr][ind][Mv] = Piece[BNr][bw][ii]; HPosX[BNr][ind][Mv] = PosX[BNr][bw][ii]; HPosY[BNr][ind][Mv] = PosY[BNr][bw][ii]; } function SetField2Val(BNr,bw,ind,val) { // sets Piece(val) on field(ind) Brd[BNr][PosX[BNr][bw][ind]][PosY[BNr][bw][ind]]=val; } function StoreMove(BNr, ii, Fig, x2, y2, jj, Fig2, x3, y3) { // stor2es move and sets the board position var iis_check=0, ll, Mv=MvCount[BNr], dd=0; var bw = MvTyp[BNr], wb=1-bw; // save Primary history HPiece[BNr][1][Mv] = -1; // preset ext. moves to null Save2Hist(BNr,Mv,bw,0,ii,0); SetField2Val(BNr,bw,ii,0); // increase #of Moves for each piece (can later on check for illegal castling if ((PosX[BNr][bw][ii]!=x2)||(PosY[BNr][bw][ii]!=y2)||(jj>=0)) { PMovs[BNr][bw][ii]++; dd++; } //not a nullmove // set additional history whenever 2 pieces are involved such as 0-0, or exd4 if (jj>=0) { if (Fig2 < 0 ) { Save2Hist(BNr,Mv,1-bw,1,jj,16); SetField2Val(BNr,1-bw,jj,0) Piece[BNr][1-bw][jj]=Fig2; PMovs[BNr][1-bw][jj]++; SetField2Val(BNr,1-bw,jj,0); } else { Save2Hist(BNr,Mv,bw,1,jj,0); SetField2Val(BNr,bw,jj,0) PosX[BNr][bw][jj]=x3; PosY[BNr][bw][jj]=y3; PMovs[BNr][bw][jj]++; SetField2Val( BNr, bw, jj, (Piece[BNr][bw][jj]+1)*(1-2*bw) ); } } // set new Piece and position Piece[BNr][bw][ii]=Fig; PosX[BNr][bw][ii]=x2; PosY[BNr][bw][ii]=y2; SetField2Val(BNr,bw,ii,(Fig+1)*(1-2*bw)); //O-O-O, O-O if ((Fig==King)&&(Fig2==Rook)) { while (PosX[BNr][bw][King]>x2) { iis_check+=IsCheck(BNr, PosX[BNr][bw][King], bw*7, bw); PosX[BNr][bw][King]--; } while (PosX[BNr][bw][King]=0) { if (Fig2>=0) { Brd[BNr][PosX[BNr][bw][jj]][PosY[BNr][bw][jj]]=0; Brd[BNr][HPosX[BNr][0][Mv]][HPosY[BNr][0][Mv]]=(HTyp[BNr][0][Mv]+1)*(1-2*bw); Brd[BNr][HPosX[BNr][1][Mv]][HPosY[BNr][1][Mv]]=(HTyp[BNr][1][Mv]+1)*(1-2*bw); Piece[BNr][bw][jj]=HTyp[BNr][1][Mv]; PosX[BNr][bw][jj]=HPosX[BNr][1][Mv]; PosY[BNr][jj]=HPosY[BNr][1][Mv]; PMovs[BNr][bw][jj]--; } else { Brd[BNr][HPosX[BNr][1][Mv]][HPosY[BNr][1][Mv]]=(HTyp[BNr][1][Mv]+1)*(2*bw-1); Piece[BNr][wb][jj]=HTyp[BNr][1][Mv]; PosX[BNr][wb][jj]=HPosX[BNr][1][Mv]; PosY[BNr][wb][jj]=HPosY[BNr][1][Mv]; PMovs[BNr][wb][jj]--; } } if (iis_check==0) return(true); return(false); } function IsCheck(BNr, xx, yy, bw) { // checks if king is in check by any of the opponent's pieces var x0=xx, y0=yy, dx, dy, bb; // Night check for (dx=-2; dx<=2; dx+=4) { for (dy=-1; dy<=1; dy+=2) { if (IsOnBoard(x0+dx, y0+dy)) { if (Brd[BNr][x0+dx][y0+dy]==10*bw-(Night+1)) return(1); } } } for (dx=-1; dx<=1; dx+=2) { for (dy=-2; dy<=2; dy+=4) { if (IsOnBoard(x0+dx, y0+dy)) { if (Brd[BNr][x0+dx][y0+dy]==10*bw-(Night+1)) return(1); } } } // Pawn Check dy=1-2*bw; for (dx=-1; dx<=1; dx+=2) { if (IsOnBoard(x0+dx, y0+dy)) { if (Brd[BNr][x0+dx][y0+dy]==12*bw-(Pawn+1)) return(1); } } // not next to opponents king if ((Math.abs(PosX[BNr][1-bw][King]-xx)<2)&&(Math.abs(PosY[BNr][1-bw][King]-yy)<2)) return(1); // check for Queen, Rook, Bishop for (dx=-1; dx<=1; dx++) { for (dy=-1; dy<=1; dy++) { if ((dx!=0)||(dy!=0)) { x0=xx+dx; y0=yy+dy; bb=0; while ((IsOnBoard(x0, y0))&&(bb==0)) { bb=Brd[BNr][x0][y0]; if (bb==0) { x0+=dx; y0+=dy; } else { if ( bb==4*bw-(Queen+1)) return(1); if ((bb==6*bw-(Rook+1))&&((dx==0)||(dy==0))) return(1); if ((bb==8*bw-(Bishop+1))&&(dx!=0)&&(dy!=0)) return(1); } } } } } return(0); } function IsOnBoard(ii, jj) { // checks if field is on board (0-7) if ( (ii<0) || (ii>7) || (jj<0) || (jj>7)) return(false); return(true); } function OpenGames() { // opens all Games after file update for (var BNr = 0; BNr < (Rows*Cols); BNr++) { var sel = GetActiveGame(BNr); if ( BNr >= PgnMoveText.length) break; Tags[BNr]=Tags[sel]; // assign Tags to the Board; OpenGame(BNr,sel); } WriteCookie(); } function OpenGame(BNr,GameNr) { // Opens active game after Viewer Update // check if valid game and already fully loaded if (isMoving) { setTimeout('OpenGame('+BNr+','+GameNr+')',TimeOut); return; } if (GameNr < 0) return; if (Tags[GameNr]["SAN"]) ApplySAN(Tags[GameNr]["SAN"]); // change nameing of the pieces if there is such a string in the pgn file WriteCookie(); with (document) { // FJ, 20160724 if (getElementById('pgn-'+BNr)) { getElementById('pgn-'+BNr).innerHTML=GetHTMLMoveText(BNr); //pgn with html links; if ( Tags[GameNr]["Result"] !="*") getElementById('Result-'+BNr).innerHTML = Tags[GameNr]["Result"].substr(0,3); else getElementById('Result-'+BNr).innerHTML = "..."; } } RefreshBoard(BNr) } function UpdateViewer() { // Handles Viewer Update after new pgn file is read - called from AnalyzePgn SkipRefresh=1; // no refresh during update WriteSelGames(); // write all games for all boards into the