{"pages":{"start":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230491"}},{"eval":{"script":"loadedImage = true\r\nimageNum = 0"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Which Browser are you using?<\/span><\/p>","mode":"instant"}},{"choice":{"options":[{"label":"Chrome","commands":[{"eval":{"script":"game.setBrowser('chrome')"}}]},{"label":"Firefox","commands":[{"eval":{"script":"game.setBrowser('firefox')"}}]},{"label":"Safari","commands":[{"eval":{"script":"game.setBrowser('safari')"}}]},{"label":"Other","commands":[{"choice":{"options":[{"label":"Tor","commands":[{"eval":{"script":"game.setBrowser('tor')"}}]},{"label":"Other","commands":[{"eval":{"script":"game.setBrowser('chrome')"}}]}]}},{"say":{"label":"<p>NOTE:  Queen&#39;s Gambit is incomplete and has only been validated on Chrome and Firefox<\/p><p>Things may not work or look as they should<\/p>","mode":"pause"}}]}]}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">What kind of thingy are you using?<\/span><\/p>","mode":"instant"}},{"choice":{"options":[{"label":"Windows","commands":[{"eval":{"script":"game.setOs('win')"}},{"say":{"label":"<p>HINT:  If things are too small or too big, you can press ctrl+ or ctrl- to enlarge or shrink.  Full-screen, \u26f6, is recommended.<\/p>","mode":"pause"}}],"visible":"$game.browser !== 'safari'"},{"label":"Android","commands":[{"eval":{"script":"game.setOs('and')"}},{"say":{"label":"<p>NOTE:  Queen&#39;s Gambit is incomplete and has not been validated on Android.<\/p><p>Things may not work or look as they should<\/p>","mode":"pause"}}],"visible":"$game.browser !== 'safari'"},{"label":"iPhone\/iPad\/iOS","commands":[{"eval":{"script":"game.setOs('ios')"}},{"say":{"label":"<p>NOTE:  Queen&#39;s Gambit is incomplete and has not been validated on iOS.<\/p><p>Things may not work or look as they should<\/p>","mode":"pause"}}]},{"label":"Mac","commands":[{"eval":{"script":"game.setOs('osx')"}},{"say":{"label":"<p>NOTE:  Queen&#39;s Gambit is incomplete and has not been validated on a mac.<\/p><p>Things may not work or look as they should<\/p>","mode":"pause"}}]},{"label":"Other","commands":[{"eval":{"script":"game.setOs('win')"}},{"say":{"label":"<p>NOTE:  Queen&#39;s Gambit is incomplete and has only been validated on Windows<\/p><p>Things may not work or look as they should<\/p>","mode":"pause"}}]}]}},{"if":{"condition":"teaseStorage.getItem('ps')","commands":[{"say":{"label":"<p><span style=\"color: #f48fb1\">Looks like we didn&#39;t finish our last game.  Would you like to continue?<\/span><\/p>","mode":"instant"}},{"choice":{"options":[{"label":"Yes!","commands":[{"eval":{"script":"game.setPlayState(teaseStorage.getItem('ps'))\r\nloadedImage = false"}},{"if":{"condition":"game.computerCapture.length >= 3","commands":[{"say":{"label":"<p><span style=\"color: #f48fb1\">Okay. Make sure your pants are pulled all the way down.<\/span><\/p>","mode":"pause"}}]}},{"noop":{"if":{"condition":"game.computerCapture.length == 1","commands":[{"say":{"label":"<p><span style=\"color: #f48fb1\">Okay. Make sure your pants pulled up, but down just enough so I see what I&#39;m working with.<\/span><\/p>","mode":"pause"}}]}}},{"if":{"condition":"game.computerCapture.length == 0","commands":[{"say":{"label":"<p><span style=\"color: #f48fb1\">Okay. Make sure your pants pulled all the way up.<\/span><\/p>","mode":"pause"}}]}},{"timer":{"duration":"0.2s","style":"hidden"}},{"goto":{"target":"--play-move"}}]},{"label":"No, start over.","commands":[{"eval":{"script":"teaseStorage.removeItem('ps')"}}]}]}}]}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">How smart do you want me to be?<\/span><\/p><p><span style=\"color: #f8bbd0\">(The smarter I am, the longer I take to think about things.)<\/span><\/p>","mode":"instant"}},{"choice":{"options":[{"label":"Foolish","commands":[{"eval":{"script":"game.computer_level = 0"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Really?  You want me to act that dumb?<\/span><\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Okay, whatever you say.<\/span><\/p>","mode":"pause"}}]},{"label":"Not Very","commands":[{"eval":{"script":"game.computer_level = 1"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">You must not be very good at this.<\/span><\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Fine, I&#39;ll try to do the best I can but as fast as I can.<\/span><\/p>","mode":"pause"}}]},{"label":"A little","commands":[{"eval":{"script":"game.computer_level = 2"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Okay, I&#39;ll try to beat you but not hold you up too long.<\/span><\/p>","mode":"pause"}}],"color":"#0d47a1"},{"label":"Very","commands":[{"eval":{"script":"game.computer_level = 3"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Alright, I&#39;ll try my best to beat you.<\/span><\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Don&#39;t be upset if I take a minute or two to plan my moves.<\/span><\/p>","mode":"pause"}}]},{"label":"Super (Very, very slow)","commands":[{"eval":{"script":"game.computer_level = 4"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">I&#39;ll take as long as I need to beat you.  Don&#39;t be upset if I take several minutes to plan my moves.<\/span><\/p>","mode":"pause"}}],"visible":"$false"}]}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Now make sure you have your pants on to start.<\/span><\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Don&#39;t touch yourself unless I say you can.<\/span><\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p><span style=\"color: #f8bbd0\"> And absolutely don&#39;t cum until you&#39;re told!<\/span><\/p>","mode":"instant"}},{"choice":{"options":[{"label":"I understand","commands":[]}]}},{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2267597"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Before we start we need to decide who goes first.<\/span><\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Choose my left or right hand.  If it&#39;s a white pawn, you go first.<\/span><\/p>","mode":"autoplay","allowSkip":true}},{"choice":{"options":[{"label":"Left","commands":[]},{"label":"Right","commands":[]}]}},{"if":{"condition":"Math.floor(Math.random() * 2) == 0","commands":[{"say":{"label":"<p><span style=\"color: #f8bbd0\">Black pawn. I go first!<\/span><\/p>","mode":"pause"}},{"eval":{"script":"game.setComputerFirst()"}}],"elseCommands":[{"say":{"label":"<p><span style=\"color: #f8bbd0\">White pawn.  You go first!<\/span><\/p>","mode":"pause"}}]}},{"timer":{"duration":"0.2s","style":"hidden"}},{"goto":{"target":"--play-move"}}],"--play-move":[{"if":{"condition":"!loadedImage","commands":[{"goto":{"target":"--util-image"}}]}},{"eval":{"script":"\/\/ Reset trackers\r\nconsole.warn(\"Starting --play-move\")\r\n_didCapture = false\r\n_didCheck = false"}},{"eval":{"script":"\/\/ Save position\r\nconsole.log('Fen:',game.getFen())\r\nconsole.log('State:',game.board_state)\r\nconsole.log('Last Move', game.lastMove)\r\nconsole.log('Player Capture', game.playerCapture)\r\nconsole.log('Computer Capture', game.computerCapture)\r\n\r\nteaseStorage.setItem('ps', game.getPlayState())\r\n"}},{"if":{"condition":"game.lastCheckedMove !== game.lastMove","commands":[{"eval":{"script":"console.warn(\"Doing last move check\")"}},{"goto":{"target":"--play-move-check"}}]}},{"eval":{"script":"\/\/ Config prompts\r\n\/\/ TODO - merge most logic below into P4WN prototype\r\nvar _pRows = game.rowPrompts()\r\nvar _pCols = game.colPrompts()\r\nvar _pRowKeys = Object.keys(_pRows||[])\r\nvar _pColKeys = Object.keys(_pCols||[])\r\nvar _setCol = undefined\r\nvar autoMoveMessage = (true \/*  game.isAutoTargetCol && game.isAutoTargetRow*\/)\r\n  ? [\"Only one option,\",\"moving for you...\"]\r\n  : [\"Making move...\"]\r\nvar _setRow = undefined\r\nvar _preRender = game.renderBoard({prompt: autoMoveMessage})\r\n\r\nvar _promptCols = game.isPlayerTurn() && (!game.hasSourceCol() || \r\n  (game.hasSource() && !game.hasTargetCol()))\r\nvar _promptRows =  game.isPlayerTurn() && !_promptCols && (!game.hasSourceRow() || \r\n  (game.hasSource() && !game.hasTargetRow()))\r\n\r\nvar _promptMessage = []\r\nif (_promptRows) {\r\n  if (game.hasSource()) {\r\n    _promptMessage = [\"Select row to move to\"]\r\n  } else {\r\n    _promptMessage = [\"Select row of piece\",\"to move\"]\r\n  }\r\n} else if (_promptCols) {\r\n  if (game.hasSource()) {\r\n    _promptMessage = [\"Select column to move to\"]\r\n  } else {\r\n    _promptMessage = [\"Select column of piece\",\"to move\"]\r\n  }\r\n}\r\n\/\/ console.log('Rows:', _pRows)\r\n\/\/ console.log('Cols:', _pCols)\r\n\r\n\/\/ console.log('hsr:',game.hasSourceRow(), _pRows, _pRowKeys, _pRowKeys.length)\r\n\/\/ console.log('hsc:',game.hasSourceCol(), _pCols, _pColKeys, _pColKeys.length)\r\n\r\nvar _delayReload = false\r\nif (game.isPlayerTurn()) {\r\n  if (!game.hasSourceRow() && _pRowKeys.length === 1) {\r\n    game.setSource(parseInt(_pRowKeys[0]),undefined)\r\n    console.log('Auto setting source row', parseInt(_pRowKeys[0]))\r\n    pages.goto(pages.getCurrentPageId())\r\n  } else if (!game.hasSourceCol() && _pColKeys.length === 1) {\r\n    console.log('Auto setting source column', parseInt(_pColKeys[0]))\r\n    game.setSource(undefined,parseInt(_pColKeys[0]))\r\n    pages.goto(pages.getCurrentPageId())\r\n  } else if (game.hasSource() && !game.hasTargetRow() && _pRowKeys.length === 1) {\r\n    console.log('Auto setting target row', parseInt(_pRowKeys[0]))\r\n    var isAuto = game.isAutoTargetCol\r\n    if (game.setTarget(parseInt(_pRowKeys[0]),undefined)){\r\n      _delayReload = isAuto\r\n      if (!_delayReload && !game.isPlayerTurn()) {\r\n        _promptMessage = []\r\n      }\r\n      if (!isAuto) pages.goto(pages.getCurrentPageId())\r\n    } else {\r\n      game.isAutoTargetRow = true\r\n      pages.goto(pages.getCurrentPageId())\r\n    }\r\n  } else if (game.hasSource() && !game.hasTargetCol() && _pColKeys.length === 1) {\r\n    console.log('Auto setting target column', parseInt(_pColKeys[0]))\r\n    var isAuto = game.isAutoTargetRow\r\n    if (game.setTarget(undefined,parseInt(_pColKeys[0]))) {\r\n      _delayReload = isAuto\r\n      if (!isAuto) pages.goto(pages.getCurrentPageId())\r\n    } else {\r\n      game.isAutoTargetCol = true\r\n      pages.goto(pages.getCurrentPageId())\r\n    }\r\n  }\r\n}"}},{"if":{"condition":"_delayReload","commands":[{"say":{"label":"<p><eval>_preRender<\/eval><\/p>","mode":"instant"}},{"noop":{"say":{"label":"<p><span style=\"color: #f8bbd0\">Okay, let me move that for you...<\/span><\/p>","mode":"instant"}}},{"if":{"condition":"true \/* game.isAutoTargetCol && game.isAutoTargetRow *\/","commands":[{"timer":{"duration":"3s","style":"hidden"}}],"elseCommands":[{"timer":{"duration":"0.3s","style":"hidden"}}]}},{"goto":{"target":"$pages.getCurrentPageId()"}}]}},{"say":{"label":"<p><eval>game.renderBoard({\n  prompt: _promptMessage,\n})<\/eval><\/p>","mode":"instant"}},{"eval":{"script":"loadedImage = false"}},{"if":{"condition":"!game.isPlayerTurn()","commands":[{"eval":{"script":"pantsOnThingsToSay = [\r\n   \"Rub your bulge for me while I'm thinking...\",\r\n\r\n   \"Keep yourself hard until it's your turn...\",\r\n\r\n   \"Slap your cock gently through your pants until I decide my move...\",\r\n\r\n  \"Stick your hands down your pants and message your cock while you wait...\",\r\n]\r\npantsOffThingsToSay = [\r\n  \"Go ahead and stroke for me while I think about this...\",\r\n\r\n  \"Tickle your balls while I decide...\",\r\n\r\n  \"Message the head of your cock until I finish...\",\r\n\r\n  \"Play with yourself however you like while I think...\",\r\n\r\n]\r\n\r\npantsOffThingsToSay2 = [\r\n\r\n  \"Hurry! Try to edge for me while you wait...\",\r\n\r\n   \"Stroke as fast as you can while I think...\",\r\n\r\n   function(){\r\n     instructNotification = \"\ud83d\udc8b Stroke for me\"\r\n     return \"Stroke for me until my next turn.\"\r\n   },\r\n\r\n]\r\n\r\nlongThinkThingsToSay = [\r\n  \"Don't rush me...\",\r\n  \"Good moves take time...\",\r\n  \"So many moves to choose from...\",\r\n  \"Still thinking...\",\r\n  \"Be patient...\",\r\n  \"I'm almost done...\",\r\n  \"Just wait...\",\r\n  \"Hold on...\",\r\n  \"This could take a moment...\",\r\n  \"Don't worry, I'll choose eventually...\",\r\n  \"I'll get there...\",\r\n  \"Stay calm, I think I've got it...\",\r\n]\r\n\r\nfunction getLongTimeMessage() {\r\n  return longThinkThingsToSay.splice(Math.floor(Math.random()*longThinkThingsToSay.length), 1)\r\n}\r\n\r\nif (game.computerCapture.length >= 4) {\r\n  Array.prototype.push.apply(pantsOffThingsToSay, pantsOffThingsToSay2)\r\n}\r\n\r\nintructNotification = \"\"\r\n\r\nlastThingToSay = window.lastThingToSay || false\r\n\r\nthingsToSay = game.computerCapture.length >= 1 ? pantsOffThingsToSay : pantsOnThingsToSay\r\n\r\nthingToSay = thingsToSay[Math.floor(Math.random()*thingsToSay.length)]\r\nwhile (lastThingToSay === thingToSay && thingsToSay.length >= 2) {\r\n  thingToSay = thingsToSay[Math.floor(Math.random()*thingsToSay.length)]\r\n}\r\nlastThingToSay = thingToSay\r\nif (typeof thingToSay === \"function\") {\r\n  thingToSay = thingToSay()\r\n}"}},{"if":{"condition":"intructNotification","commands":[{"notification.create":{"id":"instruct"}},{"eval":{"script":"Notification.get('instruct').setTitle(intructNotification)"}}],"elseCommands":[{"notification.remove":{"id":"instruct"}}]}},{"say":{"label":"<p><span style=\"color: #f48fb1\"><\/span><span style=\"color: #f48fb1\"><eval>thingToSay<\/eval><\/span><span style=\"color: #f48fb1\"><\/span><\/p>"}},{"timer":{"duration":"0.3s","style":"hidden"}},{"eval":{"script":"endTime = Date.now() + 6000"}},{"if":{"condition":"_cmv = game.computerMove()","commands":[{"say":{"label":"<p><span style=\"color: #f48fb1\"><\/span><span style=\"color: #f48fb1\"><eval>getLongTimeMessage()<\/eval><\/span><span style=\"color: #f48fb1\"><\/span><\/p>","mode":"instant"}},{"timer":{"duration":"$300","style":"hidden"}},{"if":{"condition":"_cmv = game.computerMove(_cmv)","commands":[{"say":{"label":"<p><span style=\"color: #f48fb1\"><\/span><span style=\"color: #f48fb1\"><eval>getLongTimeMessage()<\/eval><\/span><span style=\"color: #f48fb1\"><\/span><\/p>","mode":"instant"}},{"timer":{"duration":"$300","style":"hidden"}},{"if":{"condition":"_cmv = game.computerMove(_cmv)","commands":[{"say":{"label":"<p><span style=\"color: #f48fb1\"><\/span><span style=\"color: #f48fb1\"><eval>getLongTimeMessage()<\/eval><\/span><span style=\"color: #f48fb1\"><\/span><\/p>","mode":"instant"}},{"timer":{"duration":"$300","style":"hidden"}},{"if":{"condition":"_cmv = game.computerMove(_cmv)","commands":[{"say":{"label":"<p><span style=\"color: #f48fb1\"><\/span><span style=\"color: #f48fb1\"><eval>getLongTimeMessage()<\/eval><\/span><span style=\"color: #f48fb1\"><\/span><\/p>","mode":"instant"}},{"timer":{"duration":"$300","style":"hidden"}},{"if":{"condition":"_cmv = game.computerMove(_cmv)","commands":[{"say":{"label":"<p><span style=\"color: #f48fb1\"><\/span><span style=\"color: #f48fb1\"><eval>getLongTimeMessage()<\/eval><\/span><span style=\"color: #f48fb1\"><\/span><\/p>","mode":"instant"}},{"timer":{"duration":"$300","style":"hidden"}},{"noop":{"eval":{"script":"_cmv = game.computerMove(_cmv)\r\nif (_cmv) {\r\n  console.error(\"Ran out of long move depth\")\r\n}"}}},{"if":{"condition":"_cmv = game.computerMove(_cmv)","commands":[{"say":{"label":"<p><span style=\"color: #f48fb1\"><\/span><span style=\"color: #f48fb1\"><eval>getLongTimeMessage()<\/eval><\/span><span style=\"color: #f48fb1\"><\/span><\/p>","mode":"instant"}},{"timer":{"duration":"$300","style":"hidden"}},{"if":{"condition":"_cmv = game.computerMove(_cmv)","commands":[{"say":{"label":"<p><span style=\"color: #f48fb1\"><\/span><span style=\"color: #f48fb1\"><eval>getLongTimeMessage()<\/eval><\/span><span style=\"color: #f48fb1\"><\/span><\/p>","mode":"instant"}},{"timer":{"duration":"$300","style":"hidden"}},{"if":{"condition":"_cmv = game.computerMove(_cmv)","commands":[{"say":{"label":"<p><span style=\"color: #f48fb1\"><\/span><span style=\"color: #f48fb1\"><eval>getLongTimeMessage()<\/eval><\/span><span style=\"color: #f48fb1\"><\/span><\/p>","mode":"instant"}},{"timer":{"duration":"$300","style":"hidden"}},{"if":{"condition":"_cmv = game.computerMove(_cmv)","commands":[{"say":{"label":"<p><span style=\"color: #f48fb1\"><\/span><span style=\"color: #f48fb1\"><eval>getLongTimeMessage()<\/eval><\/span><span style=\"color: #f48fb1\"><\/span><\/p>","mode":"instant"}},{"timer":{"duration":"$300","style":"hidden"}},{"if":{"condition":"_cmv = game.computerMove(_cmv)","commands":[{"say":{"label":"<p><span style=\"color: #f48fb1\"><\/span><span style=\"color: #f48fb1\"><eval>getLongTimeMessage()<\/eval><\/span><span style=\"color: #f48fb1\"><\/span><\/p>","mode":"instant"}},{"timer":{"duration":"$300","style":"hidden"}},{"eval":{"script":"_cmv = game.computerMove(_cmv)\r\nif (_cmv) {\r\n  console.error(\"Ran out of long move depth\")\r\n}"}}]}}]}}]}}]}}]}}]}}]}}]}}]}}]}},{"timer":{"duration":"$endTime - Date.now()","style":"hidden"}},{"goto":{"target":"$pages.getCurrentPageId()"}}]}},{"if":{"condition":"_pCols && _promptCols","commands":[{"choice":{"options":[{"label":"a","commands":[{"eval":{"script":"_setCol = 0"}}],"visible":"$_pCols[0]"},{"label":"b","commands":[{"eval":{"script":"_setCol = 1"}}],"visible":"$_pCols[1]"},{"label":"c","commands":[{"eval":{"script":"_setCol = 2"}}],"visible":"$_pCols[2]"},{"label":"d","commands":[{"eval":{"script":"_setCol = 3"}}],"visible":"$_pCols[3]"},{"label":"e","commands":[{"eval":{"script":"_setCol = 4"}}],"visible":"$_pCols[4]"},{"label":"f","commands":[{"eval":{"script":"_setCol = 5"}}],"visible":"$_pCols[5]"},{"label":"g","commands":[{"eval":{"script":"_setCol = 6"}}],"visible":"$_pCols[6]"},{"label":"h","commands":[{"eval":{"script":"_setCol = 7"}}],"visible":"$_pCols[7]"},{"label":"\u21ba","commands":[{"eval":{"script":"game.clearSource()\r\npages.goto(pages.getCurrentPageId())"}}],"visible":"$game.hasSourceRow() || game.hasSourceCol()"}]}},{"eval":{"script":"if (!game.hasSource()) {\r\n  game.setSource(undefined,_setCol)\r\n} else if (!game.hasTarget()) {\r\n  _delayReload = game.setTarget(undefined,_setCol)\r\n}\r\n"}},{"if":{"condition":"_delayReload","commands":[{"noop":{"say":{"label":"<p><span style=\"color: #f8bbd0\">Alright, I&#39;ll move that for you...<\/span><\/p>","mode":"instant"}}},{"timer":{"duration":"0.2s","style":"hidden"}}]}},{"goto":{"target":"$pages.getCurrentPageId()"}}]}},{"if":{"condition":"_pRows && _promptRows","commands":[{"choice":{"options":[{"label":"1","commands":[{"eval":{"script":"_setRow = 0"}}],"visible":"$_pRows[0]"},{"label":"2","commands":[{"eval":{"script":"_setRow = 1"}}],"visible":"$_pRows[1]"},{"label":"3","commands":[{"eval":{"script":"_setRow = 2"}}],"visible":"$_pRows[2]"},{"label":"4","commands":[{"eval":{"script":"_setRow = 3"}}],"visible":"$_pRows[3]"},{"label":"5","commands":[{"eval":{"script":"_setRow = 4"}}],"visible":"$_pRows[4]"},{"label":"6","commands":[{"eval":{"script":"_setRow = 5"}}],"visible":"$_pRows[5]"},{"label":"7","commands":[{"eval":{"script":"_setRow = 6"}}],"visible":"$_pRows[6]"},{"label":"8","commands":[{"eval":{"script":"_setRow = 7"}}],"visible":"$_pRows[7]"},{"label":"\u21ba","commands":[{"eval":{"script":"game.clearSource()\r\npages.goto(pages.getCurrentPageId())"}}]}]}},{"eval":{"script":"if (!game.hasSource()) {\r\n  game.setSource(_setRow,undefined)\r\n} else if (!game.hasTarget()) {\r\n  _delayReload = game.setTarget(_setRow,undefined)\r\n}"}},{"if":{"condition":"_delayReload","commands":[{"noop":{"say":{"label":"<p><span style=\"color: #f8bbd0\">Got it. I&#39;ll make that move for you...<\/span><\/p>","mode":"instant"}}},{"timer":{"duration":"0.2s","style":"hidden"}}]}},{"goto":{"target":"$pages.getCurrentPageId()"}}]}},{"noop":{"choice":{"options":[{"label":"Reload","commands":[]},{"label":"Compute","commands":[{"eval":{"script":"game.computerMove()"}}]}]}}},{"eval":{"script":"pages.goto(pages.getCurrentPageId())"}}],"--play-react-draw":[{"notification.remove":{"id":"instruct"}},{"notification.remove":{"id":"cum"}},{"say":{"label":"<p><eval>game.renderBoard({\n  prompt: &quot;Draw&quot;,\n})<\/eval><\/p>","mode":"instant"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Aww, it&#39;s a draw.  Neither of us win.<\/span><\/p>","mode":"autoplay"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Go ahead and cum if you need to.<\/span><\/p>","mode":"pause"}},{"eval":{"script":"teaseStorage.removeItem('ps')"}},{"end":{}}],"--play-react-checkmate-player":[{"notification.remove":{"id":"cum"}},{"notification.remove":{"id":"instruct"}},{"say":{"label":"<p><eval>game.renderBoard({\n  prompt: &quot;Checkmate&quot;,\n})<\/eval><\/p>","mode":"instant"}},{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230570"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Checkmate?!  You win!  What should we do to celebrate?<\/span><\/p>","mode":"autoplay","allowSkip":true}},{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230556"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Hold you balls tight while you get to the edge for me.<\/span><\/p>","mode":"pause"}},{"choice":{"options":[{"label":"Edging","commands":[]}]}},{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230584"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Closer...<\/span><\/p>","mode":"custom","duration":"10s"}},{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230586"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Even closer...  And let go of your balls.<\/span><\/p>","mode":"custom","duration":"10s"}},{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230560"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Precum should be dripping out...<\/span><\/p>","mode":"custom","duration":"10s"}},{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230557"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Keep holding that edge...<\/span><\/p>","mode":"custom","duration":"10s"}},{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230564"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">A little longer...<\/span><\/p>","mode":"custom","duration":"10s"}},{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230565"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Hands off.  Let the edge fade...<\/span><\/p>","mode":"custom","duration":"20s"}},{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230568"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Now back that edge.<\/span><\/p>","mode":"autoplay"}},{"choice":{"options":[{"label":"Edging","commands":[]}]}},{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230560"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Over the edge now, but hold it back! Don&#39;t cum!<\/span><\/p>","mode":"autoplay"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Keep stroking, harder and faster. Keep holding back!<\/span><\/p>","mode":"custom","duration":"10s"}},{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230572"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Let it out! Cum for me!<\/span><\/p>","mode":"autoplay"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">CUM!<\/span><\/p>","mode":"autoplay"}},{"choice":{"options":[{"label":"Finished \ud83d\udca6","commands":[]}]}},{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230571"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Thanks for playing with me.<\/span><\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Maybe I can win next time?<\/span><\/p>","mode":"autoplay","allowSkip":true}},{"eval":{"script":"teaseStorage.removeItem('ps')"}},{"end":{}}],"--play-react-checkmate-npc":[{"notification.remove":{"id":"cum"}},{"notification.remove":{"id":"instruct"}},{"say":{"label":"<p><eval>game.renderBoard({\n  prompt: &quot;Checkmate&quot;,\n})<\/eval><\/p>","mode":"instant"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Checkmate! I win!  What should I do to celebrate...<\/span><\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Get to the edge for me...<\/span><\/p>","mode":"instant"}},{"choice":{"options":[{"label":"Edging","commands":[]}]}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Closer.  Make sure pre-cum is leaking...<\/span><\/p>","mode":"instant"}},{"choice":{"options":[{"label":"Leaking","commands":[]}]}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Stop.  Don&#39;t you dare cum.  Maybe next time.<\/span><\/p>","mode":"pause"}},{"eval":{"script":"teaseStorage.removeItem('ps')"}},{"end":{}}],"--play-react-check-player":[{"notification.remove":{"id":"instruct"}},{"say":{"label":"<p><eval>game.renderBoard({\n  prompt: &quot;Check&quot;,\n})<\/eval><\/p>","mode":"instant"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Oh no! Check! What am I going to do!<\/span><\/p>","mode":"autoplay","allowSkip":true}},{"goto":{"target":"--play-move-check"}}],"--play-react-check-npc":[{"notification.remove":{"id":"instruct"}},{"say":{"label":"<p><eval>game.renderBoard({\n  prompt: &quot;Check&quot;,\n})<\/eval><\/p>","mode":"instant"}},{"if":{"condition":"game.computerCapture.length >= 1","commands":[{"say":{"label":"<p><span style=\"color: #f8bbd0\">Ha! Check! Edge for me!<\/span><\/p>","mode":"autoplay"}},{"choice":{"options":[{"label":"Edged","commands":[]}]}}],"elseCommands":[{"say":{"label":"<p><span style=\"color: #f8bbd0\">Ha! Check! <\/span><\/p><p><span style=\"color: #f8bbd0\">Vigorously rub your bulge through your pants.<\/span><\/p>","mode":"instant"}},{"timer":{"duration":"10s-20s"}}]}},{"goto":{"target":"--play-move-check"}}],"--play-react-capture-npc":[{"notification.remove":{"id":"instruct"}},{"say":{"label":"<p><eval>game.renderBoard({\n  prompt: game.lastCaptureIcon() + &quot; captured&quot;,\n})<\/eval><\/p>","mode":"instant"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Yay! I captured your <\/span><span style=\"color: #f8bbd0\"><eval>game.lastCaptureName()<\/eval><\/span><span style=\"color: #f8bbd0\"> with my <\/span><span style=\"color: #f8bbd0\"><eval>game.lastPieceName()<\/eval><\/span><span style=\"color: #f8bbd0\">!<\/span><\/p>","mode":"autoplay","allowSkip":true}},{"goto":{"target":"--play-react-capture-npc-p"}}],"--play-react-capture-player":[{"notification.remove":{"id":"instruct"}},{"say":{"label":"<p><eval>game.renderBoard({\n  prompt: game.lastCaptureIcon() + &quot; captured&quot;,\n})<\/eval><\/p>","mode":"instant"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Oh no! You captured my <\/span><span style=\"color: #f8bbd0\"><eval>game.lastCaptureName()<\/eval><\/span><span style=\"color: #f8bbd0\">!<\/span><\/p>"}},{"eval":{"script":"loadedImage = false"}},{"goto":{"target":"--play-move-check"}}],"--play-move-check":[{"notification.remove":{"id":"skip"}},{"eval":{"script":"console.warn('Checking flags from last move...', game.lastMove)"}},{"eval":{"script":"loadedImage = false"}},{"if":{"condition":"!_didCapture && game.lastFlag(P4_MOVE_FLAG_CAPTURE)","commands":[{"if":{"condition":"_didCapture=true,game.lastWasPlayer()","commands":[{"goto":{"target":"--play-react-capture-player"}}],"elseCommands":[{"goto":{"target":"--play-react-capture-npc"}}]}}]}},{"if":{"condition":"game.lastFlag(P4_MOVE_FLAG_CHECK) && game.lastFlag(P4_MOVE_FLAG_MATE)","commands":[{"if":{"condition":"game.lastWasPlayer()","commands":[{"goto":{"target":"--play-react-checkmate-player"}}],"elseCommands":[{"goto":{"target":"--play-react-checkmate-npc"}}]}}]}},{"if":{"condition":"!_didCheck && game.lastFlag(P4_MOVE_FLAG_CHECK)","commands":[{"if":{"condition":"_didCheck=true,game.lastWasPlayer()","commands":[{"goto":{"target":"--play-react-check-player"}}],"elseCommands":[{"goto":{"target":"--play-react-check-npc"}}]}}],"elseCommands":[{"if":{"condition":"game.lastFlag(P4_MOVE_FLAG_CHECK)","commands":[{"eval":{"script":"console.warn(\"Already did CHECK check\")"}}]}}]}},{"if":{"condition":"game.lastFlag(P4_MOVE_FLAG_MATE) || game.lastFlag(P4_MOVE_FLAG_DRAW)","commands":[{"goto":{"target":"--play-react-draw"}}]}},{"eval":{"script":"game.lastCheckedMove = game.lastMove\r\n_didCapture = false\r\n_didCheck = false\r\n"}},{"goto":{"target":"--play-move"}}],"--util-image":[{"eval":{"script":"loadedImage = true\r\nlastImageNum = window.imageNum\r\nlastImagePage = window.imagePage\r\nimagePage = game.playerCapture.length\r\nlastImageTime = window.imageTime || 0\r\nimageTime = Date.now()\r\nconsole.log('imagePage', imagePage, game.playerCapture)\r\nif (imagePage > 6) {\r\n  imagePage = getRandomInt(5,7)\r\n}\r\nimagePage = Math.min(imagePage,7)\r\ntooShort = imageTime - lastImageTime < 800 && imagePage === lastImagePage\r\n\/\/          0 1 2 3 4 5 6 7\r\nif (!tooShort) {\r\n  imgSizes = [4,5,6,5,3,4,3,3]\r\n  imageNum = getRandomInt(0,imgSizes[imagePage]||0)\r\n  while(lastImageNum === imageNum) {\r\n    imageNum = getRandomInt(0,imgSizes[imagePage]||0)\r\n  }\r\n}"}},{"timer":{"duration":"1s","isAsync":true,"commands":[{"goto":{"target":"--play-move"}}],"style":"hidden"}},{"goto":{"target":"$'--util-image-' + imagePage"}}],"--util-image-0":[{"if":{"condition":"imageNum==0","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230491"}}]}},{"if":{"condition":"imageNum==1","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230494"}}]}},{"if":{"condition":"imageNum==2","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230495"}}]}},{"if":{"condition":"imageNum==3","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230490"}}]}},{"if":{"condition":"imageNum>=4","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230492"}}]}},{"goto":{"target":"--play-move"}}],"--util-image-1":[{"if":{"condition":"imageNum==0","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230501"}}]}},{"if":{"condition":"imageNum==1","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230493"}}]}},{"if":{"condition":"imageNum==2","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230502"}}]}},{"if":{"condition":"imageNum==3","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230503"}}]}},{"if":{"condition":"imageNum==4","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230498"}}]}},{"if":{"condition":"imageNum>=5","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230496"}}]}},{"goto":{"target":"--play-move"}}],"--util-image-2":[{"if":{"condition":"imageNum==0","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230506"}}]}},{"if":{"condition":"imageNum==1","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230507"}}]}},{"if":{"condition":"imageNum==2","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230508"}}]}},{"if":{"condition":"imageNum==3","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230515"}}]}},{"if":{"condition":"imageNum==4","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230510"}}]}},{"if":{"condition":"imageNum==5","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230513"}}]}},{"if":{"condition":"imageNum>=6","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230523"}}]}},{"goto":{"target":"--play-move"}}],"--util-image-3":[{"if":{"condition":"imageNum==0","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230527"}}]}},{"if":{"condition":"imageNum==1","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230525"}}]}},{"if":{"condition":"imageNum==2","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230530"}}]}},{"if":{"condition":"imageNum==3","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230528"}}]}},{"if":{"condition":"imageNum==4","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230519"}}]}},{"if":{"condition":"imageNum>=5","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230529"}}]}},{"goto":{"target":"--play-move"}}],"--util-image-4":[{"if":{"condition":"imageNum==0","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230535"}}]}},{"if":{"condition":"imageNum==1","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230536"}}]}},{"if":{"condition":"imageNum==2","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230539"}}]}},{"if":{"condition":"imageNum>=3","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230540"}}]}},{"goto":{"target":"--play-move"}}],"--util-image-5":[{"if":{"condition":"imageNum==0","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230571"}}]}},{"if":{"condition":"imageNum==1","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230561"}}]}},{"if":{"condition":"imageNum==2","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230572"}}]}},{"if":{"condition":"imageNum==3","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230570"}}]}},{"if":{"condition":"imageNum>=4","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230567"}}]}},{"goto":{"target":"--play-move"}}],"--util-image-6":[{"if":{"condition":"imageNum==0","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230582"}}]}},{"if":{"condition":"imageNum==1","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230583"}}]}},{"if":{"condition":"imageNum==2","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230586"}}]}},{"if":{"condition":"imageNum>=3","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230585"}}]}},{"goto":{"target":"--play-move"}}],"--util-image-7":[{"if":{"condition":"imageNum==0","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230558"}}]}},{"if":{"condition":"imageNum==1","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230597"}}]}},{"if":{"condition":"imageNum==2","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230600"}}]}},{"if":{"condition":"imageNum>=3","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230564"}}]}},{"goto":{"target":"--play-move"}}],"--play-react-capture-npc-p":[{"eval":{"script":"\/\/        1  2  3  4\r\npSizes = [1, 1, 1, 12]\r\npCap = game.computerCapture.length-1\r\nvar pPageNum = Math.min(pCap,pSizes.length-1)\r\npSize = pSizes[pPageNum]\r\npNum = getRandomInt(1,pSize)\r\npPage = '--play-react-capture-npc-p' + (pPageNum+1) + '-' + pNum\r\nconsole.log('pPage', pPage)\r\nloadedImage = false\r\n"}},{"timer":{"duration":"1s","isAsync":true,"commands":[{"goto":{"target":"--play-move-check"}}],"style":"hidden"}},{"if":{"condition":"pCap<3","commands":[{"notification.create":{"buttonCommands":[{"goto":{"target":"--play-move-check"}}],"buttonLabel":"Done","id":"skip"}}],"elseCommands":[]}},{"if":{"condition":"pCap>=1","commands":[{"notification.create":{"buttonCommands":[{"goto":{"target":"--play-react-cumming"}}],"buttonLabel":"Cumming \ud83d\udca6","id":"cum"}}]}},{"goto":{"target":"$pPage"}}],"--play-react-capture-npc-p4-9":[{"say":{"label":"<p><span style=\"color: #f8bbd0\">Get to the edge for me.<\/span><\/p>","mode":"instant"}},{"choice":{"options":[{"label":"Edging","commands":[]}]}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Now hold that edge while you take your turn.<\/span><\/p>","mode":"autoplay","allowSkip":true}},{"notification.create":{"id":"instruct","title":"\ud83d\udc8b Hold edge"}},{"goto":{"target":"--play-move-check"}}],"--play-react-capture-npc-p1-1":[{"say":{"label":"<p><span style=\"color: #f8bbd0\">Pull your pants down just enough to show me what you&#39;ve got.<\/span><\/p>","mode":"pause"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Nice.  Keep it out, but don&#39;t touch.<\/span><\/p>","mode":"custom","duration":"5s","allowSkip":true}},{"goto":{"target":"--play-move-check"}}],"--play-react-capture-npc-p2-1":[{"say":{"label":"<p><span style=\"color: #f8bbd0\">Pull your pants down all the way.<\/span><\/p>","mode":"instant"}},{"choice":{"options":[{"label":"Pants down","commands":[]}]}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">You can stroke for me now.<\/span><\/p>","mode":"instant"}},{"timer":{"duration":"10s-20s"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Stop.<\/span><\/p>","mode":"custom","duration":"5s","allowSkip":true}},{"goto":{"target":"--play-move-check"}}],"--play-react-capture-npc-p3-1":[{"say":{"label":"<p><span style=\"color: #f8bbd0\">Stroke as fast as you can.<\/span><\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">But gently squeeze your balls while you do it.<\/span><\/p>","mode":"instant"}},{"timer":{"duration":"10s-20s"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">That&#39;s all for now.<\/span><\/p>","mode":"custom","duration":"5s","allowSkip":true}},{"goto":{"target":"--play-move-check"}}],"--play-react-capture-npc-p4-1":[{"say":{"label":"<p><span style=\"color: #f8bbd0\">Get to the edge for me.<\/span><\/p>","mode":"instant"}},{"choice":{"options":[{"label":"Edging","commands":[]}]}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Now hold that edge.<\/span><\/p>","mode":"instant"}},{"timer":{"duration":"10s-20s"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Okay, stop.<\/span><\/p>","mode":"custom","duration":"5s","allowSkip":true}},{"goto":{"target":"--play-move-check"}}],"--play-react-capture-npc-p4-2":[{"say":{"label":"<p><span style=\"color: #f8bbd0\">Get to the edge for me.<\/span><\/p>","mode":"instant"}},{"choice":{"options":[{"label":"Edging","commands":[]}]}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Now hold that edge.<\/span><\/p>","mode":"instant"}},{"timer":{"duration":"10s-20s"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Okay, stop.<\/span><\/p>","mode":"custom","duration":"5s","allowSkip":true}},{"goto":{"target":"--play-move-check"}}],"--play-react-capture-npc-p4-3":[{"say":{"label":"<p><span style=\"color: #f8bbd0\">Stroke while messaging your balls...<\/span><\/p>","mode":"instant"}},{"timer":{"duration":"15s-25s"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">That&#39;s enough.<\/span><\/p>","mode":"custom","duration":"5s","allowSkip":true}},{"goto":{"target":"--play-move-check"}}],"--play-react-capture-npc-p4-4":[{"say":{"label":"<p><span style=\"color: #f8bbd0\">Stroke while gently messaging your balls...<\/span><\/p>","mode":"instant"}},{"timer":{"duration":"10s-20s"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">That&#39;s enough.<\/span><\/p>","mode":"custom","duration":"5s","allowSkip":true}},{"goto":{"target":"--play-move-check"}}],"--play-react-capture-npc-p4-5":[{"say":{"label":"<p><span style=\"color: #f8bbd0\">Stroke with a tight grip...<\/span><\/p>","mode":"instant"}},{"timer":{"duration":"10s-20s"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Perfect.  Stop.<\/span><\/p>","mode":"custom","duration":"5s","allowSkip":true}},{"goto":{"target":"--play-move-check"}}],"--play-react-capture-npc-p4-6":[{"say":{"label":"<p><span style=\"color: #f8bbd0\">Stroke with a loose  grip...<\/span><\/p>","mode":"instant"}},{"timer":{"duration":"10s-20s"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Perfect.  Stop.<\/span><\/p>","mode":"custom","duration":"5s","allowSkip":true}},{"goto":{"target":"--play-move-check"}}],"--play-react-capture-npc-p4-7":[{"say":{"label":"<p><span style=\"color: #f8bbd0\">With two fingers, gently stroke from the base of your cock to your frenulum.<\/span><\/p>","mode":"instant"}},{"timer":{"duration":"10s-20s"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Keep doing that while you take your turn.  Don&#39;t stop.<\/span><\/p>","mode":"custom","duration":"5s","allowSkip":true}},{"notification.create":{"id":"instruct","title":"\ud83d\udc8b Two finger stroke"}},{"goto":{"target":"--play-move-check"}}],"--play-react-capture-npc-p4-8":[{"say":{"label":"<p><span style=\"color: #f8bbd0\">Slap your cock.<\/span><\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Keep slapping it around, but in a way that feels good.<\/span><\/p>","mode":"instant"}},{"timer":{"duration":"10s-20s"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Now keep doing that until you finish your turn.<\/span><\/p>","mode":"autoplay","allowSkip":true}},{"notification.create":{"id":"instruct","title":"\ud83d\udc8b Slap cock"}},{"goto":{"target":"--play-move-check"}}],"--play-react-capture-npc-p4-10":[{"say":{"label":"<p><span style=\"color: #f8bbd0\">Squeeze your cock, then let go...<\/span><\/p>","mode":"autoplay"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Keep doing that until I tell you to stop.<\/span><\/p>","mode":"instant"}},{"timer":{"duration":"10s-20s"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">That&#39;s good.  Stop.<\/span><\/p>","mode":"custom","duration":"5s","allowSkip":true}},{"goto":{"target":"--play-move-check"}}],"--play-react-capture-npc-p4-11":[{"say":{"label":"<p><span style=\"color: #f8bbd0\">Back to stroking...<\/span><\/p>","mode":"instant"}},{"timer":{"duration":"10s-20s"}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Okay, stop.<\/span><\/p>","mode":"custom","duration":"5s","allowSkip":true}},{"goto":{"target":"--play-move-check"}}],"--play-react-capture-npc-p4-12":[{"say":{"label":"<p><span style=\"color: #f8bbd0\">Stroke for me.  However you want, but don&#39;t stop.<\/span><\/p>","mode":"instant"}},{"choice":{"options":[{"label":"Stroking","commands":[]}]}},{"say":{"label":"<p><span style=\"color: #f8bbd0\">Keep stroking like that until it&#39;s my turn.<\/span><\/p>","mode":"autoplay","allowSkip":true}},{"notification.create":{"id":"instruct","title":"\ud83d\udc8b Stroke for me"}},{"goto":{"target":"--play-move-check"}}],"--play-react-cumming":[{"notification.remove":{"id":"skip"}},{"notification.remove":{"id":"instruct"}},{"say":{"label":"<p><eval>game.renderBoard({\n  prompt: [&quot;Cumming.&quot;,&quot;&quot;,&quot;Player forfeits.&quot;],\n})<\/eval><\/p>","mode":"instant"}},{"if":{"condition":"game.playerCapture.length <= 4","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230547"}}],"elseCommands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230567"}}]}},{"say":{"label":"<p><span style=\"color: #f48fb1\">Oh no!<\/span><\/p>","mode":"custom","duration":"4s"}},{"if":{"condition":"game.playerCapture.length <= 4","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230555"}}],"elseCommands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230568"}}]}},{"say":{"label":"<p><span style=\"color: #f48fb1\">That&#39;s okay.  Stroke and cum as hard as you want...<\/span><\/p>","mode":"autoplay"}},{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230603"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">Just don&#39;t go limp after you finish!<\/span><\/p>","mode":"instant"}},{"choice":{"options":[{"label":"Finished \ud83d\udca6","commands":[]}]}},{"eval":{"script":"teaseStorage.removeItem('ps')"}},{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230607"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">Because you blew your load early,  I win!<\/span><\/p>","mode":"autoplay","allowSkip":true}},{"eval":{"script":"var _didFo = teaseStorage.getItem('fo')\r\nconsole.log('Did forced', _didFo)"}},{"if":{"condition":"_didFo","commands":[{"say":{"label":"<p><span style=\"color: #f48fb1\">You already know what you need to do now, don&#39;t you?<\/span><\/p>","mode":"instant"}},{"choice":{"options":[{"label":"Yes, let's do it.","commands":[{"say":{"label":"<p><span style=\"color: #f48fb1\">Perfect.  Let&#39;s try this again.<\/span><\/p>","mode":"autoplay","allowSkip":true}}]},{"label":"No, I'm not trying that again.","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230567"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">Are you sure?  You know it&#39;ll be fun. And I did win.<\/span><\/p>","mode":"instant"}},{"choice":{"options":[{"label":"Okay, fine.","commands":[{"say":{"label":"<p><span style=\"color: #f48fb1\">Good!<\/span><\/p>","mode":"autoplay","allowSkip":true}}]},{"label":"No.  I'm done.","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230546"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">Well that&#39;s kind of selfish.  I hope you&#39;ll try again next time.<\/span><\/p>","mode":"autoplay"}},{"end":{}},{"goto":{"target":"$badpage"}}]}]}}]}]}}],"elseCommands":[{"say":{"label":"<p><span style=\"color: #f48fb1\">Since I won, I think I should get a little something, don&#39;t you?<\/span><\/p>","mode":"instant"}},{"choice":{"options":[{"label":"I guess that's only fair","commands":[{"say":{"label":"<p><span style=\"color: #f48fb1\">Really?  I thought you&#39;d chicken out.<\/span><\/p>","mode":"autoplay","allowSkip":true}}]},{"label":"No,  I don't trust you","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230567"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">Are you sure? You do owe me, and I think you&#39;ll have fun.<\/span><\/p>","mode":"instant"}},{"choice":{"options":[{"label":"Okay, fine.","commands":[{"say":{"label":"<p><span style=\"color: #f48fb1\">Perfect!<\/span><\/p>","mode":"autoplay","allowSkip":true}}]},{"label":"No.  I'm done.","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230546"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">Well that&#39;s kind of selfish.  Maybe you&#39;ll try next time.<\/span><\/p>","mode":"autoplay"}},{"end":{}},{"goto":{"target":"$badpage"}}]}]}}]}]}}]}},{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230601"}},{"if":{"condition":"_didFo","commands":[{"say":{"label":"<p><span style=\"color: #f48fb1\">You&#39;re going to need lube for this -- you know what it&#39;s for.<\/span><\/p>","mode":"autoplay","allowSkip":true}}],"elseCommands":[{"say":{"label":"<p><span style=\"color: #f48fb1\">You&#39;re going to need lube for this -- don&#39;t worry, it&#39;s not what you think.<\/span><\/p>","mode":"autoplay","allowSkip":true}}]}},{"say":{"label":"<p><span style=\"color: #f48fb1\">If you don&#39;t have any, you could try using all that cum you just sprayed out.<\/span><\/p>","mode":"autoplay","allowSkip":true}},{"choice":{"options":[{"label":"Lube is ready","commands":[]}]}},{"say":{"label":"<p><span style=\"color: #f48fb1\">Now cover your cock in lube, grip it tight and start stroking as hard and as fast as you can.<\/span><\/p>","mode":"autoplay"}},{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230568"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">Don&#39;t you dare go limp.  Harder and faster if you feel your boner fading.<\/span><\/p>","mode":"autoplay"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">Keep pounding your cock as fast as you can.<\/span><\/p>","mode":"autoplay"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">I&#39;m going to get another load out of you whether you like it or not.<\/span><\/p>","mode":"autoplay"}},{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230558"}},{"eval":{"script":"teaseStorage.setItem('fo', 1)"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">Use my mouth as a target if you want, but keep stroking tight, hard and fast.<\/span><\/p>","mode":"autoplay"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">It&#39;s okay when your legs start to shake.  Keep going, faster.  Add more lube if you need it.<\/span><\/p>","mode":"custom","duration":"10s"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">Can you feel it building up?  Keep pounding that cock.<\/span><\/p>","mode":"custom","duration":"10s"}},{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230557"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">That&#39;s not pain you feel -- it&#39;s a deep orgasm building.<\/span><\/p>","mode":"custom","duration":"10s"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">Keep going. Push through your arm cramping.<\/span><\/p>","mode":"custom","duration":"10s"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">Grip tighter, go faster.<\/span><\/p>","mode":"custom","duration":"10s"}},{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230564"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">Give me that load.  You feel it coming.<\/span><\/p>","mode":"custom","duration":"10s"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">When your whole body is shaking, you&#39;re doing it right.<\/span><\/p>","mode":"custom","duration":"10s"}},{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230556"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">You can do it.  It&#39;s the same for us girls.<\/span><\/p>","mode":"autoplay"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">Tighten that grip.  Don&#39;t go too limp. As fast as you can.  Lots of lube.<\/span><\/p>","mode":"custom","duration":"15s"}},{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230560"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">Give it to me.<\/span><\/p>","mode":"autoplay"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">You owe me.<\/span><\/p>","mode":"custom","duration":"10s"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">Harder.  Faster.<\/span><\/p>","mode":"custom","duration":"10s"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">You <\/span><span style=\"color: #f48fb1\"><em>will<\/em><\/span><span style=\"color: #f48fb1\"> cum for me.<\/span><\/p>","mode":"custom","duration":"10s"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">Keep pounding that cock until you explode.<\/span><\/p>","mode":"custom","duration":"10s"}},{"choice":{"options":[{"label":"I did it \ud83d\udca6","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230565"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">Thank you.  That&#39;s exactly what I needed.<\/span><\/p>","mode":"autoplay"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">Come back any time.<\/span><\/p>","mode":"autoplay"}}]},{"label":"I can't do it.","commands":[{"image":{"locator":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2230567"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">If you kept going I know you could&#39;ve done it.<\/span><\/p>","mode":"autoplay"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">At least you tried.<\/span><\/p>","mode":"autoplay"}},{"say":{"label":"<p><span style=\"color: #f48fb1\">Mabey next time?<\/span><\/p>","mode":"autoplay"}}]}]}},{"end":{}}]},"init":"\/* p4wn, AKA 5k chess - by Douglas Bagnall <douglas@paradise.net.nz>\r\n* Adapted and expanded for Eos by fapnip\r\n* original P4WN: http:\/\/p4wn.sf.net\/\r\n*\/\r\n\r\nvar P4_MOVE_FLAG_OK = 1;\r\nvar P4_MOVE_FLAG_CHECK = 2;\r\nvar P4_MOVE_FLAG_MATE = 4;\r\nvar P4_MOVE_FLAG_CAPTURE = 8;\r\nvar P4_MOVE_FLAG_CASTLE_KING = 16;\r\nvar P4_MOVE_FLAG_CASTLE_QUEEN = 32;\r\nvar P4_MOVE_FLAG_DRAW = 64;\r\n\r\nvar P4_MOVE_ILLEGAL = 0;\r\nvar P4_MOVE_MISSED_MATE = P4_MOVE_FLAG_CHECK | P4_MOVE_FLAG_MATE;\r\nvar P4_MOVE_CHECKMATE = P4_MOVE_FLAG_OK | P4_MOVE_FLAG_CHECK | P4_MOVE_FLAG_MATE;\r\nvar P4_MOVE_STALEMATE = P4_MOVE_FLAG_OK | P4_MOVE_FLAG_MATE;\r\n\r\nvar FIND_TIMEOUT = 8000 \/\/ if 8 seconds or over, break out\r\nvar FIND_TIMEOUT_LIMIT = 8 \/\/ only break out 8 times\r\n\r\n;(function(){\r\n  p4_log = function(){console.log.apply(console, arguments);};\r\n\r\n  var P4WN = function(opt) {\r\n    opt = opt || {}\r\n    this.start = 0;\r\n    this.draw_offers = 0;\r\n    this.board_state = p4_new_game();\r\n\r\n    \/\/ this.board_state.treeclimber = p4_alphabeta_treeclimber \/\/ Default\r\n    \/\/ this.board_state.treeclimber = p4_nullmove_alphabeta_treeclimber\r\n    \/\/ this.board_state.treeclimber = p4_nullmove_alphabeta_quiescing_treeclimber\r\n    this.board_state.treeclimber = p4_negascout_treeclimber\r\n    \/\/ this.board_state.treeclimber = p4_negamax_treeclimber \/\/ Very very slow\r\n\r\n    this.players = ['human','computer']; \/\/[white, black] controllers\r\n    this.pawn_becomes = opt.pawn_becomes || 0; \/\/index into P4WN_PROMOTION_* arrays\r\n    this.computer_level = opt.computer_level || P4WN_DEFAULT_LEVEL;\r\n    this.buttons = {\r\n        elements: [],\r\n        refreshers: []\r\n    };\r\n    this.board_state.prepare()\r\n    this.clearSource()\r\n    this.os = 'win'\r\n    this.browser = 'chrome'\r\n    this.size = 's'\r\n    this.style = 'winSml'\r\n    this.moveCount = 0\r\n    this.lastMove = {}\r\n    this.lastCheck = ''\r\n    this.checkLastMove()\r\n    this.playerCapture = ''\r\n    this.computerCapture = ''\r\n  }\r\n\r\n  window.P4WN = P4WN\r\n\r\n  \/\/ P4WN.prototype\r\n\r\n  P4WN.prototype.setHumanFirst = function() {\r\n    this.players = ['human','computer'];\r\n  }\r\n\r\n  \r\n  P4WN.prototype.setComputerFirst = function() {\r\n    this.players = ['computer','human'];\r\n  }\r\n\r\n  \r\n  P4WN.prototype.setOs = function(v) {\r\n    this.os = v\r\n    this.updateStyle()\r\n  }\r\n\r\n  P4WN.prototype.setBrowser = function(v) {\r\n    this.browser = v\r\n    this.updateStyle()\r\n  }\r\n\r\n  P4WN.prototype.updateStyle = function() {\r\n    \/\/ TODO -- do this by adding and scannng applicable object properties in boardStyles,\r\n    \/\/         not by expanding the if\/else mess below\r\n    if (this.os == 'ios') {\r\n      this.style = 'iosSml'\r\n    } else if (this.browser == 'firefox') {\r\n      this.style = 'ffSml'\r\n    } else if (this.browser == 'safari') {\r\n      if (this.os == 'osx') {\r\n        this.style = 'osxSml'\r\n      } else {\r\n        this.style = 'winSml'\r\n      }\r\n    } else if (this.browser == 'tor') {\r\n      this.style = 'torSml'\r\n    }\r\n    console.log('Using Style:', this.style, this.os, this.browser)\r\n  }\r\n\r\n  function toSquare(row, col) {\r\n    return (row + 2) * 10 + (col + 1)\r\n  }\r\n\r\n  function toRowCol(square) {\r\n    var row = Math.floor(square\/10)\r\n    var col = (square - (row * 10)) - 1\r\n    row-=2\r\n    return [row,col]\r\n  }\r\n\r\n  var boardStyleDefaults = {\r\n      block: '\u2587',\r\n      bfont:14,\r\n      bspace:14,\r\n      pieceSize:14,\r\n      ptop:20,\r\n      pbot:20,\r\n      ppad:20,\r\n      pfont:15,\r\n      mtop:20,\r\n      pieceOffsetTop:2,\r\n      bcolor1:[181, 54, 145,1],\r\n      bcolor2:[201, 129, 182,1],\r\n      maskcolor:[0, 0, 0,.3], \/\/ darken\r\n      maskcolor2:[255, 255, 0,.3], \/\/ peice to move\r\n      maskcolor3:[0, 255, 0,.33], \/\/ last moved peice\r\n      hspacechar:'&#8288;\u200a&#8288;',\r\n      hspace:2,\r\n      lfont:11,\r\n      lrowspace:2,\r\n      lrowpad:1,\r\n      lcolspace:2,\r\n      lcolpad:2,\r\n    }\r\n\r\n  var boardStyles = {\r\n    ffSml: {\r\n      hspacechar:'&#x034F&#x200a;&#x034F;', \/\/ Firefox has a word wrap bug that ignores no-wrap for &#8288;\r\n    },\r\n    torSml: {\r\n      hspacechar:'&#x034F&#x200a;&#x034F;', \/\/ Firefox has a word wrap bug that ignores no-wrap for &#8288;\r\n      block: '\u2584',\r\n      pieceOffsetTop:5,\r\n      pieceSize:14,\r\n      bfont:22,\r\n      bspace:16,\r\n    },\r\n    winSml: {},\r\n    osxSml: {\r\n      pieceOffsetTop:0,\r\n      hspacechar:'&#8288;<span style=\"font-size:4px\">&#x200a;<\/span>&#8288;', \/\/ OSX\/Safari's hair space isn't hair at all.\r\n    },\r\n    iosSml: {\r\n      pfont:16,\r\n      pieceOffsetTop:1,\r\n      hspace:3,\r\n      lfont:13,\r\n    },\r\n    iosMed: {\r\n      bfont:16,\r\n      bspace:16,\r\n      pfont:18,\r\n      pieceOffsetTop:1,\r\n      hspace:3,\r\n      lfont:15,\r\n    },\r\n    iosLrg: {\r\n      bfont:22,\r\n      pieceSize:22,\r\n      bspace:21,\r\n      pfont:18,\r\n      hspace:6,\r\n      lfont:16,\r\n      lrowspace:15,\r\n      lrowpad:0,\r\n      lcolspace:10,\r\n      lcolpad:0,\r\n    },\r\n    \/\/ TODO - actually test these, flesh out more size options, add android tweaks, add size selection, etc.\r\n  }\r\n\r\n  Object.keys(boardStyles).forEach(function(s){\r\n    Object.keys(boardStyleDefaults).forEach(function(d){\r\n      var b = boardStyles[s]\r\n      b[d] = b[d] === undefined ? boardStyleDefaults[d] : b[d]\r\n    })\r\n  })\r\n\r\n  var rpieces  = {\r\n  \/\/ &#xFE0E; forces the character to be rendered as text, \r\n  \/\/  not colored emoji if the browser's font has one for the given char.\r\n  \/\/   K:'\u2654&#xFE0E;',\r\n  \/\/   Q:'\u2655&#xFE0E;',\r\n  \/\/   R:'\u2656&#xFE0E;',\r\n  \/\/   B:'\u2657&#xFE0E;',\r\n  \/\/   N:'\u2658&#xFE0E;',\r\n  \/\/   P:'\u2659&#xFE0E;',\r\n    K:'<span style=\"color:#fff\">\u265a&#xFE0E;<\/span>',\r\n    Q:'<span style=\"color:#fff\">\u265b&#xFE0E;<\/span>',\r\n    R:'<span style=\"color:#fff\">\u265c&#xFE0E;<\/span>',\r\n    B:'<span style=\"color:#fff\">\u265d&#xFE0E;<\/span>',\r\n    N:'<span style=\"color:#fff\">\u265e&#xFE0E;<\/span>',\r\n    P:'<span style=\"color:#fff\">\u265f&#xFE0E;<\/span>',\r\n    k:'<span style=\"color:#000\">\u265a&#xFE0E;<\/span>',\r\n    q:'<span style=\"color:#000\">\u265b&#xFE0E;<\/span>',\r\n    r:'<span style=\"color:#000\">\u265c&#xFE0E;<\/span>',\r\n    b:'<span style=\"color:#000\">\u265d&#xFE0E;<\/span>',\r\n    n:'<span style=\"color:#000\">\u265e&#xFE0E;<\/span>',\r\n    p:'<span style=\"color:#000\">\u265f&#xFE0E;<\/span>',\r\n    \/\/ K:'<span style=\"color:#fff\">\u2654&#xFE0E;<\/span>',\r\n    \/\/ Q:'<span style=\"color:#fff\">\u2655&#xFE0E;<\/span>',\r\n    \/\/ R:'<span style=\"color:#fff\">\u2656&#xFE0E;<\/span>',\r\n    \/\/ B:'<span style=\"color:#fff\">\u2657&#xFE0E;<\/span>',\r\n    \/\/ N:'<span style=\"color:#fff\">\u2658&#xFE0E;<\/span>',\r\n    \/\/ P:'<span style=\"color:#fff\">\u2659&#xFE0E;<\/span>',\r\n    \/\/ k:'<span style=\"color:#000\">\u2654&#xFE0E;<\/span>',\r\n    \/\/ q:'<span style=\"color:#000\">\u2655&#xFE0E;<\/span>',\r\n    \/\/ r:'<span style=\"color:#000\">\u2656&#xFE0E;<\/span>',\r\n    \/\/ b:'<span style=\"color:#000\">\u2657&#xFE0E;<\/span>',\r\n    \/\/ n:'<span style=\"color:#000\">\u2658&#xFE0E;<\/span>',\r\n    \/\/ p:'<span style=\"color:#000\">\u2659&#xFE0E;<\/span>',\r\n  }\r\n\r\n  function _s(a){\r\n    return a\r\n  }\r\n\r\n  P4WN.prototype.renderBoard = function(opt) {\r\n\r\n    var gb = this.getFlatBoard()\r\n\r\n    opt = opt || {}\r\n\r\n    var bds = _s(boardStyles[this.style])\r\n\r\n    function rep(c,v,j){\r\n      var r = []\r\n      for (var i = 0; i < c; i++){\r\n        r.push(v)\r\n      }\r\n      return r.join(j||'')\r\n    }\r\n    var hspace = rep(bds.hspace,bds.hspacechar,'')\r\n    function brs(c){\r\n      return rep(c,'<br>','')\r\n    }\r\n    function blks(c){\r\n      return rep(c,bds.block,hspace)\r\n    }\r\n    function lpad(c){\r\n      return '<span style=\"color:rgba(0,0,0,0)\">'+blks(c)+(c?hspace:'')+'<\/span>'\r\n    }\r\n    function pdisp(p){\r\n      return '<span style=\"font-size:'+bds.pieceSize+'px\">'+p+'<\/span>'\r\n    }\r\n    var r = []\r\n    var r2 = []\r\n    var b = brs(bds.bspace)\r\n    var bc1 = bds.bcolor1.join(',')\r\n    var bc2 = bds.bcolor2.join(',')\r\n    var mskc = bds.maskcolor.join(',')\r\n    var blk = bds.block\r\n    var mskblk = '<span style=\"color:rgba('+mskc+')\">'+blk+'<\/span>'\r\n    var mskblk2 = '<span style=\"color:rgba('+bds.maskcolor2.join(',')+')\">'+blk+'<\/span>'\r\n    var mskblk3 = '<span style=\"color:rgba('+bds.maskcolor3.join(',')+')\">'+blk+'<\/span>'\r\n    var darkblk = '<span style=\"color:rgba('+bc1+')\">'+blk+'<\/span>'\r\n    var lightblk = '<span style=\"color:rgba('+bc2+')\">'+blk+'<\/span>'\r\n    var emptyblk = '<span style=\"color:rgba(0,0,0,0)\">'+blk+'<\/span>'\r\n    var mskblks = {\r\n      'm': mskblk,\r\n      'h': mskblk2,\r\n      'l': mskblk3,\r\n      '': emptyblk,\r\n    }\r\n    \/\/ Generate chess board\r\n    for (var i = 0; i < 8; i++) {\r\n      var l = []\r\n      for (var i2 = 0; i2 < 8; i2++) {       \r\n        if (i % 2) {\r\n          if (i2 % 2) {\r\n            l.push(lightblk)\r\n          } else {\r\n            l.push(darkblk)\r\n          }\r\n        } else {\r\n          if (i2 % 2) {\r\n            l.push(darkblk)\r\n          } else {\r\n            l.push(lightblk)\r\n          }\r\n        }\r\n      }\r\n      r.push(lpad(1)+l.join(hspace))\r\n      r2.push(lpad(1)+blks(bds.ppad))\r\n    }\r\n    r2.push(r2[0])\r\n    var layers = []\r\n    \/\/ Add each chess piece to be displayed to its own layer\r\n    gb.reverse().forEach(function(r,ri){\r\n      r.forEach(function(c, ci){\r\n        if (c) {\r\n          var cp = rpieces[c]\r\n          if (cp) {\r\n            var layer = brs((ri * bds.bspace) + bds.pieceOffsetTop) + lpad(ci + 1) + pdisp(cp)\r\n            layers.push(layer)\r\n          }\r\n        }\r\n      })\r\n    })\r\n    \/\/ Build row\/column labels\r\n    var rowlabels = [8,7,6,5,4,3,2,1]\r\n    var collabels = ['a','b','c','d','e','f','g','h']\r\n    rowlabels.forEach(function(l,i){\r\n      layers.push(brs((i * bds.bspace + bds.lrowpad)) + rep(bds.lrowspace,bds.hspacechar,'') + '<span style=\"font-size:'+bds.lfont+'px\">'+l+'<\/span>')\r\n    })\r\n    collabels.forEach(function(l,i){\r\n      layers.push(brs((8 * bds.bspace + bds.lcolpad)) + lpad(1+i) + rep(bds.lrowspace,bds.hspacechar,'') + '<span style=\"font-size:'+bds.lfont+'px\">'+l+'<\/span>')\r\n    })\r\n    \/\/ Adds text prompt layer if requested\r\n    if (opt.prompt) {\r\n      var prompt = Array.isArray(opt.prompt) ? opt.prompt : [opt.prompt]\r\n      var plen = prompt.length\r\n      prompt.forEach(function(p,i){\r\n        var f = p.replace(\/ \/g, '&nbsp;')\r\n        while(f.match(\/(<[^>]+)(&nbsp;)\/)){\r\n          f = f.replace(\/(<[^>]+)(&nbsp;)\/,\"$1 \")\r\n        }\r\n        var layer = brs(((8 - (plen - i)) * bds.bspace) + bds.pieceOffsetTop) + lpad(10) + \r\n          '&#8288;<span style=\"font-size:'+bds.pfont+'px\">' + f + '<\/span>'\r\n        layers.push(layer)\r\n      })\r\n    }\r\n    \/\/ Build layer for mask, if needed (darkens\/lightens given blocks)\r\n    var mask = this.buildMask()\r\n    if (mask) {\r\n      var layerRows = []\r\n      var didCols = [0,0,0,0,0,0,0,0]\r\n      mask.forEach(function(rv, r){\r\n        var didRow = false\r\n        var row = [emptyblk]\r\n        rv.forEach(function(cv, c){\r\n          row[c+1] = mskblks[cv] || 'Z'\r\n          didRow = didRow || cv === ''\r\n          didCols[c] = didCols[c] || (!cv ? 1 : 0)\r\n        })\r\n        if (!didRow) row[0] = mskblk\r\n        layerRows.push(row.join(hspace))\r\n      })\r\n      layerRows.reverse() \/\/ flip board\r\n      layerRows.push(didCols.reduce(function(r,c){\r\n        r.push(c?emptyblk:mskblk)\r\n        return r\r\n      },[emptyblk]).join(hspace))\r\n      layers.push(layerRows.join(b))\r\n    }\r\n    var txt = \r\n    \/\/ '<span class=\"eosActivitySidebar\">TestBar<\/span>' +\r\n    '<span class=\"_continueIndicator_1figp_30 eosContainer\" style=\"font-size:100%;text-align:left\">' +\r\n      \/\/ Display some inivisible blocks to size the say bubble\r\n      '<span style=\"font-size:'+bds.bfont+'px;color:rgba(0,0,0,0)\">'\r\n        + brs(bds.mtop) + r2.join(b) + \/\/ To size\r\n      '<\/span>' +\r\n      \/\/ Display chess board layer\r\n      '<span class=\"eosPreloaderOverlay\" style=\"font-size:100%\">' +\r\n        '<span class=\"eosContainer\" style=\"font-size:100%\">' +\r\n          '<span class=\"_continueIndicator_1figp_30 eosPreloaderOverlay\" style=\"font-size:'+bds.bfont+'px\">' +\r\n            brs(bds.ptop) + r.join(b) +\r\n          '<\/span>' +\r\n        '<\/span>' +\r\n      '<\/span>' +\r\n      \/\/ Display chess piece layers, mask layer, row\/column label layers, etc.\r\n      layers.reduce(function(r, l){\r\n        r.push(\r\n      '<span class=\"eosPreloaderOverlay\" style=\"font-size:100%\">' +\r\n        '<span class=\"eosContainer\" style=\"font-size:100%\">' +\r\n          '<span class=\"_continueIndicator_1figp_30 eosPreloaderOverlay\" style=\"font-size:'+bds.bfont+'px\">' +\r\n            brs(bds.ptop) + l +\r\n          '<\/span>' +\r\n        '<\/span>' +\r\n      '<\/span>')\r\n      return r\r\n      },[]).join('')\r\n    '<\/span>'\r\n    return txt\r\n  }\r\n\r\n  \/*\r\nP4_MOVE_FLAG_OK = 1;\r\nP4_MOVE_FLAG_CHECK = 2;\r\nP4_MOVE_FLAG_MATE = 4;\r\nP4_MOVE_FLAG_CAPTURE = 8;\r\nP4_MOVE_FLAG_CASTLE_KING = 16;\r\nP4_MOVE_FLAG_CASTLE_QUEEN = 32;\r\nP4_MOVE_FLAG_DRAW = 64;\r\n\r\nP4_MOVE_ILLEGAL = 0;\r\nP4_MOVE_MISSED_MATE = P4_MOVE_FLAG_CHECK | P4_MOVE_FLAG_MATE;\r\nP4_MOVE_CHECKMATE = P4_MOVE_FLAG_OK | P4_MOVE_FLAG_CHECK | P4_MOVE_FLAG_MATE;\r\nP4_MOVE_STALEMATE = P4_MOVE_FLAG_OK | P4_MOVE_FLAG_MATE;\r\n  *\/\r\n\r\n\r\n  P4WN.prototype.lastWasPlayer = function() {\r\n    return this.players[this.lastMove.mover] == 'human'\r\n  }\r\n\r\n  P4WN.prototype.lastCaptureName = function() {\r\n    return this.pieceName(this.lastMove.capture)\r\n  }\r\n\r\n  P4WN.prototype.lastCaptureIcon = function() {\r\n    return this.pieceIcon(this.lastMove.capture)\r\n  }\r\n\r\n  P4WN.prototype.lastPieceName = function() {\r\n    return this.pieceName(this.lastMove.piece)\r\n  }\r\n\r\n  P4WN.prototype.lastPieceIcon = function() {\r\n    return this.pieceIcon((this.lastMove.piece || '').toUpperCase())\r\n  }\r\n\r\n  P4WN.prototype.lastFlag = function(c) {\r\n    return (this.lastMove.flags || 0) & c\r\n  }\r\n\r\n  P4WN.prototype.checkLastMove = function() {\r\n    var lm = this.lastMove|| {}\r\n    var lms = [lm.source,lm.target,lm.piece,lm.capture,lm.flags].join(',')\r\n    var r = lms !== this.lastCheck && lm.target && ( \r\n      (lm.flags & P4_MOVE_FLAG_CHECK) ||\r\n      (lm.flags & P4_MOVE_FLAG_CAPTURE) ||\r\n      (lm.flags & P4_MOVE_FLAG_MATE) ||\r\n      (lm.flags & P4_MOVE_FLAG_DRAW)\r\n    )\r\n    this.lastCheck = lms\r\n    return r\r\n  }\r\n\r\n  var pieceNames = {\r\n    p: 'Pawn',\r\n    n: 'Knight',\r\n    b: 'Bishop',\r\n    r: 'Rook',\r\n    q: 'Queen',\r\n    k: 'King',\r\n  }\r\n\r\n  P4WN.prototype.pieceName = function(p) {\r\n    return pieceNames[(p+'').toLowerCase()]\r\n  }\r\n  \r\n  P4WN.prototype.pieceIcon = function(p) {\r\n    return rpieces[(p+'').toLowerCase()]\r\n  }\r\n\r\n  P4WN.prototype.buildMask = function() {\r\n    var r = []\r\n    var _this = this\r\n    var fillChar = (!this.hasSource() || !this.hasTarget()) ? 'm' : ''\r\n    var lf = this.lastMove.flags\r\n    if ((lf & P4_MOVE_CHECKMATE) || (lf & P4_MOVE_STALEMATE) || (lf & P4_MOVE_FLAG_DRAW)) {\r\n      \/\/ fillChar = ''\r\n    }\r\n    for (var i = 0; i < 8; i++) {\r\n      for (var i2 = 0; i2 < 8; i2++) {\r\n        r[i] = r[i]||[]\r\n        r[i].push(fillChar)\r\n      }\r\n    }\r\n\r\n    if (this.lastMove && this.lastMove.target) {\r\n      var rowcol = toRowCol(this.lastMove.target)\r\n      r[rowcol[0]][rowcol[1]] = 'l' \/\/ mark last move\r\n      console.log('Last Move:', this.lastMove, rowcol)\r\n      if (this.lastMove.start) {\r\n        var sRowCol = toRowCol(this.lastMove.start)\r\n        r[sRowCol[0]][sRowCol[1]] = 'l' \/\/ mark last move start\r\n      }\r\n    } else {\r\n      console.warn('No last move target', this.lastMove)\r\n    }\r\n\r\n    if (!this.hasSource()) {\r\n      var ps = this.getPossibleSquares()\r\n      var rows = this.rowPrompts()\r\n      var cols = this.colPrompts()\r\n\r\n      console.log('rowPrompts', rows)\r\n      \r\n      console.log('colPrompts', cols)\r\n\r\n\r\n      ps.forEach(function(p){\r\n        var um = (p.row === _this.selectedSourceRow || !rows || rows[p.row]) \r\n                  && (p.col === _this.selectedSourceCol || !cols || cols[p.col])\r\n        if (um && p.moves.length) {\r\n          r[p.row][p.col] = ''\r\n        }\r\n      })\r\n      \r\n      console.log('Using source mask:', r, ps, rows, cols)\r\n    } else if (!this.hasTarget()) {\r\n      var ps = this.getPossibleTargetsForSource(this.selectedSourceRow,this.selectedSourceCol)\r\n      var rows = this.rowPrompts()\r\n      var cols = this.colPrompts()\r\n\r\n      ps.forEach(function(p){\r\n        var um = (p.row === _this.selectedTargetRow || !rows || rows[p.row]) \r\n                  && (p.col === _this.selectedTargetCol || !cols || cols[p.col])\r\n        if (um) r[p.row][p.col] = ''\r\n      })\r\n\r\n      console.log('Using target mask:', r, ps)\r\n      r[this.selectedSourceRow][this.selectedSourceCol] = 'h'\r\n      \r\n    } else {\r\n      console.log('Using computer move mask:', r, ps)\r\n    }\r\n    return r\r\n  }\r\n\r\n  P4WN.prototype.clearSource = function() {\r\n    this.selectedSourceRow = undefined\r\n    this.selectedSourceCol = undefined\r\n    this.clearTarget()\r\n  }\r\n\r\n  P4WN.prototype.clearTarget = function() {\r\n    this.selectedTargetRow = undefined\r\n    this.selectedTargetCol = undefined\r\n    this.isAutoTargetRow = false\r\n    this.isAutoTargetCol = false\r\n  }\r\n\r\n  P4WN.prototype.setSource = function(row, col) {\r\n    if (!this.isPlayerTurn()) return \r\n    this.selectedSourceRow = ((parseInt(row) === row) ? row : this.selectedSourceRow)\r\n    this.selectedSourceCol = ((parseInt(col) === col) ? col : this.selectedSourceCol)\r\n  }\r\n\r\n  P4WN.prototype.setTarget = function(row, col) {\r\n    if (!this.isPlayerTurn()) return \r\n    this.selectedTargetRow = ((parseInt(row) === row) ? row : this.selectedTargetRow)\r\n    this.selectedTargetCol = ((parseInt(col) === col) ? col : this.selectedTargetCol)\r\n    if (this.hasSource() && this.hasTarget()) {\r\n      var ssquare = toSquare(this.selectedSourceRow, this.selectedSourceCol)\r\n      var tsquare = toSquare(this.selectedTargetRow, this.selectedTargetCol)\r\n      console.log('Moving:', this.selectedSourceRow, this.selectedSourceCol, ssquare, 'to', this.selectedTargetRow, this.selectedTargetCol, tsquare)\r\n      this.clearSource()\r\n      var moveResult = this.move(ssquare, tsquare)\r\n      return moveResult.ok\r\n    }\r\n  }\r\n\r\n  P4WN.prototype.hasSource = function() {\r\n    if (!this.isPlayerTurn()) {\r\n      return false\r\n    } \r\n    if (!isNaN(this.selectedSourceCol) && !isNaN(this.selectedSourceRow)) {\r\n      return true\r\n    }\r\n    return false\r\n  }\r\n\r\n  \r\n\r\n  P4WN.prototype.hasSourceCol = function() {\r\n    if (!this.isPlayerTurn()) {\r\n      return false\r\n    } \r\n    if (!isNaN(this.selectedSourceCol)) {\r\n      return true\r\n    }\r\n    return false\r\n  }\r\n\r\n  P4WN.prototype.hasSourceRow = function() {\r\n    if (!this.isPlayerTurn()) {\r\n      return false\r\n    } \r\n    if (!isNaN(this.selectedSourceRow)) {\r\n      return true\r\n    }\r\n    return false\r\n  }\r\n\r\n  P4WN.prototype.hasTarget = function() {\r\n    if (!this.isPlayerTurn()) {\r\n      return false\r\n    } \r\n    if (!isNaN(this.selectedTargetCol) && !isNaN(this.selectedTargetRow)) {\r\n      return true\r\n    }\r\n    return false\r\n  }\r\n\r\n  P4WN.prototype.hasTargetRow = function() {\r\n    if (!this.isPlayerTurn()) {\r\n      return false\r\n    } \r\n    if (!isNaN(this.selectedTargetRow)) {\r\n      return true\r\n    }\r\n    return false\r\n  }\r\n\r\n  P4WN.prototype.hasTargetCol = function() {\r\n    if (!this.isPlayerTurn()) {\r\n      return false\r\n    } \r\n    if (!isNaN(this.selectedTargetCol)) {\r\n      return true\r\n    }\r\n    return false\r\n  }\r\n\r\n  P4WN.prototype.colPrompts = function() {\r\n    if (!this.isPlayerTurn()) {\r\n      return false\r\n    } else if (isNaN(this.selectedSourceCol) || isNaN(this.selectedSourceRow)) {\r\n      return this.getPossibleSourceCols()\r\n    } else if (isNaN(this.selectedTargetCol) || isNaN(this.selectedTargetRow)) {\r\n      return this.getPossibleTargetCols()\r\n    }\r\n    return false\r\n  }\r\n\r\n  P4WN.prototype.rowPrompts = function() {\r\n    if (!this.isPlayerTurn()) {\r\n      return false\r\n    } else if (isNaN(this.selectedSourceCol) || isNaN(this.selectedSourceRow)) {\r\n      return this.getPossibleSourceRows()\r\n    } else if (isNaN(this.selectedTargetRow) || isNaN(this.selectedTargetCol)) {\r\n      return this.getPossibleTargetRows()\r\n    }\r\n    return false\r\n  }\r\n\r\n  P4WN.prototype.getPossibleTargetsForSource = function(ssr, ssc){\r\n    this._ptc = this._ptc || {}\r\n    var ssquare = toSquare(ssr, ssc)\r\n    \/\/ console.log('Checking moves for square', ssquare)\r\n    \/\/ var stateFen = p4_state2fen(this.board_state, false)\r\n    \/\/ var state = p4_fen2state(stateFen, undefined)\r\n    var state = this.board_state\r\n    var board = state.board\r\n    var spiece = board[ssquare]\r\n    var stype = P4_PIECE_LUT_R[spiece]\r\n    \/\/ var p = P4WN_PROMOTION_INTS[this.pawn_becomes]\r\n    var stype = P4_PIECE_LUT_R[spiece]\r\n    if (!stype) return [] \r\n    var mover = state.to_play\r\n    var ck = ([ssquare,mover,JSON.stringify(board)]).join(':')\r\n    var r = this._ptc[ck]\r\n    if (r) {\r\n      \/\/ console.log('Targets for source', ssr, ssc, ssquare, r)\r\n      return r\r\n    }\r\n    r = []\r\n    state.prepare()\r\n    var pieces = [[spiece,ssquare]]\r\n    var promotion = P4WN_PROMOTION_INTS[this.pawn_becomes]\r\n    var moves = state.parse(mover, state.enpassant, 0, pieces);\r\n    for (i = 0; i < moves.length; i++){\r\n      var tsquare = moves[i][2]\r\n      var changes = p4_make_move(state, ssquare, tsquare, promotion);\r\n      \/\/ if(!colour) console.warn('Player move changes:', e, s, E, S, changes)\r\n\r\n      \/*is it check? *\/\r\n      if (p4_check_check(state, mover)){\r\n          p4_unmake_move(state, changes);\r\n          continue;\r\n      }\r\n      p4_unmake_move(state, changes);\r\n      \/\/ if (check_only) {\r\n      \/\/     p4_unmake_move(state, changes);\r\n      \/\/     return {flags: P4_MOVE_FLAG_OK, ok: true, string: \"valid\"};\r\n      \/\/ }\r\n      var rowCol = toRowCol(tsquare)\r\n      if (tsquare !== ssquare) {\r\n        var capture = board[tsquare]\r\n        \/\/ console.log('move for square:', tsquare)\r\n        r.push({\r\n          mover: mover,\r\n          row: rowCol[0],\r\n          col: rowCol[1],\r\n          square: tsquare,\r\n          type: stype,\r\n          piece: spiece,\r\n          capture: capture,\r\n          captureType: P4_PIECE_LUT_R[capture],\r\n        })\r\n      }\r\n    }\r\n\r\n    this._ptc[ck] = r\r\n    \/\/ console.log('Targets for source', ssr, ssc, ssquare, r)\r\n    return r\r\n  }\r\n\r\n  P4WN.prototype.getPossibleTargetCols = function(){\r\n    var ssr = this.selectedSourceRow\r\n    var ssc = this.selectedSourceCol\r\n    var str = this.selectedTargetRow\r\n    var stc = this.selectedTargetCol\r\n    return this.getPossibleTargetsForSource(ssr, ssc).reduce(function(r, s){\r\n      if ((stc === undefined || stc === s.col) && \r\n        (str === undefined || str === s.row)) {\r\n          r[s.col] = s\r\n      }\r\n      return r\r\n    },{})\r\n  }\r\n\r\n  P4WN.prototype.getPossibleTargetRows = function(){\r\n    var ssr = this.selectedSourceRow\r\n    var ssc = this.selectedSourceCol\r\n    var str = this.selectedTargetRow\r\n    var stc = this.selectedTargetCol\r\n    return this.getPossibleTargetsForSource(ssr, ssc).reduce(function(r, s){\r\n      if ((stc === undefined || stc === s.col) && \r\n        (str === undefined || str === s.row)) {\r\n          r[s.row] = s\r\n      }\r\n      return r\r\n    },{})\r\n  }\r\n\r\n  P4WN.prototype.getPossibleSourceCols = function(){\r\n    var ssr = this.selectedSourceRow\r\n    var ssc = this.selectedSourceCol\r\n    return this.getPossibleSquares().reduce(function(r,s){\r\n      if (\r\n        !s.moves.length ||\r\n        (ssr !== undefined && s.row !== ssr) ||\r\n        (ssc !== undefined && s.col !== ssc)\r\n        ) {\r\n        return r\r\n      }\r\n      var p = r[s.col] || []\r\n      p.push(s)\r\n      r[s.col] = p\r\n      return r\r\n    },{})\r\n  }\r\n\r\n  P4WN.prototype.getPossibleSourceRows = function(){\r\n    var ssr = this.selectedSourceRow\r\n    var ssc = this.selectedSourceCol\r\n    return this.getPossibleSquares().reduce(function(r,s){\r\n      if (\r\n        !s.moves.length ||\r\n        (ssr !== undefined && s.row !== ssr) ||\r\n        (ssc !== undefined && s.col !== ssc)\r\n       ) {\r\n        return r\r\n      }\r\n      var p = r[s.row] || []\r\n      p.push(s)\r\n      r[s.row] = p\r\n      return r\r\n    },{})\r\n  }\r\n\r\n  P4WN.prototype.getPossibleSquares = function(){\r\n\r\n    var r = []\r\n    var state = this.board_state\r\n    var board = state.board\r\n    var mover = state.to_play\r\n    this._psc = this._psc || {}\r\n    var ck = ([mover,JSON.stringify(board)]).join(':')\r\n    if (this._psc[ck]) return this._psc[ck]\r\n    state.prepare()\r\n    var pieces = state.pieces[mover]\r\n    var st = Date.now()\r\n    \/\/ [[spiece,ssquare]]\r\n    for (var i = 0, l = pieces.length; i < l; i++) {\r\n      var p = pieces[i]\r\n      var square = p[1]\r\n      var piece = board[square]\r\n      var rowCol = toRowCol(square)\r\n      if (piece){\r\n        r.push({\r\n          mover: mover,\r\n          row: rowCol[0],\r\n          col: rowCol[1],\r\n          square: square,\r\n          type: P4_PIECE_LUT_R[piece],\r\n          piece: piece,\r\n          moves: this.getPossibleTargetsForSource(rowCol[0], rowCol[1]),\r\n        })\r\n      }\r\n    }\r\n    console.warn('Calc all player moves in:', (Date.now() - st) \/ 1000, 'sec.') \r\n    this._psc[ck] = r\r\n    console.log('Player sqaures', r)\r\n    return r\r\n  }\r\n\r\n  P4WN.prototype.getFlatBoard = function(){\r\n\r\n    var r = []\r\n    var state = this.board_state\r\n    var board = state.board\r\n    \r\n    for (var row = 7; row>=0; row--) {\r\n      for (var col = 0; col<8; col++) {\r\n        var square = toSquare(row, col)\r\n        var piece = board[square]\r\n        var c = r[row] || []\r\n        r[row] = c\r\n        c[col] = P4_PIECE_LUT_R[piece] || ''\r\n      }\r\n    }\r\n    return r\r\n  }\r\n\r\n  P4WN.prototype.isPlayerTurn = function() {\r\n    return this.players[this.board_state.to_play] == 'human'\r\n  }\r\n\r\n  P4WN.prototype.computerMove = function(opts){\r\n      this.auto_play_timeout = undefined;\r\n      var state = this.board_state;\r\n      var mv;\r\n      var depth = this.computer_level + 1;\r\n      var start_time = Date.now();\r\n      console.log('finding move', opts)\r\n      mv = state.findmove(depth, opts);\r\n      var delta = Date.now() - start_time;\r\n      console.warn(\"computerMove took\", delta\/1000, 'sec.');\r\n      \/\/ if (P4WN_ADAPTIVE_LEVELS && depth > 2){\r\n      \/\/     var min_time = 25 * depth;\r\n      \/\/     while (delta < min_time){\r\n      \/\/         depth++;\r\n      \/\/         mv = state.findmove(depth);\r\n      \/\/         delta = Date.now() - start_time;\r\n      \/\/         p4_log(\"retry at depth\", depth, \" total time:\", delta);\r\n      \/\/     }\r\n      \/\/ }\r\n      if (mv.needMore) {\r\n        return mv\r\n      }\r\n      this.move(mv[0], mv[1]);\r\n  }\r\n\r\n  P4WN.prototype.getFen = function(reduced) {\r\n    return p4_state2fen(this.board_state, reduced)\r\n  }\r\n\r\n  P4WN.prototype.getPlayState = function(reduced) {\r\n    return [\r\n      p4_state2fen(this.board_state, reduced),\r\n      this.playerCapture,\r\n      this.computerCapture,\r\n      this.lastMove,\r\n      this.moveCount,\r\n      this.computer_level,\r\n      this.players[1] === 'human',\r\n    ]\r\n  }\r\n\r\n  P4WN.prototype.setPlayState = function(playState) {\r\n    this.board_state = p4_fen2state(playState[0])\r\n    this.playerCapture = playState[1]\r\n    this.computerCapture = playState[2]\r\n    this.lastMove = playState[3]\r\n    this.moveCount = playState[4]\r\n    this.computer_level = playState[5]\r\n    if (playState[6]) this.setComputerFirst()\r\n  }\r\n\r\n  P4WN.prototype.move = function(start, end){\r\n    console.log('Doing move', start, end, promotion)\r\n      var state = this.board_state;\r\n      var promotion = P4WN_PROMOTION_INTS[this.pawn_becomes]\r\n      var isPlayer = this.isPlayerTurn()\r\n      \r\n      \r\n      var moveResult = state.move(start, end, promotion);\r\n      if(moveResult.ok){\r\n        \/\/ moveResult.start = start\r\n          \/\/ this.display_move_text(state.moveno, move_result.string);\r\n          \/\/ this.refresh();\r\n          \/\/ if (! (move_result.flags & P4_MOVE_FLAG_MATE)){\r\n          \/\/     \/\/ this.next_move_timeout = window.setTimeout(\r\n          \/\/     \/\/     function(p4d){\r\n          \/\/     \/\/         return function(){\r\n          \/\/     \/\/             p4d.next_move();\r\n          \/\/     \/\/         };\r\n          \/\/     \/\/     }(this), 1);\r\n          \/\/ }\r\n          \/\/ console.log('Setting last move')\r\n          \/\/ this.lastMove = moveResult\r\n          p4_log(\"Good move!\", start, end);\r\n      } else {\r\n          p4_log(\"bad move!\", start, end);\r\n      }\r\n      moveResult.start = start\r\n      console.warn('Setting last move', isPlayer?\"Player\":\"Computer\", isPlayer, moveResult)\r\n      this.lastMove = moveResult\r\n      \/\/ for (var i = 0; i < this.move_listeners.length; i++){\r\n      \/\/     this.move_listeners[i](move_result);\r\n      \/\/ }\r\n      if (isPlayer) {\r\n        if (this.lastMove.capture) this.playerCapture += this.lastMove.capture\r\n      } else {\r\n        this.moveCount++\r\n        if (this.lastMove.capture) this.computerCapture += this.lastMove.capture       \r\n      }\r\n      return moveResult;\r\n  };\r\n\r\n  \/* The pieces are stored as numbers between 2 and 13, inclusive.\r\n  * Empty squares are stored as 0, and off-board squares as 16.\r\n  * There is some bitwise logic to it:\r\n  *  piece & 1 -> colour (white: 0, black: 1)\r\n  *  piece & 2 -> single move piece (including pawn)\r\n  *  if (piece & 2) == 0:\r\n  *     piece & 4  -> row and column moves\r\n  *     piece & 8  -> diagonal moves\r\n  *\/\r\n  \r\n  var P4_PAWN = 2, P4_ROOK = 4, P4_KNIGHT = 6, P4_BISHOP = 8, P4_QUEEN = 12, P4_KING = 10;\r\n  var P4_EDGE = 16;\r\n\r\n  \/* in order, even indices: <nothing>, pawn, rook, knight, bishop, king, queen. Only the\r\n  * even indices are used.*\/\r\n  var P4_MOVES = [[], [],\r\n                  [], [],\r\n                  [1,10,-1,-10], [], \/\/ pawn\r\n                  [21,19,12,8,-21,-19,-12,-8], [], \/\/ rook\r\n                  [11,9,-11,-9], [], \/\/ knight\r\n                  [1,10,11,9,-1,-10,-11,-9], [], \/\/ bishop\r\n                  [1,10,11,9,-1,-10,-11,-9], [] \/\/king\r\n                ];\r\n  var P4WN_LEVELS = ['stupid', 'middling', 'smart', 'expert', 'master'];\r\n  var P4WN_DEFAULT_LEVEL = 2; \/\/ smart\r\n  var P4WN_ADAPTIVE_LEVELS = false;\r\n  \r\n  \/*the next two should match*\/\r\n  var P4WN_PROMOTION_STRINGS = ['queen', 'rook', 'knight', 'bishop'];\r\n  var P4WN_PROMOTION_INTS = [P4_QUEEN, P4_ROOK, P4_KNIGHT, P4_BISHOP];\r\n\r\n  \/*P4_VALUES defines the relative value of various pieces.\r\n  *\r\n  * It follows the 1,3,3,5,9 pattern you learn as a kid, multiplied by\r\n  * 20 to give sub-pawn resolution to other factors, with bishops given\r\n  * a wee boost over knights.\r\n  *\/\r\n  var P4_VALUES=[0, 0,      \/\/Piece values\r\n                20, 20,    \/\/pawns\r\n                100, 100,  \/\/rooks\r\n                60, 60,    \/\/knights\r\n                61, 61,    \/\/bishops\r\n                8000, 8000,\/\/kings\r\n                180, 180,  \/\/queens\r\n                0];\r\n\r\n  \/* A score greater than P4_WIN indicates a king has been taken. It is\r\n  * less than the value of a king, in case someone finds a way to, say,\r\n  * sacrifice two queens in order to checkmate.\r\n  *\/\r\n  var P4_KING_VALUE = P4_VALUES[10];\r\n  var P4_WIN = P4_KING_VALUE >> 1;\r\n\r\n  \/* every move, a winning score decreases by this much *\/\r\n  var P4_WIN_DECAY = 300;\r\n  var P4_WIN_NOW = P4_KING_VALUE - 250;\r\n\r\n  \/* P4_{MAX,MIN}_SCORE should be beyond any possible evaluated score *\/\r\n\r\n  var P4_MAX_SCORE = 9999;    \/\/ extremes of evaluation range\r\n  var P4_MIN_SCORE = -P4_MAX_SCORE;\r\n\r\n  \/*initialised in p4_initialise_state *\/\r\n  var P4_CENTRALISING_WEIGHTS;\r\n  var P4_BASE_PAWN_WEIGHTS;\r\n  var P4_KNIGHT_WEIGHTS;\r\n\r\n  \/*P4_DEBUG turns on debugging features *\/\r\n  var P4_DEBUG = 0;\r\n  var P4_INITIAL_BOARD = \"rnbqkbnr\/pppppppp\/8\/8\/8\/8\/PPPPPPPP\/RNBQKBNR w KQkq - 1 1\";\r\n  \/\/ var P4_INITIAL_BOARD = \"rnbqkbnr\/pppppppp\/8\/8\/8\/8\/PPPPPPPP\/RNBQKBNR w KQkq - 0 1\";\r\n\r\n  \/*use javascript typed arrays rather than plain arrays\r\n  * (faster in some browsers, unsupported in others, possibly slower elsewhere) *\/\r\n  var P4_USE_TYPED_ARRAYS = this.Int32Array !== undefined;\r\n\r\n  var P4_PIECE_LUT = { \/*for FEN, PGN interpretation *\/\r\n      P: 2,\r\n      p: 3,\r\n      R: 4,\r\n      r: 5,\r\n      N: 6,\r\n      n: 7,\r\n      B: 8,\r\n      b: 9,\r\n      K: 10,\r\n      k: 11,\r\n      Q: 12,\r\n      q: 13\r\n  };\r\n\r\n  var P4_ENCODE_LUT = '  PPRRNNBBKKQQ';\r\n\r\n  var P4_PIECE_LUT_R = Object.keys(P4_PIECE_LUT).reduce(function(r,k){\r\n    r[P4_PIECE_LUT[k]] = k\r\n    return r\r\n  },{})\r\n\r\n  function p4_alphabeta_treeclimber(state, count, colour, score, s, e, alpha, beta){\r\n      var move = p4_make_move(state, s, e, P4_QUEEN);\r\n      var i;\r\n      var ncolour = 1 - colour;\r\n      var movelist = p4_parse(state, colour, move.ep, -score);\r\n      var movecount = movelist.length;\r\n      if(count){\r\n          \/\/branch nodes\r\n          var t;\r\n          for(i = 0; i < movecount; i++){\r\n              var mv = movelist[i];\r\n              var mscore = mv[0];\r\n              var ms = mv[1];\r\n              var me = mv[2];\r\n              if (mscore > P4_WIN){ \/\/we won! Don't look further.\r\n                  alpha = P4_KING_VALUE;\r\n                  break;\r\n              }\r\n              t = -p4_alphabeta_treeclimber(state, count - 1, ncolour, mscore, ms, me,\r\n                                            -beta, -alpha);\r\n              if (t > alpha){\r\n                  alpha = t;\r\n              }\r\n              if (alpha >= beta){\r\n                  break;\r\n              }\r\n          }\r\n          if (alpha < -P4_WIN_NOW && ! p4_check_check(state, colour)){\r\n              \/* Whatever we do, we lose the king.\r\n              * But if it is not check then this is stalemate, and the\r\n              * score doesn't apply.\r\n              *\/\r\n              alpha = state.stalemate_scores[colour];\r\n          }\r\n          if (alpha < -P4_WIN){\r\n              \/*make distant checkmate seem less bad *\/\r\n              alpha += P4_WIN_DECAY;\r\n          }\r\n      }\r\n      else{\r\n          \/\/leaf nodes\r\n          while(beta > alpha && --movecount != -1){\r\n              if(movelist[movecount][0] > alpha){\r\n                  alpha = movelist[movecount][0];\r\n              }\r\n          }\r\n      }\r\n      p4_unmake_move(state, move);\r\n      return alpha;\r\n  }\r\n\r\n  \/* p4_prepare() works out weightings for assessing various moves,\r\n  * favouring centralising moves early, for example.\r\n  *\r\n  * It is called before each tree search, not for each parse(), so it\r\n  * is OK for it to be a little bit slow. But that also means it drifts\r\n  * out of sync with the real board state, especially on deep searches.\r\n  *\/\r\n\r\n  function p4_prepare(state){\r\n      var i, j, x, y, a;\r\n      var pieces = state.pieces = [[], []];\r\n      \/*convert state.moveno half move count to move cycle count *\/\r\n      var moveno = state.moveno >> 1;\r\n      var board = state.board;\r\n\r\n      \/* high earliness_weight indicates a low move number. The formula\r\n      * should work above moveno == 50, but this is javascript.\r\n      *\/\r\n      var earliness_weight = (moveno > 50) ? 0 : parseInt(6 * Math.exp(moveno * -0.07));\r\n      var king_should_hide = moveno < 12;\r\n      var early = moveno < 5;\r\n      \/* find the pieces, kings, and weigh material*\/\r\n      var kings = [0, 0];\r\n      var material = [0, 0];\r\n      var best_pieces = [0, 0];\r\n      for(i = 20; i  < 100; i++){\r\n          a = board[i];\r\n          var piece = a & 14;\r\n          var colour = a & 1;\r\n          if(piece){\r\n              pieces[colour].push([a, i]);\r\n              if (piece == P4_KING){\r\n                  kings[colour] = i;\r\n              }\r\n              else{\r\n                  material[colour] += P4_VALUES[piece];\r\n                  best_pieces[colour] = Math.max(best_pieces[colour], P4_VALUES[piece]);\r\n              }\r\n          }\r\n      }\r\n\r\n      \/*does a draw seem likely soon?*\/\r\n      var draw_likely = (state.draw_timeout > 90 || state.current_repetitions >= 2);\r\n      \/\/ if (draw_likely)\r\n      \/\/     p4_log(\"draw likely\", state.current_repetitions, state.draw_timeout);\r\n      state.values = [[], []];\r\n      var qvalue = P4_VALUES[P4_QUEEN]; \/*used as ballast in various ratios*\/\r\n      var material_sum = material[0] + material[1] + 2 * qvalue;\r\n      var wmul = 2 * (material[1] + qvalue) \/ material_sum;\r\n      var bmul = 2 * (material[0] + qvalue) \/ material_sum;\r\n      var multipliers = [wmul, bmul];\r\n      var emptiness = 4 * P4_QUEEN \/ material_sum;\r\n      state.stalemate_scores = [parseInt(0.5 + (wmul - 1) * 2 * qvalue),\r\n                                parseInt(0.5 + (bmul - 1) * 2 * qvalue)];\r\n      \/\/p4_log(\"value multipliers (W, B):\", wmul, bmul,\r\n      \/\/       \"stalemate scores\", state.stalemate_scores);\r\n      for (i = 0; i < P4_VALUES.length; i++){\r\n          var v = P4_VALUES[i];\r\n          if (v < P4_WIN){\/\/i.e., not king\r\n              state.values[0][i] = parseInt(v * wmul + 0.5);\r\n              state.values[1][i] = parseInt(v * bmul + 0.5);\r\n          }\r\n          else {\r\n              state.values[0][i] = v;\r\n              state.values[1][i] = v;\r\n          }\r\n      }\r\n      \/*used for pruning quiescence search *\/\r\n      state.best_pieces = [parseInt(best_pieces[0] * wmul + 0.5),\r\n                          parseInt(best_pieces[1] * bmul + 0.5)];\r\n\r\n      var kx = [kings[0] % 10, kings[1] % 10];\r\n      var ky = [parseInt(kings[0] \/ 10), parseInt(kings[1] \/ 10)];\r\n\r\n      \/* find the frontmost pawns in each file *\/\r\n      var pawn_cols = [[], []];\r\n      for (y = 3; y < 9; y++){\r\n          for (x = 1; x < 9; x++){\r\n              i = y * 10 + x;\r\n              a = board[i];\r\n              if ((a & 14) != P4_PAWN)\r\n                  continue;\r\n              if ((a & 1) == 0){\r\n                  pawn_cols[0][x] = y;\r\n              }\r\n              else if (pawn_cols[1][x] === undefined){\r\n                  pawn_cols[1][x] = y;\r\n              }\r\n          }\r\n      }\r\n      var target_king = (moveno >= 20 || material_sum < 5 * qvalue);\r\n      var weights = state.weights;\r\n\r\n      for (y = 2; y < 10; y++){\r\n          for (x = 1; x < 9; x++){\r\n              i = y * 10 + x;\r\n              var early_centre = P4_CENTRALISING_WEIGHTS[i] * earliness_weight;\r\n              var plateau = P4_KNIGHT_WEIGHTS[i];\r\n              for (var c = 0; c < 2; c++){\r\n                  var dx = Math.abs(kx[1 - c] - x);\r\n                  var dy = Math.abs(ky[1 - c] - y);\r\n                  var our_dx = Math.abs(kx[c] - x);\r\n                  var our_dy = Math.abs(ky[c] - y);\r\n\r\n                  var d = Math.max(Math.sqrt(dx * dx + dy * dy), 1) + 1;\r\n                  var mul = multipliers[c]; \/*(mul < 1) <==> we're winning*\/\r\n                  var mul3 = mul * mul * mul;\r\n                  var at_home = y == 2 + c * 7;\r\n                  var pawn_home = y == 3 + c * 5;\r\n                  var row4 = y == 5 + c;\r\n                  var promotion_row = y == 9 - c * 7;\r\n                  var get_out = (early && at_home) * -5;\r\n\r\n                  var knight = parseInt(early_centre * 0.3) + 2 * plateau + get_out;\r\n                  var rook = parseInt(early_centre * 0.3);\r\n                  var bishop = parseInt(early_centre * 0.6) + plateau + get_out;\r\n                  if (at_home){\r\n                      rook += (x == 4 || x == 5) * (earliness_weight + ! target_king);\r\n                      rook += (x == 1 || x == 8) * (moveno > 10 && moveno < 20) * -3;\r\n                      rook += (x == 2 || x == 7) * (moveno > 10 && moveno < 20) * -1;\r\n                  }\r\n\r\n                  \/*Queen wants to stay home early, then jump right in*\/\r\n                  \/*keep kings back on home row for a while*\/\r\n                  var queen = parseInt(plateau * 0.5 + early_centre * (0.5 - early));\r\n                  var king = (king_should_hide && at_home) * 2 * earliness_weight;\r\n\r\n                  \/*empty board means pawn advancement is more urgent*\/\r\n                  var get_on_with_it = Math.max(emptiness * 2, 1);\r\n                  var pawn = get_on_with_it * P4_BASE_PAWN_WEIGHTS[c ? 119 - i : i];\r\n                  if (early){\r\n                      \/* Early pawn weights are slightly randomised, so each game is different.\r\n                      *\/\r\n                      if (y >= 4 && y <= 7){\r\n                          var boost = 1 + 3 * (y == 5 || y == 6);\r\n                          pawn += parseInt((boost + p4_random_int(state, 4)) * 0.1 *\r\n                                          early_centre);\r\n                      }\r\n                      if (x == 4 || x == 5){\r\n                          \/\/discourage middle pawns from waiting at home\r\n                          pawn -= 3 * pawn_home;\r\n                          pawn += 3 * row4;\r\n                      }\r\n                  }\r\n                  \/*pawn promotion row is weighted as a queen minus a pawn.*\/\r\n                  if (promotion_row)\r\n                      pawn += state.values[c][P4_QUEEN] - state.values[c][P4_PAWN];\r\n\r\n                  \/*pawns in front of a castled king should stay there*\/\r\n                  pawn += 4 * (y == 3 && ky[c] == 2 && Math.abs(our_dx) < 2 &&\r\n                              kx[c] != 5 && x != 4 && x != 5);\r\n                  \/*passed pawns (having no opposing pawn in front) are encouraged. *\/\r\n                  var cols = pawn_cols[1 - c];\r\n                  if (cols[x] == undefined ||\r\n                      (c == 0 && cols[x] < y) ||\r\n                      (c == 1 && cols[x] > y))\r\n                      pawn += 2;\r\n\r\n                  \/* After a while, start going for opposite king. Just\r\n                  * attract pieces into the area so they can mill about in\r\n                  * the area, waiting for an opportunity.\r\n                  *\r\n                  * As prepare is only called at the beginning of each tree\r\n                  * search, the king could wander out of the targetted area\r\n                  * in deep searches. But that's OK. Heuristics are\r\n                  * heuristics.\r\n                  *\/\r\n                  if (target_king){\r\n                      knight += 2 * parseInt(8 * mul \/ d);\r\n                      rook += 2 * ((dx < 2) + (dy < 2));\r\n                      bishop += 3 * (Math.abs((dx - dy))  < 2);\r\n                      queen += 2 * parseInt(8 \/ d) + (dx * dy == 0) + (dx - dy == 0);\r\n                      \/* The losing king wants to stay in the middle, while\r\n                      the winning king goes in for the kill.*\/\r\n                      var king_centre_wt = 8 * emptiness * P4_CENTRALISING_WEIGHTS[i];\r\n                      king += parseInt(150 * emptiness \/ (mul3 * d) + king_centre_wt * mul3);\r\n                  }\r\n                  weights[P4_PAWN + c][i] = pawn;\r\n                  weights[P4_KNIGHT + c][i] = knight;\r\n                  weights[P4_ROOK + c][i] = rook;\r\n                  weights[P4_BISHOP + c][i] = bishop;\r\n                  weights[P4_QUEEN + c][i] = queen;\r\n                  weights[P4_KING + c][i] = king;\r\n\r\n                  if (draw_likely && mul < 1){\r\n                      \/*The winning side wants to avoid draw, so adds jitter to its weights.*\/\r\n                      var range = 3 \/ mul3;\r\n                      for (j = 2 + c; j < 14; j += 2){\r\n                          weights[j][i] += p4_random_int(state, range);\r\n                      }\r\n                  }\r\n              }\r\n          }\r\n      }\r\n      state.prepared = true;\r\n  }\r\n\r\n  function p4_maybe_prepare(state){\r\n      if (! state.prepared)\r\n          p4_prepare(state);\r\n  }\r\n\r\n\r\n  function p4_parse(state, colour, ep, score, pieces) {\r\n      var board = state.board;\r\n      var s, e;    \/\/start and end position\r\n      var E, a;       \/\/E=piece at end place, a= piece moving\r\n      var i, j;\r\n      var other_colour = 1 - colour;\r\n      var dir = (10 - 20 * colour); \/\/dir= 10 for white, -10 for black\r\n      var movelist = [];\r\n      var captures = [];\r\n      var weight;\r\n      pieces = pieces || state.pieces[colour];\r\n      var castle_flags = (state.castles >> (colour * 2)) & 3;\r\n      var values = state.values[other_colour];\r\n      var all_weights = state.weights;\r\n      for (j = pieces.length - 1; j >= 0; j--){\r\n          s = pieces[j][1]; \/\/ board position\r\n          a = board[s]; \/\/piece number\r\n          var weight_lut = all_weights[a];\r\n          weight = score - weight_lut[s];\r\n          a &= 14;\r\n          if(a > 2){    \/\/non-pawns\r\n              var moves = P4_MOVES[a];\r\n              if(a & 2){\r\n                  for(i = 0; i < 8; i++){\r\n                      e = s + moves[i];\r\n                      E = board[e];\r\n                      if(!E){\r\n                          movelist.push([weight + values[E] + weight_lut[e], s, e]);\r\n                      }\r\n                      else if((E&17)==other_colour){\r\n                          captures.push([weight + values[E] + weight_lut[e] + all_weights[E][e], s, e]);\r\n                      }\r\n                  }\r\n                  if(a == P4_KING && castle_flags){\r\n                      if((castle_flags & 1) &&\r\n                          (board[s - 1] + board[s - 2] + board[s - 3] == 0) &&\r\n                          p4_check_castling(board, s - 2, other_colour, dir, -1)){\/\/Q side\r\n                          movelist.push([weight + 12, s, s - 2]);     \/\/no analysis, just encouragement\r\n                      }\r\n                      if((castle_flags & 2) && (board[s + 1] + board[s + 2] == 0) &&\r\n                          p4_check_castling(board, s, other_colour, dir, 1)){\/\/K side\r\n                          movelist.push([weight + 13, s, s + 2]);\r\n                      }\r\n                  }\r\n              }\r\n              else{\/\/rook, bishop, queen\r\n                  var mlen = moves.length;\r\n                  for(i=0;i<mlen;){     \/\/goeth thru list of moves\r\n                      var m = moves[i++];\r\n                      e=s;\r\n                      do {\r\n                          e+=m;\r\n                          E=board[e];\r\n                          if(!E){\r\n                              movelist.push([weight + values[E] + weight_lut[e], s, e]);\r\n                          }\r\n                          else if((E&17)==other_colour){\r\n                              captures.push([weight + values[E] + weight_lut[e] + all_weights[E][e], s, e]);\r\n                          }\r\n                      }while(!E);\r\n                  }\r\n              }\r\n          }\r\n          else{    \/\/pawns\r\n              e=s+dir;\r\n              if(!board[e]){\r\n                  movelist.push([weight + weight_lut[e], s, e]);\r\n                  \/* s * (120 - s) < 3200 true for outer two rows on either side.*\/\r\n                  var e2 = e + dir;\r\n                  if(s * (120 - s) < 3200 && (!board[e2])){\r\n                      movelist.push([weight + weight_lut[e2], s, e2]);\r\n                  }\r\n              }\r\n              \/* +\/-1 for pawn capturing *\/\r\n              E = board[--e];\r\n              if(E && (E & 17) == other_colour){\r\n                  captures.push([weight + values[E] + weight_lut[e] + all_weights[E][e], s, e]);\r\n              }\r\n              e += 2;\r\n              E = board[e];\r\n              if(E && (E & 17) == other_colour){\r\n                  captures.push([weight + values[E] + weight_lut[e] + all_weights[E][e], s, e]);\r\n              }\r\n          }\r\n      }\r\n      if(ep){\r\n          var pawn = P4_PAWN | colour;\r\n          var taken;\r\n          \/* Some repetitive calculation here could be hoisted out, but that would\r\n              probably slow things: the common case is no pawns waiting to capture\r\n              enpassant, not 2.\r\n          *\/\r\n          s = ep - dir - 1;\r\n          if (board[s] == pawn){\r\n              taken = values[P4_PAWN] + all_weights[P4_PAWN | other_colour][ep - dir];\r\n              captures.push([score - weight_lut[s] + weight_lut[ep] + taken, s, ep]);\r\n          }\r\n          s += 2;\r\n          if (board[s] == pawn){\r\n              taken = values[P4_PAWN] + all_weights[P4_PAWN | other_colour][ep - dir];\r\n              captures.push([score - weight_lut[s] + weight_lut[ep] + taken, s, ep]);\r\n          }\r\n      }\r\n      return captures.concat(movelist);\r\n  }\r\n\r\n  \/*Explaining the bit tricks used in check_castling and check_check:\r\n  *\r\n  * in binary:    16 8 4 2 1\r\n  *   empty\r\n  *   pawn               1 c\r\n  *   rook             1   c\r\n  *   knight           1 1 c\r\n  *   bishop         1     c\r\n  *   king           1   1 c\r\n  *   queen          1 1   c\r\n  *   wall         1\r\n  *\r\n  * so:\r\n  *\r\n  * piece & (16 | 4 | 2 | 1) is:\r\n  *  2 + c  for kings and pawns\r\n  *  4 + c  for rooks and queens\r\n  *  6 + c  for knights\r\n  *  0 + c  for bishops\r\n  * 16      for walls\r\n  *\r\n  * thus:\r\n  * ((piece & 23) == 4 | colour) separates the rooks and queens out\r\n  * from the rest.\r\n  * ((piece & 27) == 8 | colour) does the same for queens and bishops.\r\n  *\/\r\n\r\n  \/* check_castling\r\n  *\r\n  * s - \"start\" location (either king home square, or king destination)\r\n  *     the checks are done left to right.\r\n  * * dir - direction of travel (White: 10, Black: -10)\r\n  * side: -1 means Q side; 1, K side\r\n  *\/\r\n\r\n  function p4_check_castling(board, s, colour, dir, side){\r\n      var e;\r\n      var E;\r\n      var m, p;\r\n      var knight = colour + P4_KNIGHT;\r\n      var diag_slider = P4_BISHOP | colour;\r\n      var diag_mask = 27;\r\n      var grid_slider = P4_ROOK | colour;\r\n      var king_pawn = 2 | colour;\r\n      var grid_mask = 23;\r\n\r\n      \/* go through 3 positions, checking for check in each\r\n      *\/\r\n      for(p = s; p < s + 3; p++){\r\n          \/\/bishops, rooks, queens\r\n          e = p;\r\n          do{\r\n              e += dir;\r\n              E=board[e];\r\n          } while (! E);\r\n          if((E & grid_mask) == grid_slider)\r\n              return 0;\r\n          e = p;\r\n          var delta = dir - 1;\r\n          do{\r\n              e += delta;\r\n              E=board[e];\r\n          } while (! E);\r\n          if((E & diag_mask) == diag_slider)\r\n              return 0;\r\n          e = p;\r\n          delta += 2;\r\n          do{\r\n              e += delta;\r\n              E=board[e];\r\n          } while (! E);\r\n          if((E & diag_mask) == diag_slider)\r\n              return 0;\r\n          \/*knights on row 7. (row 6 is handled below)*\/\r\n          if (board[p + dir - 2] == knight ||\r\n              board[p + dir + 2] == knight)\r\n              return 0;\r\n      }\r\n\r\n      \/* a pawn or king in any of 5 positions on row 7.\r\n      * or a knight on row 6. *\/\r\n      for(p = s + dir - 1; p < s + dir + 4; p++){\r\n          E = board[p] & grid_mask;\r\n          if(E == king_pawn || board[p + dir] == knight)\r\n              return 0;\r\n      }\r\n      \/* scan back row for rooks, queens on the other side.\r\n      * Same side check is impossible, because the castling rook is there\r\n      *\/\r\n      e = (side < 0) ? s + 2 : s;\r\n      do {\r\n          e -= side;\r\n          E=board[e];\r\n      } while (! E);\r\n      if((E & grid_mask) == grid_slider)\r\n          return 0;\r\n\r\n      return 1;\r\n  }\r\n\r\n  function p4_check_check(state, colour){\r\n      var board = state.board;\r\n      \/*find the king.  The pieces list updates from the end,\r\n      * so the last-most king is correctly placed.*\/\r\n      var pieces = state.pieces[colour];\r\n      var p;\r\n      var i = pieces.length;\r\n      do {\r\n          p = pieces[--i];\r\n      } while (p[0] != (P4_KING | colour));\r\n      var s = p[1];\r\n      var other_colour = 1 - colour;\r\n      var dir = 10 - 20 * colour;\r\n      if (board[s + dir - 1] == (P4_PAWN | other_colour) ||\r\n          board[s + dir + 1] == (P4_PAWN | other_colour))\r\n          return true;\r\n      var knight_moves = P4_MOVES[P4_KNIGHT];\r\n      var king_moves = P4_MOVES[P4_KING];\r\n      var knight = P4_KNIGHT | other_colour;\r\n      var king = P4_KING | other_colour;\r\n      for (i = 0; i < 8; i++){\r\n          if (board[s + knight_moves[i]] == knight ||\r\n              board[s + king_moves[i]] == king)\r\n              return true;\r\n      }\r\n      var diagonal_moves = P4_MOVES[P4_BISHOP];\r\n      var grid_moves = P4_MOVES[P4_ROOK];\r\n\r\n      \/* diag_mask ignores rook moves of queens,\r\n      * grid_mask ignores the bishop moves*\/\r\n      var diag_slider = P4_BISHOP | other_colour;\r\n      var diag_mask = 27;\r\n      var grid_slider = P4_ROOK | other_colour;\r\n      var grid_mask = 23;\r\n      for (i = 0; i < 4; i++){\r\n          var m = diagonal_moves[i];\r\n          var e = s;\r\n          var E;\r\n          do {\r\n              e += m;\r\n              E = board[e];\r\n          } while (!E);\r\n          if((E & diag_mask) == diag_slider)\r\n              return true;\r\n\r\n          m = grid_moves[i];\r\n          e = s;\r\n          do {\r\n              e += m;\r\n              E = board[e];\r\n          } while (!E);\r\n          if((E & grid_mask) == grid_slider)\r\n              return true;\r\n      }\r\n      return false;\r\n  }\r\n\r\n  function p4_optimise_piece_list(state){\r\n      var i, p, s, e;\r\n      var movelists = [\r\n          p4_parse(state, 0, 0, 0),\r\n          p4_parse(state, 1, 0, 0)\r\n      ];\r\n      \/\/ var weights = state.weights;\r\n      var board = state.board;\r\n      for (var colour = 0; colour < 2; colour++){\r\n          var our_values = state.values[colour];\r\n          var pieces = state.pieces[colour];\r\n          var movelist = movelists[colour];\r\n          var threats = movelists[1 - colour];\r\n          \/* sparse array to index by score. *\/\r\n          var scores = [];\r\n          for (i = 0; i < pieces.length; i++){\r\n              p = pieces[i];\r\n              scores[p[1]] = {\r\n                  score: 0,\r\n                  piece: p[0],\r\n                  pos: p[1],\r\n                  threatened: 0\r\n              };\r\n          }\r\n          \/* Find the best score for each piece by pure static weights,\r\n          * ignoring captures, which have their own path to the top. *\/\r\n          for(i = movelist.length - 1; i >= 0; i--){\r\n              var mv = movelist[i];\r\n              var score = mv[0];\r\n              s = mv[1];\r\n              e = mv[2];\r\n              if(! board[e]){\r\n                  var x = scores[s];\r\n                  x.score = Math.max(x.score, score);\r\n              }\r\n          }\r\n          \/* moving out of a threat is worth considering, especially\r\n          * if it is a pawn and you are not.*\/\r\n          for(i = threats.length - 1; i >= 0; i--){\r\n              var mv = threats[i];\r\n              var x = scores[mv[2]];\r\n              if (x !== undefined){\r\n                  var S = board[mv[1]];\r\n                  var r = (1 + x.piece > 3 + S < 4) * 0.01;\r\n                  if (x.threatened < r)\r\n                      x.threatened = r;\r\n              }\r\n          }\r\n          var pieces2 = [];\r\n          for (i = 20; i < 100; i++){\r\n              p = scores[i];\r\n              if (p !== undefined){\r\n                  p.score += p.threatened * our_values[p.piece];\r\n                  pieces2.push(p);\r\n              }\r\n          }\r\n          pieces2.sort(function(a, b){return a.score - b.score;});\r\n          for (i = 0; i < pieces2.length; i++){\r\n              p = pieces2[i];\r\n              pieces[i] = [p.piece, p.pos];\r\n          }\r\n      }\r\n  }\r\n\r\n  function p4_findmove(state, level, colour, ep, opts){\r\n      p4_prepare(state);\r\n      p4_optimise_piece_list(state);\r\n      \/\/ var board = state.board;\r\n      colour = (colour===undefined) ? state.to_play : colour;\r\n      ep = (ep===undefined) ? state.enpassant : ep;\r\n      \/\/ var movelist = p4_parse(state, colour, ep, 0);\r\n      \/\/ var alpha = P4_MIN_SCORE;\r\n      var movelist\r\n      if (!opts) {\r\n        movelist = p4_parse(state, colour, ep, 0)\r\n      } else {\r\n        movelist = opts.movelist\r\n        colour = opts.colour\r\n        ep = opts.ep\r\n      }\r\n      opts = opts || {ep: ep, colour: colour, needMore: true, i: 0, alpha: P4_MIN_SCORE, movelist: movelist, level: level, moreCount: FIND_TIMEOUT_LIMIT}\r\n      var mv = opts.mv\r\n      var t = opts.t\r\n      var bs = opts.bs || 0;\r\n      var be = opts.be || 0;\r\n      \/\/ var movelist = opts.movelist\r\n      var alpha = opts.alpha\r\n      level = opts.level\r\n\r\n      if (level <= 0){\r\n          for (i = opts.i; i < movelist.length; i++){\r\n              mv = movelist[i];\r\n              if(movelist[i][0] > alpha){\r\n                  alpha = mv[0];\r\n                  bs = mv[1];\r\n                  be = mv[2];\r\n              }\r\n          }\r\n          return [bs, be, alpha];\r\n      }\r\n\r\n      var start_time = Date.now()\r\n\r\n      for(i = opts.i; i < movelist.length; i++){\r\n          mv = movelist[i];\r\n          var mscore = mv[0];\r\n          var ms = mv[1];\r\n          var me = mv[2];\r\n          if (mscore > P4_WIN){\r\n              p4_log(\"XXX taking king! it should never come to this\");\r\n              alpha = P4_KING_VALUE;\r\n              bs = ms;\r\n              be = me;\r\n              break;\r\n          }\r\n          t = -state.treeclimber(state, level - 1, 1 - colour, mscore, ms, me,\r\n                                P4_MIN_SCORE, -alpha);\r\n          if (t > alpha){\r\n              alpha = t;\r\n              bs = ms;\r\n              be = me;\r\n          }\r\n          if (opts.moreCount && i <= movelist.length && (Date.now() - start_time) > FIND_TIMEOUT) {\r\n            opts.moreCount --\r\n            opts.i = i\r\n            opts.alpha = alpha\r\n            opts.mv = mv\r\n            opts.bs = bs\r\n            opts.be = be\r\n            opts.t = t\r\n            return opts\r\n          }\r\n      }\r\n      if (alpha < -P4_WIN_NOW && ! p4_check_check(state, colour)){\r\n          alpha = state.stalemate_scores[colour];\r\n      }\r\n      return [bs, be, alpha];\r\n  }\r\n\r\n  \/*p4_make_move changes the state and returns an object containing\r\n  * everything necesary to undo the change.\r\n  *\r\n  * p4_unmake_move uses the p4_make_move return value to restore the\r\n  * previous state.\r\n  *\/\r\n\r\n  function p4_make_move(state, s, e, promotion){\r\n      var board = state.board;\r\n      var S = board[s];\r\n      var E = board[e];\r\n      board[e] = S;\r\n      board[s] = 0;\r\n      var piece = S & 14;\r\n      var moved_colour = S & 1;\r\n      var end_piece = S; \/* can differ from S in queening*\/\r\n      \/\/now some stuff to handle queening, castling\r\n      var rs = 0, re, rook;\r\n      var ep_taken = 0, ep_position;\r\n      var ep = 0;\r\n      if(piece == P4_PAWN){\r\n          if((60 - e) * (60 - e) > 900){\r\n              \/*got to end; replace the pawn on board and in pieces cache.*\/\r\n              promotion |= moved_colour;\r\n              board[e] = promotion;\r\n              end_piece = promotion;\r\n          }\r\n          else if (((s ^ e) & 1) && E == 0){\r\n              \/*this is a diagonal move, but the end spot is empty, so we surmise enpassant *\/\r\n              ep_position = e - 10 + 20 * moved_colour;\r\n              ep_taken = board[ep_position];\r\n              board[ep_position] = 0;\r\n          }\r\n          else if ((s - e) * (s - e) == 400){\r\n              \/*delta is 20 --> two row jump at start*\/\r\n              ep = (s + e) >> 1;\r\n          }\r\n      }\r\n      else if (piece == P4_KING && ((s - e) * (s - e) == 4)){  \/\/castling - move rook too\r\n          rs = s - 4 + (s < e) * 7;\r\n          re = (s + e) >> 1; \/\/avg of s,e=rook's spot\r\n          rook = moved_colour + P4_ROOK;\r\n          board[rs] = 0;\r\n          board[re] = rook;\r\n          \/\/piece_locations.push([rook, re]);\r\n      }\r\n\r\n      var old_castle_state = state.castles;\r\n      if (old_castle_state){\r\n          var mask = 0;\r\n          var shift = moved_colour * 2;\r\n          var side = moved_colour * 70;\r\n          var s2 = s - side;\r\n          var e2 = e + side;\r\n          \/\/wipe both our sides if king moves\r\n          if (s2 == 25)\r\n              mask |= 3 << shift;\r\n          \/\/wipe one side on any move from rook points\r\n          else if (s2 == 21)\r\n              mask |= 1 << shift;\r\n          else if (s2 == 28)\r\n              mask |= 2 << shift;\r\n          \/\/or on any move *to* opposition corners\r\n          if (e2 == 91)\r\n              mask |= 4 >> shift;\r\n          else if (e2 == 98)\r\n              mask |= 8 >> shift;\r\n          state.castles &= ~mask;\r\n      }\r\n\r\n      var old_pieces = state.pieces.slice();\r\n      var our_pieces = old_pieces[moved_colour];\r\n      var dest = state.pieces[moved_colour] = [];\r\n      for (var i = 0; i < our_pieces.length; i++){\r\n          var x = our_pieces[i];\r\n          var pp = x[0];\r\n          var ps = x[1];\r\n          if (ps != s && ps != rs){\r\n              dest.push(x);\r\n          }\r\n      }\r\n      dest.push([end_piece, e]);\r\n      if (rook)\r\n          dest.push([rook, re]);\r\n\r\n      if (E || ep_taken){\r\n          var their_pieces = old_pieces[1 - moved_colour];\r\n          dest = state.pieces[1 - moved_colour] = [];\r\n          var gone = ep_taken ? ep_position : e;\r\n          for (i = 0; i < their_pieces.length; i++){\r\n              var x = their_pieces[i];\r\n              if (x[1] != gone){\r\n                  dest.push(x);\r\n              }\r\n          }\r\n      }\r\n\r\n      return {\r\n          \/*some of these (e.g. rook) could be recalculated during\r\n          * unmake, possibly more cheaply. *\/\r\n          s: s,\r\n          e: e,\r\n          S: S,\r\n          E: E,\r\n          ep: ep,\r\n          castles: old_castle_state,\r\n          rs: rs,\r\n          re: re,\r\n          rook: rook,\r\n          ep_position: ep_position,\r\n          ep_taken: ep_taken,\r\n          pieces: old_pieces\r\n      };\r\n  }\r\n\r\n  function p4_unmake_move(state, move){\r\n      var board = state.board;\r\n      if (move.ep_position){\r\n          board[move.ep_position] = move.ep_taken;\r\n      }\r\n      board[move.s] = move.S;\r\n      board[move.e] = move.E;\r\n      \/\/move.piece_locations.length--;\r\n      if(move.rs){\r\n          board[move.rs] = move.rook;\r\n          board[move.re] = 0;\r\n          \/\/move.piece_locations.length--;\r\n      }\r\n      state.pieces = move.pieces;\r\n      state.castles = move.castles;\r\n  }\r\n\r\n\r\n  function p4_insufficient_material(state){\r\n      var knights = false;\r\n      var bishops = undefined;\r\n      var i;\r\n      var board = state.board;\r\n      for(i = 20; i  < 100; i++){\r\n          var piece = board[i] & 14;\r\n          if(piece == 0 || piece == P4_KING){\r\n              continue;\r\n          }\r\n          if (piece == P4_KNIGHT){\r\n              \/* only allow one knight of either colour, never with a bishop *\/\r\n              if (knights || bishops !== undefined){\r\n                  return false;\r\n              }\r\n              knights = true;\r\n          }\r\n          else if (piece == P4_BISHOP){\r\n              \/*any number of bishops, but on only one colour square *\/\r\n              var x = i & 1;\r\n              var y = parseInt(i \/ 10) & 1;\r\n              var parity = x ^ y;\r\n              if (knights){\r\n                  return false;\r\n              }\r\n              else if (bishops === undefined){\r\n                  bishops = parity;\r\n              }\r\n              else if (bishops != parity){\r\n                  return false;\r\n              }\r\n          }\r\n          else {\r\n              return false;\r\n          }\r\n      }\r\n      return true;\r\n  }\r\n\r\n  \/* p4_move(state, s, e, promotion)\r\n  * s, e are start and end positions\r\n  *\r\n  * promotion is the desired pawn promotion if the move gets a pawn to the other\r\n  * end.\r\n  *\r\n  * return value contains bitwise flags\r\n  *\/\r\n  function p4_move(state, s, e, promotion, check_only){\r\n      var board = state.board;\r\n      var colour = state.to_play;\r\n      var other_colour = 1 - colour;\r\n      if (s != parseInt(s)){\r\n          if (e === undefined){\r\n              var mv = p4_interpret_movestring(state, s);\r\n              s = mv[0];\r\n              e = mv[1];\r\n              if (s == 0)\r\n                  return {flags: P4_MOVE_ILLEGAL, ok: false};\r\n              promotion = mv[2];\r\n          }\r\n          else {\/*assume two point strings: 'e2', 'e4'*\/\r\n              s = p4_destringify_point(s);\r\n              e = p4_destringify_point(e);\r\n          }\r\n      }\r\n      if (promotion === undefined)\r\n          promotion = P4_QUEEN;\r\n      var E=board[e];\r\n      var S=board[s];\r\n      \/\/ if(colour) console.warn('Player move:', e, s, E, S)\r\n\r\n      \/*See if this move is even slightly legal, disregarding check.\r\n      *\/\r\n      var i;\r\n      var legal = false;\r\n      p4_maybe_prepare(state);\r\n      var pieces = [[S,s]]\r\n      var moves = p4_parse(state, colour, state.enpassant, 0, pieces);\r\n      for (i = 0; i < moves.length; i++){\r\n          if (e == moves[i][2] && s == moves[i][1]){\r\n              legal = true;\r\n              break;\r\n          }\r\n      }\r\n      if (! legal) {\r\n          return {flags: P4_MOVE_ILLEGAL, ok: false};\r\n      }\r\n\r\n      \/*Try the move, and see what the response is.*\/\r\n      var changes = p4_make_move(state, s, e, promotion);\r\n      \/\/ if(!colour) console.warn('Player move changes:', e, s, E, S, changes)\r\n\r\n      \/*is it check? *\/\r\n      if (p4_check_check(state, colour)){\r\n          p4_unmake_move(state, changes);\r\n          \/\/ p4_log('in check', changes);\r\n          return {flags: P4_MOVE_ILLEGAL, ok: false, string: \"in check!\"};\r\n      }\r\n      if (check_only) {\r\n          p4_unmake_move(state, changes);\r\n          return {flags: P4_MOVE_FLAG_OK, ok: true, string: \"valid\"};\r\n      }\r\n      \/*The move is known to be legal. We won't be undoing it.*\/\r\n\r\n      var flags = P4_MOVE_FLAG_OK;\r\n\r\n      state.enpassant = changes.ep;\r\n      state.history.push([s, e, promotion]);\r\n\r\n      \/*draw timeout: 50 moves without pawn move or capture is a draw *\/\r\n      if (changes.E || changes.ep_position || E){\r\n          state.draw_timeout = 0;\r\n          flags |= P4_MOVE_FLAG_CAPTURE;\r\n      }\r\n      else if ((S & 14) == P4_PAWN){\r\n          state.draw_timeout = 0;\r\n      }\r\n      else{\r\n          state.draw_timeout++;\r\n      }\r\n      if (changes.rs){\r\n          flags |= (s > e) ? P4_MOVE_FLAG_CASTLE_QUEEN : P4_MOVE_FLAG_CASTLE_KING;\r\n      }\r\n      var shortfen = p4_state2fen(state, true);\r\n      var repetitions = (state.position_counts[shortfen] || 0) + 1;\r\n      state.position_counts[shortfen] = repetitions;\r\n      state.current_repetitions = repetitions;\r\n      if (state.draw_timeout > 100 || repetitions >= 3 ||\r\n          p4_insufficient_material(state)){\r\n          flags |= P4_MOVE_FLAG_DRAW;\r\n      }\r\n      state.moveno++;\r\n      state.to_play = other_colour;\r\n\r\n      if (p4_check_check(state, other_colour)){\r\n          flags |= P4_MOVE_FLAG_CHECK;\r\n      }\r\n      \/* check for (stale|check)mate, by seeing if there is a move for\r\n      * the other side that doesn't result in check. (In other words,\r\n      * reduce the pseudo-legal-move list down to a legal-move list,\r\n      * and check it isn't empty).\r\n      *\r\n      * We don't need to p4_prepare because other colour pieces can't\r\n      * have moved (just disappeared) since previous call. Also,\r\n      * setting the promotion piece is unnecessary, because all\r\n      * promotions block check equally well.\r\n      *\/\r\n      var is_mate = true;\r\n      var replies = p4_parse(state, other_colour, changes.ep, 0);\r\n      var rln = replies.length\r\n      for (i = 0; i < rln; i++){\r\n          var m = replies[i];\r\n          var change2 = p4_make_move(state, m[1], m[2], P4_QUEEN);\r\n          var check = p4_check_check(state, other_colour);\r\n          p4_unmake_move(state, change2);\r\n          if (!check){\r\n              is_mate = false;\r\n              break;\r\n          }\r\n      }\r\n      if (is_mate)\r\n          flags |= P4_MOVE_FLAG_MATE;\r\n\r\n      var movestring = p4_move2string(state, s, e, S, promotion, flags, moves);\r\n      \/\/ p4_log(\"successful move\", s, e, movestring, flags);\r\n      state.prepared = false;\r\n      return {\r\n          flags: flags,\r\n          string: movestring,\r\n          mover: colour,\r\n          source: s,\r\n          target: e,\r\n          piece: P4_PIECE_LUT_R[S],\r\n          capture: (flags & P4_MOVE_FLAG_CAPTURE) ? P4_PIECE_LUT_R[E] : false,\r\n          ok: true\r\n      };\r\n  }\r\n\r\n\r\n  function p4_move2string(state, s, e, S, promotion, flags, moves){\r\n      var piece = S & 14;\r\n      var src, dest;\r\n      var mv, i;\r\n      var capture = flags & P4_MOVE_FLAG_CAPTURE;\r\n\r\n      src = p4_stringify_point(s);\r\n      dest = p4_stringify_point(e);\r\n      if (piece == P4_PAWN){\r\n          if (capture){\r\n              mv = src.charAt(0) + 'x' + dest;\r\n          }\r\n          else\r\n              mv = dest;\r\n          if (e > 90 || e < 30){  \/\/end row, queening\r\n              if (promotion === undefined)\r\n                  promotion = P4_QUEEN;\r\n              mv += '=' + P4_ENCODE_LUT.charAt(promotion);\r\n          }\r\n      }\r\n      else if (piece == P4_KING && (s-e) * (s-e) == 4) {\r\n          if (e < s)\r\n              mv = 'O-O-O';\r\n          else\r\n              mv = 'O-O';\r\n      }\r\n      else {\r\n          var row_qualifier = '';\r\n          var col_qualifier = '';\r\n          var pstr = P4_ENCODE_LUT.charAt(S);\r\n          var sx = s % 10;\r\n          var sy = parseInt(s \/ 10);\r\n\r\n          \/* find any other pseudo-legal moves that would put the same\r\n          * piece in the same place, for which we'd need\r\n          * disambiguation. *\/\r\n          var co_landers = [];\r\n          for (i = 0; i < moves.length; i++){\r\n              var m = moves[i];\r\n              if (e == m[2] && s != m[1] && state.board[m[1]] == S){\r\n                  co_landers.push(m[1]);\r\n              }\r\n          }\r\n          if (co_landers.length){\r\n              for (i = 0; i < co_landers.length; i++){\r\n                  var c = co_landers[i];\r\n                  var cx = c % 10;\r\n                  var cy = parseInt(c \/ 10);\r\n                  if (cx == sx)\/*same column, so qualify by row*\/\r\n                      row_qualifier = src.charAt(1);\r\n                  if (cy == sy)\r\n                      col_qualifier = src.charAt(0);\r\n              }\r\n              if (row_qualifier == '' && col_qualifier == ''){\r\n                  \/*no co-landers on the same rank or file, so one or the other will do.\r\n                  * By convention, use the column (a-h) *\/\r\n                  col_qualifier = src.charAt(0);\r\n              }\r\n          }\r\n          mv = pstr + col_qualifier + row_qualifier + (capture ? 'x' : '') + dest;\r\n      }\r\n      if (flags & P4_MOVE_FLAG_CHECK){\r\n          if (flags & P4_MOVE_FLAG_MATE)\r\n              mv += '#';\r\n          else\r\n              mv += '+';\r\n      }\r\n      else if (flags & P4_MOVE_FLAG_MATE)\r\n          mv += ' stalemate';\r\n      return mv;\r\n  }\r\n\r\n\r\n  function p4_jump_to_moveno(state, moveno){\r\n      \/\/ p4_log('jumping to move', moveno);\r\n      if (moveno === undefined || moveno > state.moveno)\r\n          moveno = state.moveno;\r\n      else if (moveno < 0){\r\n          moveno = state.moveno + moveno;\r\n      }\r\n      var state2 = p4_fen2state(state.beginning);\r\n      var i = 0;\r\n      while (state2.moveno < moveno){\r\n          var m = state.history[i++];\r\n          p4_move(state2, m[0], m[1], m[2]);\r\n      }\r\n      \/* copy the replayed state across, not all that deeply, but\r\n      * enough to cover, eg, held references to board. *\/\r\n      var attr, dest;\r\n      for (attr in state2){\r\n          var src = state2[attr];\r\n          if (attr instanceof Array){\r\n              dest = state[attr];\r\n              dest.length = 0;\r\n              for (i = 0; i < src.length; i++){\r\n                  dest[i] = src[i];\r\n              }\r\n          }\r\n          else {\r\n              state[attr] = src;\r\n          }\r\n      }\r\n      state.prepared = false;\r\n  }\r\n\r\n\r\n  \/* write a standard FEN notation\r\n  * http:\/\/en.wikipedia.org\/wiki\/Forsyth%E2%80%93Edwards_Notation\r\n  * *\/\r\n  function p4_state2fen(state, reduced){\r\n      var piece_lut = '  PpRrNnBbKkQq';\r\n      var board = state.board;\r\n      var fen = '';\r\n      \/\/fen does Y axis backwards, X axis forwards *\/\r\n      for (var y = 9; y > 1; y--){\r\n          var count = 0;\r\n          for (var x = 1; x < 9; x++){\r\n              var piece = board[y * 10 + x];\r\n              if (piece == 0)\r\n                  count++;\r\n              else{\r\n                  if (count)\r\n                      fen += count.toString();\r\n                  fen += piece_lut.charAt(piece);\r\n                  count = 0;\r\n              }\r\n          }\r\n          if (count)\r\n              fen += count;\r\n          if (y > 2)\r\n              fen += '\/';\r\n      }\r\n      \/*white or black *\/\r\n      fen += ' ' + 'wb'.charAt(state.to_play) + ' ';\r\n      \/*castling *\/\r\n      if (state.castles){\r\n          var lut = [2, 'K', 1, 'Q', 8, 'k', 4, 'q'];\r\n          for (var i = 0; i < 8; i += 2){\r\n              if (state.castles & lut[i]){\r\n                  fen += lut[i + 1];\r\n              }\r\n          }\r\n      }\r\n      else\r\n          fen += '-';\r\n      \/*enpassant *\/\r\n      if (state.enpassant !== 0){\r\n          fen += ' ' + p4_stringify_point(state.enpassant);\r\n      }\r\n      else\r\n          fen += ' -';\r\n      if (reduced){\r\n          \/*if the 'reduced' flag is set, the move number and draw\r\n          *timeout are not added. This form is used to detect draws by\r\n          *3-fold repetition.*\/\r\n          return fen;\r\n      }\r\n      fen += ' ' + state.draw_timeout + ' ';\r\n      fen += (state.moveno >> 1) + 1;\r\n      return fen;\r\n  }\r\n\r\n  function p4_stringify_point(p){\r\n      var letters = \" abcdefgh\";\r\n      var x = p % 10;\r\n      var y = (p - x) \/ 10 - 1;\r\n      return letters.charAt(x) + y;\r\n  }\r\n\r\n  function p4_destringify_point(p){\r\n      var x = parseInt(p.charAt(0), 19) - 9; \/\/a-h <-> 10-18, base 19\r\n      var y = parseInt(p.charAt(1)) + 1;\r\n      if (y >= 2 && y < 10 && x >= 1 && x < 9)\r\n          return y * 10 + x;\r\n      return undefined;\r\n  }\r\n\r\n  \/* read a standard FEN notation\r\n  * http:\/\/en.wikipedia.org\/wiki\/Forsyth%E2%80%93Edwards_Notation\r\n  * *\/\r\n  function p4_fen2state(fen, state){\r\n      if (state === undefined)\r\n          state = p4_initialise_state();\r\n      var board = state.board;\r\n      var fenbits = fen.split(' ');\r\n      var fen_board = fenbits[0];\r\n      var fen_toplay = fenbits[1];\r\n      var fen_castles = fenbits[2];\r\n      var fen_enpassant = fenbits[3];\r\n      var fen_timeout = fenbits[4];\r\n      var fen_moveno = fenbits[5];\r\n      if (fen_timeout === undefined)\r\n          fen_timeout = 0;\r\n      \/\/fen does Y axis backwards, X axis forwards *\/\r\n      var y = 90;\r\n      var x = 1;\r\n      var i, c;\r\n      for (var j = 0; j < fen_board.length; j++){\r\n          c = fen_board.charAt(j);\r\n          if (c == '\/'){\r\n              x = 1;\r\n              y -= 10;\r\n              if (y < 20)\r\n                  break;\r\n              continue;\r\n          }\r\n          var piece = P4_PIECE_LUT[c];\r\n          if (piece && x < 9){\r\n              board[y + x] = piece;\r\n              x++;\r\n          }\r\n          else {\r\n              var end = Math.min(x + parseInt(c), 9);\r\n              for (; x < end; x++){\r\n                  board[y + x] = 0;\r\n              }\r\n          }\r\n      }\r\n      state.to_play = (fen_toplay.toLowerCase() == 'b') ? 1 : 0;\r\n      state.castles = 0;\r\n      \/* Sometimes we meet bad FEN that says it can castle when it can't. *\/\r\n      var wk = board[25] == P4_KING;\r\n      var bk = board[95] == P4_KING + 1;\r\n      var castle_lut = {\r\n          k: 8 * (bk && board[98] == P4_ROOK + 1),\r\n          q: 4 * (bk && board[91] == P4_ROOK + 1),\r\n          K: 2 * (wk && board[28] == P4_ROOK),\r\n          Q: 1 * (wk && board[21] == P4_ROOK)\r\n      };\r\n      for (i = 0; i < fen_castles.length; i++){\r\n          c = fen_castles.charAt(i);\r\n          var castle = castle_lut[c];\r\n          if (castle !== undefined){\r\n              state.castles |= castle;\r\n              if (castle == 0){\r\n                  console.log(\"FEN claims castle state \" + fen_castles +\r\n                              \" but pieces are not in place for \" + c);\r\n              }\r\n          }\r\n      }\r\n\r\n      state.enpassant = (fen_enpassant != '-') ? p4_destringify_point(fen_enpassant) : 0;\r\n      state.draw_timeout = parseInt(fen_timeout);\r\n      if (fen_moveno === undefined){\r\n          \/*have a guess based on entropy and pieces remaining*\/\r\n          var pieces = 0;\r\n          var mix = 0;\r\n          var p, q, r;\r\n          for (y = 20; y < 100; y+=10){\r\n              for (x = 1; x < 9; x++){\r\n                  p = board[y + x] & 15;\r\n                  pieces += (!!p);\r\n                  if (x < 8){\r\n                      q = board[y + x + 1];\r\n                      mix += (!q) != (!p);\r\n                  }\r\n                  if (y < 90){\r\n                      q = board[y + x + 10];\r\n                      mix += (!q) != (!p);\r\n                  }\r\n              }\r\n          }\r\n          fen_moveno = Math.max(1, parseInt((32 - pieces) * 1.3 + (4 - fen_castles.length) * 1.5 + ((mix - 16) \/ 5)));\r\n          \/\/p4_log(\"pieces\", pieces, \"mix\", mix, \"estimate\", fen_moveno);\r\n      }\r\n      state.moveno = 2 * (parseInt(fen_moveno) - 1) + state.to_play;\r\n      state.history = [];\r\n      state.beginning = fen;\r\n      state.prepared = false;\r\n      state.position_counts = {};\r\n      \/* Wrap external functions as methods. *\/\r\n      state.move = function(s, e, promotion){\r\n          return p4_move(this, s, e, promotion);\r\n      };\r\n      state.parse = function(color, ep, score, pieces){\r\n          return p4_parse(this, color, ep, score, pieces);\r\n      };\r\n      state.prepare = function(){\r\n          return p4_maybe_prepare(this);\r\n      };\r\n      state.findmove = function(level, opts){\r\n          return p4_findmove(this, level, undefined, undefined, opts);\r\n      };\r\n      state.jump_to_moveno = function(moveno){\r\n          return p4_jump_to_moveno(this, moveno);\r\n      };\r\n      return state;\r\n  }\r\n\r\n  \/*\r\n  Weights would all fit within an Int8Array *except* for the last row\r\n  for pawns, which is close to the queen value (180, max is 127).\r\n\r\n  Int8Array seems slightly quicker in Chromium 18, no different in\r\n  Firefox 12.\r\n\r\n  Int16Array is no faster, perhaps slower than Int32Array.\r\n\r\n  Int32Array is marginally slower than plain arrays with Firefox 12, but\r\n  significantly quicker with Chromium.\r\n  *\/\r\n\r\n  var P4_ZEROS = [];\r\n  function p4_zero_array(){\r\n      if (P4_USE_TYPED_ARRAYS)\r\n          return new Int32Array(120);\r\n      if (P4_ZEROS.length == 0){\r\n          for(var i = 0; i < 120; i++){\r\n              P4_ZEROS[i] = 0;\r\n          }\r\n      }\r\n      return P4_ZEROS.slice();\r\n  }\r\n\r\n  \/* p4_initialise_state() creates the board and initialises weight\r\n  * arrays etc.  Some of this is really only needs to be done once.\r\n  *\/\r\n\r\n  function p4_initialise_state(){\r\n      var board = p4_zero_array();\r\n      P4_CENTRALISING_WEIGHTS = p4_zero_array();\r\n      P4_BASE_PAWN_WEIGHTS = p4_zero_array();\r\n      P4_KNIGHT_WEIGHTS = p4_zero_array();\r\n      for(var i = 0; i < 120; i++){\r\n          var y = parseInt(i \/ 10);\r\n          var x = i % 10;\r\n          var dx = Math.abs(x - 4.5);\r\n          var dy = Math.abs(y - 5.5);\r\n          P4_CENTRALISING_WEIGHTS[i] = parseInt(6 - Math.pow((dx * dx + dy * dy) * 1.5, 0.6));\r\n          \/\/knights have a flat topped centre (bishops too, but less so).\r\n          P4_KNIGHT_WEIGHTS[i] = parseInt(((dx < 2) + (dy < 2) * 1.5)\r\n                                          + (dx < 3) + (dy < 3)) - 2;\r\n          P4_BASE_PAWN_WEIGHTS[i] = parseInt('000012347000'.charAt(y));\r\n          if (y > 9 || y < 2 || x < 1 || x > 8)\r\n              board[i] = 16;\r\n      }\r\n      var weights = [];\r\n      for (i = 0; i < 14; i++){\r\n          weights[i] = p4_zero_array();\r\n      }\r\n      var state = {\r\n          board: board,\r\n          weights: weights,\r\n          history: [],\r\n          treeclimber: p4_alphabeta_treeclimber\r\n      };\r\n      p4_random_seed(state, P4_DEBUG ? 1 : Date.now());\r\n      return state;\r\n  }\r\n\r\n  function p4_new_game(){\r\n      return p4_fen2state(P4_INITIAL_BOARD);\r\n  }\r\n\r\n  \/*convert an arbitrary movestring into a pair of integers offsets into\r\n  * the board. The string might be in any of these forms:\r\n  *\r\n  *  \"d2-d4\" \"d2d4\" \"d4\" -- moving a pawn\r\n  *\r\n  *  \"b1-c3\" \"b1c3\" \"Nc3\" \"N1c3\" \"Nbc3\" \"Nb1c3\" -- moving a knight\r\n  *\r\n  *  \"b1xc3\" \"b1xc3\" \"Nxc3\" -- moving a knight, also happens to capture.\r\n  *\r\n  *  \"O-O\" \"O-O-O\" -- special cases for castling (\"e1-c1\", etc, also work)\r\n  *\r\n  *  Note that for the \"Nc3\" (pgn) format, some knowledge of the board\r\n  *  is necessary, so the state parameter is required. If it is\r\n  *  undefined, the other forms will still work.\r\n  *\/\r\n\r\n  function p4_interpret_movestring(state, str){\r\n      \/* Ignore any irrelevant characters, then tokenise.\r\n      *\r\n      *\/\r\n      var FAIL = [0, 0];\r\n      var algebraic_re = \/^\\s*([RNBQK]?[a-h]?[1-8]?)[ :x-]*([a-h][1-8]?)(=[RNBQ])?[!?+#e.p]*\\s*$\/;\r\n      var castle_re = \/^\\s*([O0o]-[O0o](-[O0o])?)\\s*$\/;\r\n      var position_re = \/^[a-h][1-8]$\/;\r\n\r\n      var m = algebraic_re.exec(str);\r\n      if (m == null){\r\n          \/*check for castling notation (O-O, O-O-O) *\/\r\n          m = castle_re.exec(str);\r\n          if (m){\r\n              s = 25 + state.to_play * 70;\r\n              if (m[2])\/*queenside*\/\r\n                  e = s - 2;\r\n              else\r\n                  e = s + 2;\r\n          }\r\n          else\r\n              return FAIL;\r\n      }\r\n      var src = m[1];\r\n      var dest = m[2];\r\n      var queen = m[3];\r\n      var s, e, q;\r\n      var moves, i;\r\n      if (src == '' || src == undefined){\r\n          \/* a single coordinate pawn move *\/\r\n          e = p4_destringify_point(dest);\r\n          s = p4_find_source_point(state, e, 'P' + dest.charAt(0));\r\n      }\r\n      else if (\/^[RNBQK]\/.test(src)){\r\n          \/*pgn format*\/\r\n          e = p4_destringify_point(dest);\r\n          s = p4_find_source_point(state, e, src);\r\n      }\r\n      else if (position_re.test(src) && position_re.test(dest)){\r\n          s = p4_destringify_point(src);\r\n          e = p4_destringify_point(dest);\r\n      }\r\n      else if (\/^[a-h]$\/.test(src)){\r\n          e = p4_destringify_point(dest);\r\n          s = p4_find_source_point(state, e, 'P' + src);\r\n      }\r\n      if (s == 0)\r\n          return FAIL;\r\n\r\n      if (queen){\r\n          \/* the chosen queen piece *\/\r\n          q = P4_PIECE_LUT[queen.charAt(1)];\r\n      }\r\n      return [s, e, q];\r\n  }\r\n\r\n\r\n  function p4_find_source_point(state, e, str){\r\n      var colour = state.to_play;\r\n      var piece = P4_PIECE_LUT[str.charAt(0)];\r\n      piece |= colour;\r\n      var s, i;\r\n\r\n      var row, column;\r\n      \/* can be specified as Na, Na3, N3, and who knows, N3a? *\/\r\n      for (i = 1; i < str.length; i++){\r\n          var c = str.charAt(i);\r\n          if (\/[a-h]\/.test(c)){\r\n              column = str.charCodeAt(i) - 96;\r\n          }\r\n          else if (\/[1-8]\/.test(c)){\r\n              \/*row goes 2 - 9 *\/\r\n              row = 1 + parseInt(c);\r\n          }\r\n      }\r\n      var possibilities = [];\r\n      p4_prepare(state);\r\n      var moves = p4_parse(state, colour,\r\n                          state.enpassant, 0);\r\n      for (i = 0; i < moves.length; i++){\r\n          var mv = moves[i];\r\n          if (e == mv[2]){\r\n              s = mv[1];\r\n              if (state.board[s] == piece &&\r\n                  (column === undefined || column == s % 10) &&\r\n                  (row === undefined || row == parseInt(s \/ 10))\r\n                ){\r\n                    var change = p4_make_move(state, s, e, P4_QUEEN);\r\n                    if (! p4_check_check(state, colour))\r\n                        possibilities.push(s);\r\n                    p4_unmake_move(state, change);\r\n              }\r\n          }\r\n      }\r\n      \/\/ p4_log(\"finding\", str, \"that goes to\", e, \"got\", possibilities);\r\n\r\n      if (possibilities.length == 0){\r\n          return 0;\r\n      }\r\n      else if (possibilities.length > 1){\r\n          \/\/ p4_log(\"p4_find_source_point seems to have failed\",\r\n          \/\/       state, e, str,\r\n          \/\/       possibilities);\r\n      }\r\n      return possibilities[0];\r\n  }\r\n\r\n\r\n  \/*random number generator based on\r\n  * http:\/\/burtleburtle.net\/bob\/rand\/smallprng.html\r\n  *\/\r\n  function p4_random_seed(state, seed){\r\n      seed &= 0xffffffff;\r\n      state.rng = (P4_USE_TYPED_ARRAYS) ? new Uint32Array(4) : [];\r\n      state.rng[0] = 0xf1ea5eed;\r\n      state.rng[1] = seed;\r\n      state.rng[2] = seed;\r\n      state.rng[3] = seed;\r\n      for (var i = 0; i < 20; i++)\r\n          p4_random31(state);\r\n  }\r\n\r\n  function p4_random31(state){\r\n      var rng = state.rng;\r\n      var b = rng[1];\r\n      var c = rng[2];\r\n      \/* These shifts amount to rotates.\r\n      * Note the three-fold right shift '>>>', meaning an unsigned shift.\r\n      * The 0xffffffff masks are needed to keep javascript to 32bit. (supposing\r\n      * untyped arrays).\r\n      *\/\r\n      var e = rng[0] - ((b << 27) | (b >>> 5));\r\n      rng[0] = b ^ ((c << 17) | (c >>> 15));\r\n      rng[1] = (c + rng[3]) & 0xffffffff;\r\n      rng[2] = (rng[3] + e) & 0xffffffff;\r\n      rng[3] = (e + rng[0]) & 0xffffffff;\r\n      return rng[3] & 0x7fffffff;\r\n  }\r\n\r\n  function p4_random_int(state, top){\r\n      \/* uniform integer in range [0 <= n < top), supposing top < 2 ** 31\r\n      *\r\n      * This method is slightly (probably pointlessly) more accurate\r\n      * than converting to 0-1 float, multiplying and truncating, and\r\n      * considerably more accurate than a simple modulus.\r\n      * Obviously it is a bit slower.\r\n      *\/\r\n      \/* mask becomes one less than the next highest power of 2 *\/\r\n      var mask = top;\r\n      mask--;\r\n      mask |= mask >>> 1;\r\n      mask |= mask >>> 2;\r\n      mask |= mask >>> 4;\r\n      mask |= mask >>> 8;\r\n      mask |= mask >>> 16;\r\n      var r;\r\n      do{\r\n          r = p4_random31(state) & mask;\r\n      } while (r >= top);\r\n      return r;\r\n  }\r\n\r\n  \/\/ Alternative AI functions:\r\n  \/\/ 'alphabeta (default)', p4_alphabeta_treeclimber,\r\n  \/\/ 'nullmove', p4_nullmove_alphabeta_treeclimber,\r\n  \/\/ 'nullmove\/quiesce', p4_nullmove_alphabeta_quiescing_treeclimber,\r\n  \/\/ 'negascout', p4_negascout_treeclimber,\r\n  \/\/ 'negamax (slow!)', p4_negamax_treeclimber\r\n  function p4_negamax_treeclimber(state, count, colour, score, s, e){\r\n      var move;\r\n      if (s)\r\n          move = p4_make_move(state, s, e, P4_QUEEN);\r\n      var ep = s ? move.ep: 0;\r\n      var ncolour = 1 - colour;\r\n      var movelist = p4_parse(state, colour, ep, -score);\r\n      var movecount = movelist.length;\r\n      state.node_count += movecount;\r\n      var best = P4_MIN_SCORE;\r\n      if(count){\r\n          \/\/branch nodes\r\n          var t;\r\n          for(var i = 0; i < movecount; i++){\r\n              var mv = movelist[i];\r\n              var mscore = mv[0];\r\n              if (mscore > P4_WIN){\r\n                  best = P4_KING_VALUE;\r\n                  break;\r\n              }\r\n              t = -p4_negamax_treeclimber(state, count - 1, ncolour, mscore, mv[1], mv[2]);\r\n              if (t > best){\r\n                  best = t;\r\n              }\r\n          }\r\n\r\n          if (best < -P4_WIN_NOW && ! p4_check_check(state, colour)){\r\n              best = state.stalemate_scores[colour];\r\n          }\r\n          if (best < -P4_WIN){\r\n              best += P4_WIN_DECAY;\r\n          }\r\n      }\r\n      else{\r\n          \/\/leaf nodes\r\n          while(--movecount != -1){\r\n              if(movelist[movecount][0] > best){\r\n                  best = movelist[movecount][0];\r\n              }\r\n          }\r\n      }\r\n      if (s)\r\n          p4_unmake_move(state, move);\r\n      return best;\r\n  }\r\n\r\n  function p4_counting_treeclimber(state, count, colour, score, s, e){\r\n      var move, i, ep;\r\n      var promotions = [P4_QUEEN, P4_ROOK, P4_BISHOP, P4_KNIGHT];\r\n      var pi = 0;\r\n      var ncolour = 1 - colour;\r\n      var subnodes = 0;\r\n      do {\r\n          if (s){\r\n              move = p4_make_move(state, s, e, promotions[pi]);\r\n              ep = move.ep;\r\n          }\r\n          else {\r\n              ep = 0;\r\n          }\r\n          var pseudo_movelist = p4_parse(state, colour, ep, 0);\r\n          var movelist = [];\r\n          var promotion_count = 0;\r\n          \/* Pseudo_movelist contains moves into check, so drop those.\r\n          *\/\r\n          for (i = 0; i < pseudo_movelist.length; i++){\r\n              var mv2 = pseudo_movelist[i];\r\n              var s2 = mv2[1], e2 = mv2[2];\r\n              var move2 = p4_make_move(state, s2, e2, P4_QUEEN);\r\n              if (! p4_check_check(state, colour)){\r\n                  movelist.push(mv2);\r\n                  if ((move2.S & 14) == 2 && (e2 < 30 || e2 > 90)){\r\n                      \/*this is a promotion*\/\r\n                      promotion_count++;\r\n                  }\r\n              }\r\n              p4_unmake_move(state, move2);\r\n          }\r\n          var movecount = movelist.length;\r\n          if(count){\r\n              for(i = 0; i < movecount; i++){\r\n                  var mv = movelist[i];\r\n                  subnodes += p4_counting_treeclimber(state, count - 1, ncolour, 0, mv[1], mv[2]);\r\n              }\r\n          }\r\n          else{\r\n              subnodes += movecount;\r\n              subnodes += promotion_count * 3; \/\/3 extras on top of queen\r\n          }\r\n          if (s)\r\n              p4_unmake_move(state, move);\r\n\r\n          \/\/if (pi && move.S < 4 && ((60 - e) * (60 - e) > 900))\r\n          \/\/    console.log(s, move.S, promotions[pi]);\r\n          pi++;\r\n      } while(s &&\r\n              pi < promotions.length &&\r\n              move.S < 4 &&\r\n              ((60 - e) * (60 - e) > 900));\r\n\r\n      return subnodes;\r\n  }\r\n\r\n\r\n\r\n\r\n  function p4_nullmove_alphabeta_treeclimber(state, count, colour, score, s, e, alpha, beta){\r\n      var move;\r\n      if (s)\r\n          move = p4_make_move(state, s, e, P4_QUEEN);\r\n      var ep = s ? move.ep: 0;\r\n      var ncolour = 1 - colour;\r\n      var board = state.board;\r\n      if(count){\r\n          \/\/branch nodes\r\n          var t;\r\n          \/* first try a null move. This sets a decent value for beta in\r\n            almost every situation (I think. seems to work).\r\n          *\/\r\n          if (count >= 2){\r\n              t = p4_nullmove_alphabeta_treeclimber(state, count - 2, colour, score, 0, 0,\r\n                                                    alpha, beta);\r\n              \/\/console.log('count, t, alpha, beta', count, t, alpha, beta);\r\n              if (t > beta){\r\n                  if (s)\r\n                      p4_unmake_move(state, move);\r\n                  return beta;\r\n              }\r\n          }\r\n          var movelist = p4_parse(state, colour, ep, -score);\r\n          var movecount = movelist.length;\r\n          for(var i = 0; i < movecount; i++){\r\n              var mv = movelist[i];\r\n              var mscore = mv[0];\r\n              var ms = mv[1];\r\n              var me = mv[2];\r\n              if (mscore > P4_WIN){ \/\/we won! Don't look further.\r\n                  alpha = P4_KING_VALUE;\r\n                  break;\r\n              }\r\n              t = -p4_nullmove_alphabeta_treeclimber(state, count - 1, ncolour, mscore, ms, me,\r\n                                                    -beta, -alpha);\r\n              if (t > alpha)\r\n                  alpha = t;\r\n              if (alpha >= beta)\r\n                  break;\r\n          }\r\n          if (alpha < -P4_WIN_NOW && ! p4_check_check(state, colour)){\r\n              alpha = state.stalemate_scores[colour];\r\n          }\r\n          if (alpha < -P4_WIN){\r\n              alpha += P4_WIN_DECAY;\r\n          }\r\n      }\r\n      else{\r\n          \/\/leaf nodes\r\n          var movelist = p4_parse(state, colour, ep, -score);\r\n          var movecount = movelist.length;\r\n          while(beta > alpha && --movecount >= 0){\r\n              if(movelist[movecount][0] > alpha){\r\n                  alpha = movelist[movecount][0];\r\n              }\r\n          }\r\n      }\r\n      if (s)\r\n          p4_unmake_move(state, move);\r\n      return alpha;\r\n  }\r\n\r\n  function p4_nullmove_alphabeta_quiescing_treeclimber(state, count, colour, score, s, e,\r\n                                                      alpha, beta){\r\n      if (s)\r\n          var move = p4_make_move(state, s, e, P4_QUEEN);\r\n      var ep = s ? move.ep: 0;\r\n      var ncolour = 1 - colour;\r\n      var i, mv;\r\n      var board = state.board;\r\n      if(count){\r\n          var t;\r\n          \/* first try a null move. This sets a decent value for beta in\r\n            almost every situation (I think. seems to work).\r\n          *\/\r\n          if (count >= 2){\r\n              t = p4_nullmove_alphabeta_quiescing_treeclimber(state, count - 2, colour, score, 0, 0,\r\n                                                              alpha, beta);\r\n              if (t > beta){\r\n                  if(s)\r\n                      p4_unmake_move(state, move);\r\n                  return beta;\r\n              }\r\n          }\r\n          var movelist = p4_parse(state, colour, ep, -score);\r\n          var movecount = movelist.length;\r\n          for(i = 0; i < movecount; i++){\r\n              mv = movelist[i];\r\n              var mscore = mv[0];\r\n              var ms = mv[1];\r\n              var me = mv[2];\r\n              if (mscore > P4_WIN){ \/\/we won! Don't look further.\r\n                  alpha = P4_KING_VALUE;\r\n                  break;\r\n              }\r\n              t = -p4_nullmove_alphabeta_quiescing_treeclimber(state, count - 1, ncolour, mscore, ms, me,\r\n                                                              -beta, -alpha);\r\n              if (t > alpha){\r\n                  alpha = t;\r\n              }\r\n              if (alpha >= beta){\r\n                  break;\r\n              }\r\n          }\r\n\r\n          if (alpha < -P4_WIN_NOW && ! p4_check_check(state, colour)){\r\n              alpha = state.stalemate_scores[colour];\r\n          }\r\n          if (alpha < -P4_WIN){\r\n              \/*make distant checkmate seem less bad *\/\r\n              alpha += P4_WIN_DECAY;\r\n          }\r\n      }\r\n      else{\r\n          var movelist = p4_parse(state, colour, ep, -score);\r\n          var movecount = movelist.length;\r\n          var threshold = alpha - state.best_pieces[colour];\r\n          while(--movecount >= 0){\r\n              mv = movelist[movecount];\r\n              var mscore = mv[0];\r\n              var ms = mv[1];\r\n              var me = mv[2];\r\n              if (mscore > threshold && board[me]){\r\n                      \/\/console.log(\"quiescing\", score, mscore, alpha, beta);\r\n                      \/*a capture*\/\r\n                  mscore = -p4_quiesce(state, 1, ncolour, ms, me, -beta, -mscore);\r\n              }\r\n              if (mscore > alpha)\r\n                  alpha = mscore;\r\n          }\r\n      }\r\n      if(s)\r\n          p4_unmake_move(state, move);\r\n      return alpha;\r\n  }\r\n\r\n  function p4_quiesce(state, count, colour, s, e, alpha, beta){\r\n      if (alpha > beta)\r\n          return alpha;\r\n      var move = p4_make_move(state, s, e, P4_QUEEN);\r\n      var i;\r\n      var ncolour = 1 - colour;\r\n      var movelist = p4_parse(state, colour, move.ep, -alpha);\r\n      var movecount = movelist.length;\r\n      var mv;\r\n      if(count){\r\n          \/\/branch nodes\r\n          var t;\r\n          var board = state.board;\r\n          for(i = 0; i < movecount; i++){\r\n              mv = movelist[i];\r\n              var mscore = mv[0];\r\n              var ms = mv[1];\r\n              var me = mv[2];\r\n              if (board[me] == 0){\r\n                  \/*captures are sorted first, so we can break rather than continue*\/\r\n                  break;\r\n              }\r\n              if (mscore > P4_WIN){\r\n                  alpha = P4_KING_VALUE;\r\n                  break;\r\n              }\r\n              t = -p4_quiesce(state, count - 1, ncolour, ms, me, -beta, -mscore);\r\n              if (t > alpha){\r\n                  alpha = t;\r\n              }\r\n              if (alpha >= beta){\r\n                  break;\r\n              }\r\n          }\r\n          if (alpha < -P4_WIN_NOW && ! p4_check_check(state, colour)){\r\n              alpha = state.stalemate_scores[colour];\r\n          }\r\n          if (alpha < -P4_WIN){\r\n              alpha += P4_WIN_DECAY;\r\n          }\r\n      }\r\n      else{\r\n          \/\/leaf nodes\r\n          while(beta > alpha && --movecount != -1){\r\n              if(movelist[movecount][0] > alpha){\r\n                  alpha = movelist[movecount][0];\r\n              }\r\n          }\r\n      }\r\n      p4_unmake_move(state, move);\r\n      return alpha;\r\n  }\r\n\r\n  function p4_negascout_treeclimber2(state, count, colour, score, s, e, alpha, beta){\r\n      var move = p4_make_move(state, s, e, P4_QUEEN);\r\n      var i;\r\n      var ncolour = 1 - colour;\r\n      var movelist = p4_parse(state, colour, move.ep, -score);\r\n      var movecount = movelist.length;\r\n      var mv;\r\n      if(count){\r\n          \/\/branch nodes\r\n          var t;\r\n          var b = beta;\r\n          for(i = 0; i < movecount; i++){\r\n              mv = movelist[i];\r\n              var mscore = mv[0];\r\n              var ms = mv[1];\r\n              var me = mv[2];\r\n              if (mscore > P4_WIN){ \/\/we won! Don't look further.\r\n                  alpha = P4_KING_VALUE;\r\n                  break;\r\n              }\r\n              t = -p4_negascout_treeclimber2(state, count - 1, ncolour, mscore, ms, me,\r\n                                            -b, -alpha);\r\n              if (t > alpha && t < beta && i != 0){\r\n                  t = -p4_negascout_treeclimber2(state, count - 1, ncolour, mscore, ms, me,\r\n                                                -beta, -alpha);\r\n              }\r\n              if (t > alpha){\r\n                  alpha = t;\r\n              }\r\n              if (alpha >= beta){\r\n                  break;\r\n              }\r\n              b = alpha + 1;\r\n          }\r\n\r\n          if (alpha < -P4_WIN_NOW && ! p4_check_check(state, colour)){\r\n              alpha = state.stalemate_scores[colour];\r\n          }\r\n          if (alpha < -P4_WIN){\r\n              alpha += P4_WIN_DECAY;\r\n          }\r\n      }\r\n      else{\r\n          \/\/leaf nodes\r\n          while(beta > alpha && --movecount != -1){\r\n              if(movelist[movecount][0] > alpha){\r\n                  alpha = movelist[movecount][0];\r\n              }\r\n          }\r\n      }\r\n      p4_unmake_move(state, move);\r\n      return alpha;\r\n  }\r\n\r\n\r\n\r\n  function p4_negascout_treeclimber(state, count, colour, score, s, e, alpha, beta){\r\n      var move = p4_make_move(state, s, e, P4_QUEEN);\r\n      var i;\r\n      var ncolour = 1 - colour;\r\n      var movelist = p4_parse(state, colour, move.ep, -score);\r\n      var movecount = movelist.length;\r\n      var mv;\r\n      if(count){\r\n          \/\/branch nodes\r\n          var t;\r\n          var b = beta;\r\n          for(i = 0; i < movecount; i++){\r\n              mv = movelist[i];\r\n              var mscore = mv[0];\r\n              var ms = mv[1];\r\n              var me = mv[2];\r\n              if (mscore > P4_WIN){ \/\/we won! Don't look further.\r\n                  alpha = P4_KING_VALUE;\r\n                  break;\r\n              }\r\n              t = -p4_negascout_treeclimber(state, count - 1, ncolour, mscore, ms, me,\r\n                                            -b, -alpha);\r\n              if (t > alpha && t < beta && i != 0){\r\n                  t = -p4_negascout_treeclimber(state, count - 1, ncolour, mscore, ms, me,\r\n                                                -beta, -alpha);\r\n              }\r\n              if (t > alpha){\r\n                  alpha = t;\r\n              }\r\n              if (alpha >= beta){\r\n                  break;\r\n              }\r\n              b = alpha + 1;\r\n          }\r\n\r\n          if (alpha < -P4_WIN_NOW && ! p4_check_check(state, colour)){\r\n              alpha = state.stalemate_scores[colour];\r\n          }\r\n          if (alpha < -P4_WIN){\r\n              alpha += P4_WIN_DECAY;\r\n          }\r\n      }\r\n      else{\r\n          \/\/leaf nodes\r\n          while(beta > alpha && --movecount != -1){\r\n              if(movelist[movecount][0] > alpha){\r\n                  alpha = movelist[movecount][0];\r\n              }\r\n          }\r\n      }\r\n      p4_unmake_move(state, move);\r\n      return alpha;\r\n  }\r\n\r\n})()\r\n\r\nfunction generateRandom(maxLimit){\r\n  return Math.floor(Math.random() * (maxLimit || 10))\r\n}\r\n\r\nfunction getRandomInt(min, max) {\r\n    min = Math.ceil(min);\r\n    max = Math.floor(max);\r\n    return Math.floor(Math.random() * (max - min + 1)) + min;\r\n}\r\n\r\n\r\n\/\/ Init game\r\nvar game = new P4WN()","modules":{"storage":{},"notification":{},"audio":{}},"files":{"metart-my-queen-elvera-high-0002-cropped.jpg":{"id":2235268,"hash":"d5bfdb84ad562ff7db34b2315aeffcf73676fd5f","size":451540,"type":"image\/jpeg","width":1437,"height":1725}},"galleries":{"dee37de7-e225-4c69-a815-97b5abe59f8f":{"name":"Elvera - My Queen","images":[{"id":2230489,"hash":"b22e784be9ae329fbcb95858259816dd3f3792ff","size":561120,"width":1435,"height":2160},{"id":2230490,"hash":"be34ede411848f400cb5e58c4c1ed4aaa677e789","size":653876,"width":1437,"height":2160},{"id":2230491,"hash":"d0160147a03798e3f80d42d73a5f8e25afd641b8","size":642991,"width":1437,"height":2160},{"id":2230492,"hash":"750f31ef1a55f2a27ccfd3f533d1b1fa390eb399","size":578361,"width":2160,"height":1437},{"id":2230493,"hash":"89a7f9730c9d438f3d38e7587c446293c40aa496","size":584098,"width":2160,"height":1437},{"id":2230494,"hash":"eeedd8fc63dd0fdd8f08d38fc7e51e2a2e6eaf69","size":598879,"width":2160,"height":1437},{"id":2230495,"hash":"4aa8a396706ea536e143c6392c5734590bd25eef","size":633899,"width":2160,"height":1437},{"id":2230496,"hash":"fede50d5e436f8205de44562746ae46fed2b6c84","size":604227,"width":1437,"height":2160},{"id":2230497,"hash":"d97be55d801ea6bd138a20816e3dd0e843f14f5e","size":504673,"width":2160,"height":1437},{"id":2230498,"hash":"a41a6b34c821aa5d45e3432996bc0062bfdf1c4a","size":677279,"width":1436,"height":2160},{"id":2230499,"hash":"61c9b85d0f4e368dfeebf1be85b7b0bd984b389d","size":440190,"width":2160,"height":1437},{"id":2230500,"hash":"4431352cc269437eef46ceb37da3fc6be4397df9","size":566252,"width":1437,"height":2160},{"id":2230501,"hash":"2bb5ffa30d4c212c6659affb6b2be8e867cf37dc","size":591313,"width":1437,"height":2160},{"id":2230502,"hash":"96a0d4767dc8641bcf73a0657318146f35c7f782","size":647832,"width":2160,"height":1437},{"id":2230503,"hash":"31f04ac3e11cefe0c5450a6cab86ef84fd1a6321","size":675518,"width":2160,"height":1437},{"id":2230504,"hash":"566ac4690d3b7edcb66caefd0836f4edb8763617","size":790633,"width":1437,"height":2160},{"id":2230505,"hash":"34fdd06b6ddd27bb9ec14d0e6a1e8717bea12628","size":797607,"width":2160,"height":1437},{"id":2230506,"hash":"e4044affec770d2e2a8e82106495aa8cd4fd3663","size":938484,"width":2160,"height":1437},{"id":2230507,"hash":"90579f37de04aeddaf864f2863e4c8e05c69d62a","size":777145,"width":2160,"height":1437},{"id":2230508,"hash":"ed252b059c8f9c6a8b47d16afdee8f50456598e2","size":657215,"width":2160,"height":1437},{"id":2230509,"hash":"5d7b78333c65ced8419637dd67342972ff107ff6","size":411287,"width":2160,"height":1437},{"id":2230510,"hash":"20cba3bff09db4611054fd72fa78862db9c7c963","size":728236,"width":2160,"height":1437},{"id":2230511,"hash":"c25eed9bee56e172b4c279974aa394b16d38b779","size":428587,"width":2160,"height":1436},{"id":2230512,"hash":"3d38619d5ed0b4efa2e7801b1af21eea4d1749d2","size":502602,"width":2160,"height":1437},{"id":2230513,"hash":"acfc120b83f3425b74bdc0033d28bc2d6fb69ca8","size":582814,"width":2160,"height":1437},{"id":2230514,"hash":"fc1b29ed5bc5ae610cf390acaf34606bbc8f806c","size":607276,"width":2160,"height":1437},{"id":2230515,"hash":"2755e8c49b71e76bcc75a55dfca62438109467c3","size":668393,"width":2160,"height":1437},{"id":2230516,"hash":"d86b9387dca9d2b0211dca27b3dadc89517de93e","size":560530,"width":2160,"height":1437},{"id":2230517,"hash":"335ce5b7e24232adc134a93c026faa161298699a","size":652504,"width":2160,"height":1437},{"id":2230518,"hash":"d0f6328f11d16410ec4ca787aaaec47c3988de01","size":565420,"width":2160,"height":1437},{"id":2230519,"hash":"0f77af607ebaf76e9eff31e7ecc9f5039975a225","size":466567,"width":1436,"height":2160},{"id":2230520,"hash":"e679cc458e25aa50797f132346bc5703ded035bf","size":506576,"width":1437,"height":2160},{"id":2230521,"hash":"72adb7d992731a12327474a2e1197c98cc82b2ee","size":463258,"width":1437,"height":2160},{"id":2230522,"hash":"1e690eab1dedb327acba0940483d8568faf7e718","size":744338,"width":2160,"height":1437},{"id":2230523,"hash":"a6d56c40e1f5075f917fdb06202fc1fa666b0cef","size":660705,"width":2160,"height":1437},{"id":2230524,"hash":"733cfc232a3030b7a4cf9e76e57f497fb3f37a92","size":554060,"width":1437,"height":2160},{"id":2230525,"hash":"cae41a63afac3b2322d1f958a7afb2ce65e21d5f","size":499293,"width":2160,"height":1437},{"id":2230526,"hash":"4ed26cf9e2ad8e4518a50fc723e30dff867e57fc","size":537654,"width":2160,"height":1437},{"id":2230527,"hash":"926203d8c869614df337ed0f0bce98c2a4895a70","size":509037,"width":2160,"height":1437},{"id":2230528,"hash":"17b1a7d381788820fbce90cd776b366b233b6d1f","size":439099,"width":2160,"height":1437},{"id":2230529,"hash":"084280e10234715977ce61d40d0ff92387e6db8f","size":489346,"width":2160,"height":1437},{"id":2230530,"hash":"62329b31bd2fd72c80d04934e3658c71e6688161","size":481631,"width":2160,"height":1437},{"id":2230531,"hash":"638faf688d46390563c454fffd4a08dc826348d6","size":667067,"width":2160,"height":1437},{"id":2230532,"hash":"eb53a54c4f33812945df9784f548e29b6b09d303","size":655050,"width":2160,"height":1437},{"id":2230533,"hash":"c8a6cdd9b2a26b8320feacf92927e7761d8f64f2","size":687368,"width":1437,"height":2160},{"id":2230534,"hash":"d52314a3b32d10809818693d86085c4a361121eb","size":543000,"width":1437,"height":2160},{"id":2230535,"hash":"9e4d15ae201d0974463103dc980b4a327f0f9ab5","size":391456,"width":2160,"height":1437},{"id":2230536,"hash":"c440781a6a88ee97dc74099a2d550c274ab822f6","size":740753,"width":1437,"height":2160},{"id":2230537,"hash":"bf5d1dbb928a7c33beb10231dac98bb7601f9cd7","size":631671,"width":1437,"height":2160},{"id":2230538,"hash":"db158b97a7b1b95e675f9aa3c153d24779d6fbd1","size":678762,"width":1437,"height":2160},{"id":2230539,"hash":"378802b26aa607c5024699b4f41d9ecd4b754217","size":536086,"width":1437,"height":2160},{"id":2230540,"hash":"f3cf9f8564faeb504fefa32d8452f606cdfe5d70","size":626260,"width":1437,"height":2160},{"id":2230541,"hash":"19ab0548b70fbe3d41f40260cb40222c354f1789","size":528473,"width":1437,"height":2160},{"id":2230542,"hash":"791b0127f79d829fae3b22a3f0f9b7da7693c4e8","size":480051,"width":1437,"height":2160},{"id":2230543,"hash":"ce5e2a5014e6a7277833284c19247be9574a830f","size":482405,"width":1437,"height":2160},{"id":2230544,"hash":"0fa4dddf6edfb8ae41bdf2b392d0f1809aae41b0","size":571200,"width":1437,"height":2160},{"id":2230545,"hash":"15a9d6267eaf324499a651b6fd78476717adbac6","size":436427,"width":1437,"height":2160},{"id":2230546,"hash":"404dd8f8ae8af06d850ca9629aee5a5b80cff3d8","size":433867,"width":2160,"height":1437},{"id":2230547,"hash":"4c525648de1a277f0f1769103d963dedd5ca4b79","size":501120,"width":1437,"height":2160},{"id":2230548,"hash":"4dcc891d515c9a31364e00ac01d7e8f7a154cdf9","size":312673,"width":2160,"height":1437},{"id":2230549,"hash":"e4fd41839d24f277dca1f680d1ff96386f162fa4","size":417809,"width":2160,"height":1437},{"id":2230550,"hash":"ae4b4bb639ef21e555e3661c5d0fd6a2144dbd30","size":450165,"width":2160,"height":1437},{"id":2230551,"hash":"97b6ba55e4c0ce6c6de9603b0d2ada01afb746c1","size":517439,"width":2160,"height":1437},{"id":2230552,"hash":"02c08e2ed598849b4b7dc459afdadd0438ad9307","size":402010,"width":2160,"height":1437},{"id":2230553,"hash":"0dd5e7348e6f9f66d1da6797c14ddbaa6994483e","size":482410,"width":1437,"height":2160},{"id":2230554,"hash":"54de71aacce1f3c9ceb24721673a0a90a876c207","size":606916,"width":1437,"height":2160},{"id":2230555,"hash":"41914c04770d6954176fdd146eb5ae2292eddbed","size":643244,"width":2160,"height":1437},{"id":2230556,"hash":"77e5dc8ab9cc0416a152b2a2fa52c96e7527f7d3","size":516088,"width":1437,"height":2160},{"id":2230557,"hash":"1a0addef98bf0e869c670fc2b9a763dd91209e94","size":409740,"width":2160,"height":1437},{"id":2230558,"hash":"9b67ee3c5041ca8d71ff104fcc113efed755f411","size":548900,"width":1436,"height":2160},{"id":2230559,"hash":"447cb60a5bec33c603e65e5a6514115328a8bfd6","size":705558,"width":1437,"height":2160},{"id":2230560,"hash":"1fde4c4b5a12192db5291ec08c16b8a56ebc19b7","size":478984,"width":2160,"height":1437},{"id":2230561,"hash":"6a612ad6faff590e05066617cf44f71f43d49a27","size":477169,"width":2160,"height":1437},{"id":2230562,"hash":"e3871ea206f0429bf805f830bea331080bafbfcb","size":469514,"width":1437,"height":2160},{"id":2230563,"hash":"46cc812ffeb43228d4811b932e6e520adc298a13","size":469235,"width":1437,"height":2160},{"id":2230564,"hash":"67d8d66080ecfa3fc268a82286682e1175f14d66","size":384553,"width":2160,"height":1437},{"id":2230565,"hash":"357e3924838d1712c1ed77ecfef9709ee0b4ded7","size":419570,"width":2160,"height":1437},{"id":2230566,"hash":"446e60ffeb92e509027903276c509fd5b33b6102","size":356238,"width":2160,"height":1437},{"id":2230567,"hash":"14aae0cdcb27204722cfebf5485c534a16a55a33","size":463684,"width":1437,"height":2160},{"id":2230568,"hash":"d0ef4f34483d5fd35df57fbe094d6fbfbed939b8","size":623988,"width":2160,"height":1437},{"id":2230569,"hash":"0d225c3003cb0e64c279224cbc353999b6c38e0f","size":649361,"width":2160,"height":1437},{"id":2230570,"hash":"30bed0447b4208082a5101c6e815beb554a5b19d","size":526107,"width":2160,"height":1437},{"id":2230571,"hash":"bbb8fd1b11bcaf080ad9cfd6c8131ae1ff88157d","size":494341,"width":2160,"height":1437},{"id":2230572,"hash":"fb1f1df6b0e7315802fa5eef05e453beff4f7c1a","size":458269,"width":2160,"height":1437},{"id":2230573,"hash":"92b07be85bc02fc0af7b68567dae10a49c27bd18","size":599563,"width":1437,"height":2160},{"id":2230574,"hash":"cc1c0bbe6ce42c1ab738066956f0b2969ac0eb76","size":691667,"width":1437,"height":2160},{"id":2230576,"hash":"372bea4c1d9f951420cedfd9ab7358272a447085","size":725628,"width":1437,"height":2160},{"id":2230577,"hash":"6bc8814304861b80338a7f7b8832d4925d94d561","size":744396,"width":2160,"height":1437},{"id":2230578,"hash":"00a44ab50305ba99012bf541de07f41d15126a40","size":762864,"width":2160,"height":1437},{"id":2230579,"hash":"59351ef2cca919c37d88f9ae3a0818c8a089216d","size":713803,"width":1437,"height":2160},{"id":2230580,"hash":"95df6ce1140c13174a58cb69f1d887f1f72a72c8","size":644207,"width":1437,"height":2160},{"id":2230581,"hash":"28f5dfff0f82ecc7b4ebcd1d1148bbeb91bb043c","size":619938,"width":1437,"height":2160},{"id":2230582,"hash":"c0148bebaf9582e5996ea434dfac1b3f38f0ac9c","size":509682,"width":1437,"height":2160},{"id":2230583,"hash":"e8c34217fb66fc60f771373b348c0709f52503ea","size":512302,"width":2160,"height":1437},{"id":2230584,"hash":"800b425f882304d1612d36de083008433becbbe7","size":599509,"width":2160,"height":1437},{"id":2230585,"hash":"28ac6f4bcfd987b8fdaa196a62fb1fdc6faff045","size":525862,"width":1437,"height":2160},{"id":2230586,"hash":"0569b7a2ccb3e099df37e069a69a984009ed7571","size":546317,"width":2160,"height":1437},{"id":2230587,"hash":"58a542698dc8d06fd50c6f37934dab3edb208484","size":728094,"width":2160,"height":1437},{"id":2230588,"hash":"6a2febbcd70ef9514b2af583c7d448cd1693d058","size":800294,"width":1437,"height":2160},{"id":2230589,"hash":"e67295f72d82014894303ba5bc6b64190c138a8e","size":669753,"width":1437,"height":2160},{"id":2230590,"hash":"644453d33cbb37fc53a36e8aa4ad46deb847d3a6","size":721186,"width":1437,"height":2160},{"id":2230591,"hash":"43438d42efd5b809506e0466f15ab15549d30b11","size":832809,"width":2160,"height":1437},{"id":2230592,"hash":"7a342dc603ab6b2007cc1120e7baa7a0c3b4491e","size":929925,"width":2160,"height":1437},{"id":2230593,"hash":"442c0c6b7c739c44b47ae9c35ecce1bbcd46b002","size":759866,"width":2160,"height":1437},{"id":2230594,"hash":"ca71ebbaf1340fb0da23d3f8b4f33e6d93e30f67","size":714575,"width":2160,"height":1437},{"id":2230595,"hash":"64c3ba67d6d131209090441fa5b6a280d816b01d","size":731374,"width":2160,"height":1437},{"id":2230596,"hash":"c6bad5acf877f27f1913332fbac777455dbe122e","size":653460,"width":2160,"height":1437},{"id":2230597,"hash":"87cce57786a7d96a73c971ac4b1796903e218f8c","size":622057,"width":2160,"height":1437},{"id":2230598,"hash":"73545c6fa385db11f284c8f68ae3bdcf742f48d0","size":670282,"width":2160,"height":1437},{"id":2230599,"hash":"6fa79f2aac28989c7d76acd9cb26ee946d618a24","size":744090,"width":2160,"height":1437},{"id":2230600,"hash":"23921da9dcd5e2c772453a378ad35ba749621fc2","size":639880,"width":2160,"height":1437},{"id":2230601,"hash":"237642822f6c1849a320b7cad5cbf07b19f31171","size":595493,"width":2160,"height":1437},{"id":2230602,"hash":"b3f0d20e7d20fde14bf889dabf3e630b8e8ca17f","size":647436,"width":1437,"height":2160},{"id":2230603,"hash":"0ba2060cf72f041268b9d9669855477588c24452","size":789542,"width":2160,"height":1437},{"id":2230604,"hash":"b0fd77f3b62f6b92c5fc9b8819c9af1f230f5ca3","size":716892,"width":2160,"height":1437},{"id":2230605,"hash":"fe5d544a1c61d64e2f091eca576d5ccadf61bdeb","size":795746,"width":2160,"height":1437},{"id":2230606,"hash":"9c2a061bc36aa1007716eae569abd9b58677206f","size":737926,"width":2160,"height":1437},{"id":2230607,"hash":"aa2b4dbd2dd555681bac38bd7ddea10bd4751a5b","size":743844,"width":2160,"height":1437},{"id":2230608,"hash":"2e437f5bff2138d9dbe3446c913c0b6022115950","size":473215,"width":1435,"height":2160},{"id":2267597,"hash":"0f044056d75a44a129826d4eb3a7d535023ef0c3","size":1291558,"width":100,"height":100}]}},"editor":{"recentImages":[{"type":"gallery","mimeType":"image\/jpeg","galleryId":"dee37de7-e225-4c69-a815-97b5abe59f8f","url":"gallery:dee37de7-e225-4c69-a815-97b5abe59f8f\/2267597","imageId":2267597}]}}