goban-engine
Version:
This contains the built Go engine that is used by the Goban package. There are no display components in this package, only the logic for playing the game of Go, making it suitable for usage in node.js or other server-side environments.
2 lines • 112 kB
JavaScript
/*! For license information please see goban-engine.js.LICENSE.txt */
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports["goban-engine"]=t():e["goban-engine"]=t()}(this,(()=>(()=>{"use strict";var e={228:e=>{var t=Object.prototype.hasOwnProperty,r="~";function o(){}function i(e,t,r){this.fn=e,this.context=t,this.once=r||!1}function n(e,t,o,n,s){if("function"!=typeof o)throw new TypeError("The listener must be a function");var a=new i(o,n||e,s),h=r?r+t:t;return e._events[h]?e._events[h].fn?e._events[h]=[e._events[h],a]:e._events[h].push(a):(e._events[h]=a,e._eventsCount++),e}function s(e,t){0==--e._eventsCount?e._events=new o:delete e._events[t]}function a(){this._events=new o,this._eventsCount=0}Object.create&&(o.prototype=Object.create(null),(new o).__proto__||(r=!1)),a.prototype.eventNames=function(){var e,o,i=[];if(0===this._eventsCount)return i;for(o in e=this._events)t.call(e,o)&&i.push(r?o.slice(1):o);return Object.getOwnPropertySymbols?i.concat(Object.getOwnPropertySymbols(e)):i},a.prototype.listeners=function(e){var t=r?r+e:e,o=this._events[t];if(!o)return[];if(o.fn)return[o.fn];for(var i=0,n=o.length,s=new Array(n);i<n;i++)s[i]=o[i].fn;return s},a.prototype.listenerCount=function(e){var t=r?r+e:e,o=this._events[t];return o?o.fn?1:o.length:0},a.prototype.emit=function(e,t,o,i,n,s){var a=r?r+e:e;if(!this._events[a])return!1;var h,c,l=this._events[a],u=arguments.length;if(l.fn){switch(l.once&&this.removeListener(e,l.fn,void 0,!0),u){case 1:return l.fn.call(l.context),!0;case 2:return l.fn.call(l.context,t),!0;case 3:return l.fn.call(l.context,t,o),!0;case 4:return l.fn.call(l.context,t,o,i),!0;case 5:return l.fn.call(l.context,t,o,i,n),!0;case 6:return l.fn.call(l.context,t,o,i,n,s),!0}for(c=1,h=new Array(u-1);c<u;c++)h[c-1]=arguments[c];l.fn.apply(l.context,h)}else{var d,_=l.length;for(c=0;c<_;c++)switch(l[c].once&&this.removeListener(e,l[c].fn,void 0,!0),u){case 1:l[c].fn.call(l[c].context);break;case 2:l[c].fn.call(l[c].context,t);break;case 3:l[c].fn.call(l[c].context,t,o);break;case 4:l[c].fn.call(l[c].context,t,o,i);break;default:if(!h)for(d=1,h=new Array(u-1);d<u;d++)h[d-1]=arguments[d];l[c].fn.apply(l[c].context,h)}}return!0},a.prototype.on=function(e,t,r){return n(this,e,t,r,!1)},a.prototype.once=function(e,t,r){return n(this,e,t,r,!0)},a.prototype.removeListener=function(e,t,o,i){var n=r?r+e:e;if(!this._events[n])return this;if(!t)return s(this,n),this;var a=this._events[n];if(a.fn)a.fn!==t||i&&!a.once||o&&a.context!==o||s(this,n);else{for(var h=0,c=[],l=a.length;h<l;h++)(a[h].fn!==t||i&&!a[h].once||o&&a[h].context!==o)&&c.push(a[h]);c.length?this._events[n]=1===c.length?c[0]:c:s(this,n)}return this},a.prototype.removeAllListeners=function(e){var t;return e?(t=r?r+e:e,this._events[t]&&s(this,t)):(this._events=new o,this._eventsCount=0),this},a.prototype.off=a.prototype.removeListener,a.prototype.addListener=a.prototype.on,a.prefixed=r,a.EventEmitter=a,e.exports=a},336:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.callbacks=void 0,t.setGobanCallbacks=function(e){for(const r in e)void 0!==e[r]&&(t.callbacks[r]=e[r])},t.callbacks={getClockDrift:()=>0}},806:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.GobanBase=void 0;const o=r(925),i=r(228),n=r(336);let s=0;class a extends i.EventEmitter{static setTranslations=o.setGobanTranslations;static setCallbacks=n.setGobanCallbacks;goban_id=++s;_destroyed=!1;get destroyed(){return this._destroyed}constructor(){super()}destroy(){this.emit("destroy"),this._destroyed=!0,this.engine.removeAllListeners(),this.removeAllListeners()}decodeMoves(e){return this.engine.decodeMoves(e)}encodeMoves(e){return this.engine.encodeMoves(e)}encodeMove(e){return this.engine.encodeMove(e)}prettyCoordinates(e,t){return this.engine.prettyCoordinates(e,t)}decodePrettyCoordinates(e){return this.engine.decodePrettyCoordinates(e)}get is_game_record(){return this.engine.is_game_record}}t.GobanBase=a},906:function(e,t,r){var o=this&&this.__createBinding||(Object.create?function(e,t,r,o){void 0===o&&(o=r);var i=Object.getOwnPropertyDescriptor(t,r);i&&!("get"in i?!t.__esModule:i.writable||i.configurable)||(i={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,o,i)}:function(e,t,r,o){void 0===o&&(o=r),e[o]=t[r]}),i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),n=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)"default"!==r&&Object.prototype.hasOwnProperty.call(e,r)&&o(t,e,r);return i(t,e),t};Object.defineProperty(t,"__esModule",{value:!0}),t.BoardState=void 0;const s=r(228),a=r(896),h=r(460),c=n(r(688)),l=r(696),u=r(460),d=r(336);let _=0;const f=Array(625).fill(0);class p extends s.EventEmitter{height=19;width=19;board;removal;goban_callback;player;board_is_repeating;white_prisoners;black_prisoners;constructor(e,t){if(super(),this.goban_callback=t,this.width=e.width??e.board?.[0]?.length??19,this.height=e.height??e.board?.length??19,this.board=e.board?(0,u.cloneMatrix)(e.board):(0,h.makeMatrix)(this.width,this.height,a.JGOFNumericPlayerColor.EMPTY),this.removal=e.removal?(0,u.cloneMatrix)(e.removal):(0,h.makeMatrix)(this.width,this.height,!1),this.height!==this.board.length||this.width!==this.board[0].length)throw new Error("Board size mismatch");if(this.height!==this.removal.length||this.width!==this.removal[0].length)throw new Error("Removal size mismatch");this.player=e.player??a.JGOFNumericPlayerColor.EMPTY,this.board_is_repeating=e.board_is_repeating??!1,this.white_prisoners=e.white_prisoners??0,this.black_prisoners=e.black_prisoners??0}cloneBoardState(){return new p(this,this.goban_callback)}cloneBoard(){return this.board.map((e=>e.slice()))}toggleSingleGroupRemoval(e,t,r=!1){const o={removed:!1,group:[]};if(e<0||t<0)return o;try{if(e>=0&&t>=0){const i=!this.removal[t][e];if(this.board[t][e]===a.JGOFNumericPlayerColor.EMPTY)return o;const n=new l.StoneStringBuilder(this,this.board).getGroup(e,t);if(i&&!r){const r=c.territoryScoring(this.board,this.removal,!1);let i=0,s=0;if(n.foreachNeighboringEmptyString((o=>{let n=!1;o.map((o=>{r[o.y][o.x].isTerritoryFor!==this.board[t][e]||r[o.y][o.x].isFalseEye||(n=!0)})),n&&(s+=1,i+=o.intersections.length)})),i>=5||s>=2)return console.log("This group is almost assuredly alive, refusing to remove"),d.callbacks.toast?.("refusing_to_remove_group_is_alive",4e3),o}return n.map((({x:e,y:t})=>this.setRemoved(e,t,i,!1))),this.emit("stone-removal.updated"),{removed:i,group:n.intersections}}}catch(i){console.log(i.stack)}return o}setRemoved(e,t,r,o=!0){e<0||t<0||e>this.width||t>this.height||(this.removal[t][e]=r,this.goban_callback&&this.goban_callback.setForRemoval(e,t,this.removal[t][e],o))}clearRemoved(){let e=!1;for(let t=0;t<this.height;++t)for(let r=0;r<this.width;++r)this.removal[t][r]&&(e=!0,this.setRemoved(r,t,!1,!1));e&&this.emit("stone-removal.updated")}getNeighboringRawStoneStrings(e){const t=e;++_,this._floodFillMarkFilled(e);const r=[];return this.foreachNeighbor(e,((e,o)=>{if(this.board[o][e]){++_,this._floodFillMarkFilled(t);for(let e=0;e<r.length;++e)this._floodFillMarkFilled(r[e]);const i=this.getRawStoneString(e,o,!1);i.length&&r.push(i)}})),r}getRawStoneString(e,t,r){const o=this.board[t][e];r&&++_;const i=[e],n=[t],s=[];for(;i.length;)if(e=i.pop()||0,t=n.pop()||0,f[t*this.width+e]!==_&&(f[t*this.width+e]=_,this.board[t][e]===o)){const r={x:e,y:t};s.push(r),this.foreachNeighbor(r,a)}function a(e,t){i.push(e),n.push(t)}return s}_floodFillMarkFilled(e){for(let t=0;t<e.length;++t)f[e[t].y*this.width+e[t].x]=_}countLiberties(e){let t=0;const r=(0,h.makeMatrix)(this.width,this.height,0),o=(e,o)=>{0===this.board[o][e]&&0===r[o][e]&&(r[o][e]=1,t+=1)};for(let i=0;i<e.length;++i)this.foreachNeighbor(e[i],o);return t}computeLibertyMap(){const e=(0,h.makeMatrix)(this.width,this.height,0);if(!this.board)return e;for(let t=0;t<this.height;++t)for(let r=0;r<this.width;++r)if(this.board[t][r]&&!e[t][r]){const o=this.getRawStoneString(r,t,!0),i=this.countLiberties(o);for(const t of o)e[t.y][t.x]=i}return e}foreachNeighbor(e,t){if(e instanceof Array){const r=e,o=new Array(this.height*this.width);for(let e=0;e<r.length;++e)o[r[e].x+r[e].y*this.width]=!0;const i=(e,r)=>{const i=e+r*this.width;o[i]||(o[i]=!0,t(e,r))};for(let e=0;e<r.length;++e){const t=r[e];t.x-1>=0&&i(t.x-1,t.y),t.x+1!==this.width&&i(t.x+1,t.y),t.y-1>=0&&i(t.x,t.y-1),t.y+1!==this.height&&i(t.x,t.y+1)}}else{const r=e;r.x-1>=0&&t(r.x-1,r.y),r.x+1!==this.width&&t(r.x+1,r.y),r.y-1>=0&&t(r.x,r.y-1),r.y+1!==this.height&&t(r.x,r.y+1)}}boardEquals(e){return(0,u.matricesAreEqual)(this.board,e.board)}computeScoringLocations(e){const t={black:{territory:0,stones:0,locations:[]},white:{territory:0,stones:0,locations:[]}};if(e){const e=c.areaScoring(this.board,this.removal);for(let r=0;r<this.height;++r)for(let o=0;o<this.width;++o)e[r][o]===c.BLACK?(this.board[r][o]===a.JGOFNumericPlayerColor.BLACK?t.black.stones+=1:t.black.territory+=1,t.black.locations.push({x:o,y:r})):e[r][o]===c.WHITE&&(this.board[r][o]===a.JGOFNumericPlayerColor.WHITE?t.white.stones+=1:t.white.territory+=1,t.white.locations.push({x:o,y:r}))}else{const e=c.territoryScoring(this.board,this.removal);for(let r=0;r<this.height;++r)for(let o=0;o<this.width;++o)e[r][o].isTerritoryFor===c.BLACK?(t.black.territory+=1,t.black.locations.push({x:o,y:r})):e[r][o].isTerritoryFor===c.WHITE&&(t.white.territory+=1,t.white.locations.push({x:o,y:r}))}return t}}t.BoardState=p},878:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ConditionalMoveTree=void 0;class r{children;parent;move;constructor(e,t){this.move=e,this.parent=t,this.children={}}encode(){const e={};for(const t in this.children)e[t]=this.children[t].encode();return[this.move,e]}static decode(e){const t=e[0],o=e[1],i=new r(t);for(const n in o){const e=r.decode(o[n]);e.parent=i,i.children[n]=e}return i}getChild(e){return e in this.children?this.children[e]:new r(null,this)}duplicate(){return r.decode(this.encode())}}t.ConditionalMoveTree=r},82:function(e,t,r){var o=this&&this.__createBinding||(Object.create?function(e,t,r,o){void 0===o&&(o=r);var i=Object.getOwnPropertyDescriptor(t,r);i&&!("get"in i?!t.__esModule:i.writable||i.configurable)||(i={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,o,i)}:function(e,t,r,o){void 0===o&&(o=r),e[o]=t[r]}),i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),n=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)"default"!==r&&Object.prototype.hasOwnProperty.call(e,r)&&o(t,e,r);return i(t,e),t};Object.defineProperty(t,"__esModule",{value:!0}),t.GobanEngine=t.AUTOSCORE_TOLERANCE=t.AUTOSCORE_TRIALS=void 0;const s=r(906),a=r(408),h=r(862),c=r(460),l=r(187),u=r(896),d=n(r(688));t.AUTOSCORE_TRIALS=1e3,t.AUTOSCORE_TOLERANCE=.1;class _ extends s.BoardState{throw_all_errors;handicap_rank_difference;handicap=NaN;initial_state={black:"",white:""};komi=NaN;move_tree;move_tree_layout_vector=[];move_tree_layout_hash={};move_tree_layout_dirty=!1;name="";player_pool;latencies;players={black:{username:"black",id:NaN},white:{username:"white",id:NaN}};puzzle_collection=NaN;puzzle_description="[missing puzzle description]";puzzle_opponent_move_mode="manual";puzzle_player_move_mode="free";puzzle_rank=NaN;puzzle_type="[missing puzzle type]";config;disable_analysis=!1;time_control={system:"none",speed:"correspondence",pause_on_weekends:!0};game_id=NaN;review_id;decoded_moves=[];automatic_stone_removal=!1;group_ids;rengo;rengo_teams;rengo_casual_mode;stalling_score_estimate;is_game_record=!1;_phase="play";get phase(){return this._phase}set phase(e){this._phase!==e&&(this._phase=e,this.emit("phase",this.phase))}_cur_move;get cur_move(){return this._cur_move}set cur_move(e){this._cur_move!==e&&(this._cur_move=e,this.emit("cur_move",this.cur_move))}_cur_review_move;get cur_review_move(){return this._cur_review_move}set cur_review_move(e){this._cur_review_move!==e&&(this._cur_review_move=e,this.emit("cur_review_move",this.cur_review_move))}_last_official_move;get last_official_move(){return this._last_official_move}set last_official_move(e){this._last_official_move!==e&&(this._last_official_move=e,this.emit("last_official_move",this.last_official_move))}_strict_seki_mode=!1;get strict_seki_mode(){return this._strict_seki_mode}set strict_seki_mode(e){this._strict_seki_mode!==e&&(this._strict_seki_mode=e,this.emit("strict_seki_mode",this.strict_seki_mode))}_rules="japanese";get rules(){return this._rules}set rules(e){this._rules!==e&&(this._rules=e,this.emit("rules",this.rules))}_winner;get winner(){return this._winner}set winner(e){this._winner!==e&&(this._winner=e,"number"==typeof e&&this.emit("winner",this.winner))}_undo_requested;get undo_requested(){return this._undo_requested}set undo_requested(e){this._undo_requested!==e&&(this._undo_requested=e,this.emit("undo_requested",this.undo_requested))}_outcome="";get outcome(){return this._outcome}set outcome(e){this._outcome!==e&&(this._outcome=e,this.emit("outcome",this.outcome))}aga_handicap_scoring=!1;allow_ko=!1;allow_self_capture=!1;allow_superko=!1;superko_algorithm="psk";dontStoreBoardHistory;free_handicap_placement=!1;loading_sgf=!1;move_before_jump;needs_sealing;score_prisoners=!1;score_stones=!1;score_handicap=!1;score_territory=!1;score_territory_in_seki=!1;territory_included_in_sgf=!1;constructor(e,t,r){super(_.fillDefaults(_.migrateConfig((e=>{try{"original_sgf"in e&&(e.initial_state={black:"",white:""})}catch(t){console.log(t)}return e})(e))),t);for(const a in e)"move_tree"!==a&&(this[a]=e[a]);const o=this;this.config=e,this.is_game_record=!!e.is_game_record,this.dontStoreBoardHistory=!!r,t&&(this.goban_callback=t,this.goban_callback.engine=this),this.white_prisoners=0,this.black_prisoners=0,this.board_is_repeating=!1,this.players=e.players||{black:{username:"black",id:NaN},white:{username:"white",id:NaN}},this.player_pool=e.player_pool||{},this.rengo_casual_mode=e.rengo_casual_mode||!1;try{this.config.original_disable_analysis=this.config.disable_analysis,"undefined"!=typeof window&&void 0!==window.user&&window.user&&!this.isParticipant(window.user.id)&&(this.disable_analysis=!1,this.config.disable_analysis=!1)}catch(s){console.log(s)}if(this.player=1,"initial_player"in e&&(this.player="white"===e.initial_player?2:1),e.players&&(this.player_pool[e.players.black.id]=e.players.black,this.player_pool[e.players.white.id]=e.players.white),e.rengo&&e.rengo_teams)for(const a of e.rengo_teams.black.concat(e.rengo_teams.white))this.player_pool[a.id]=a;let i,n=()=>{};if(e.original_sgf&&(e.initial_state={black:e.initial_state?.black||"",white:e.initial_state?.white||""},"play"===this.phase&&(this.phase="finished"),n=this.parseSGF(e.original_sgf)),e.initial_state){this.initial_state=e.initial_state;const t=this.decodeMoves(e.initial_state.black||""),r=this.decodeMoves(e.initial_state.white||"");for(let e=0;e<t.length;++e){const r=t[e].x,o=t[e].y;this.initialStatePlace(r,o,1,!0)}for(let e=0;e<r.length;++e){const t=r[e].x,o=r[e].y;this.initialStatePlace(t,o,2,!0)}}this.move_tree=new h.MoveTree(this,!0,-1,-1,!1,0,0,null,this.getState()),this._cur_move=this.move_tree,this._last_official_move=this.cur_move,delete this.move_before_jump;try{this.loading_sgf=!0,n(),this.loading_sgf=!1}catch(s){console.log("Error loading SGF: ",s.message),s.stack&&console.log(s.stack)}if(e.moves){const t=this.decoded_moves=this.decodeMoves(e.moves);for(let r=0;r<t.length;++r){const o=t[r];if(o.edited)this.editPlace(o.x,o.y,o.color||0,!0);else try{this.place(o.x,o.y,!1,!1,!0,!0,!0),o.player_update&&(this.cur_move.player_update=o.player_update,this.updatePlayers(o.player_update)),o.played_by&&(this.cur_move.played_by=o.played_by)}catch(s){if(this.throw_all_errors)throw s;e.errors||(e.errors=[]),e.errors.push({error:`Error placing ${this.cur_move.player===u.JGOFNumericPlayerColor.BLACK?"black":"white"} at ${this.prettyCoordinates(o.x,o.y)} (${o.x}, ${o.y})`,stack:s.stack}),console.log(e.errors[e.errors.length-1]),this.editPlace(o.x,o.y,o.color||0,!0)}}}if(e.move_tree&&function e(t,r){if(t.loadJsonForThisNode(r),r.trunk_next){const i=r.trunk_next;o.place(i.x,i.y,!1,!1,!0,!0,!0),e(o.cur_move,i),o.jumpTo(t)}if(r.branches)for(let i=0;i<r.branches.length;++i){const n=r.branches[i];o.place(n.x,n.y,!1,!1,!0,!0,!1),e(o.cur_move,n),o.jumpTo(t)}}(this.move_tree,e.move_tree),e.removed&&(i=this.decodeMoves(e.removed)),i){for(let e=0;e<i.length;++e)this.setRemoved(i[e].x,i[e].y,!0,!1);this.emit("stone-removal.updated")}if(e.needs_sealing){if(this.needs_sealing=e.needs_sealing,"stone removal"===this.phase)for(const t of e.needs_sealing)this.setNeedsSealing(t.x,t.y,!0);this.emit("stone-removal.needs-sealing",e.needs_sealing)}}decodeMoves(e){return(0,c.decodeMoves)(e,this.width,this.height)}encodeMoves(e){return(0,c.encodeMoves)(e)}encodeMove(e){return(0,c.encodeMoves)([e])}decodePrettyCoordinates(e){return(0,c.decodePrettyCoordinates)(e,this.height)}prettyCoordinates(e,t){return"number"!=typeof e&&(t=e.y,e=e.x),(0,c.prettyCoordinates)(e,t,this.height)}getState(){return this.cloneBoardState()}setState(e){this.player=e.player,this.white_prisoners=e.white_prisoners,this.black_prisoners=e.black_prisoners,this.board_is_repeating=e.board_is_repeating,this.goban_callback?.setState?.();const t=(0,c.makeMatrix)(this.width,this.height,!1);for(let r=0;r<this.height;++r)for(let o=0;o<this.width;++o)(this.board[r][o]!==e.board[r][o]||this.cur_move.x===o&&this.cur_move.y===r)&&(this.board[r][o]=e.board[r][o],t[r][o]=!0),(this.removal[r][o]!==e.removal[r][o]||this.cur_move.x===o&&this.cur_move.y===r)&&(this.removal[r][o]=e.removal[r][o],t[r][o]=!0);if(this.goban_callback)for(let r=0;r<this.height;++r)for(let e=0;e<this.width;++e)this.goban_callback.set(e,r,this.board[r][e]);return e}currentPositionId(){return(0,c.positionId)(this.board,this.height,this.width)}followPath(e,t,r){try{const o=[],i=this.move_tree.index(e);let n;n=i||this.last_official_move;const s=this.decodeMoves(t);let a=0;for(;a<s.length;){const e=s[a],t=n.lookupMove(e.x,e.y,this.playerByColor(e.color||0),!!e.edited);if(!t)break;n=t,++a,r&&r(e.x,e.y,!!e.edited,e.color||0)}for(this.jumpTo(n);a<s.length;++a){const e=s[a];e.edited?this.editPlace(e.x,e.y,e.color||0):this.place(e.x,e.y,!1,!1,!0,!0),r&&r(e.x,e.y,!!e.edited,e.color||0),o.push(this.cur_move)}return o}catch(o){return console.log(o.stack),this.jumpTo(this.last_official_move),[]}}updatePlayers(e){if(!this.player_pool)throw new Error("updatePlayers called with no player_pool available");this.players.black=this.player_pool[e.players.black],this.players.white=this.player_pool[e.players.white];try{if(this.config.rengo&&e.rengo_teams){this.rengo_teams={black:[],white:[]};for(const t of["black","white"])for(const r of e.rengo_teams[t])this.rengo_teams[t].push(this.player_pool[r])}}catch(t){console.error(t),console.error(t.stack)}this.config.black_player_id=e.players.black,this.config.white_player_id=e.players.white,this.emit("player-update",e)}showPrevious(){return!this.dontStoreBoardHistory&&(!!this.cur_move.prev()&&(this.jumpTo(this.cur_move.prev()),!0))}showNext(){return!this.dontStoreBoardHistory&&(!!this.cur_move.next()&&(this.jumpTo(this.cur_move.next()),!0))}showNextTrunk(){return!this.dontStoreBoardHistory&&(!!this.cur_move.trunk_next&&(this.jumpTo(this.cur_move.trunk_next),!0))}jumpTo(e){e&&(this.move_before_jump=this.cur_move,this.setState(e.state),this.cur_move=e,e.player_update&&this.updatePlayers(e.player_update))}jumpToLastOfficialMove(){this.dontStoreBoardHistory||this.jumpTo(this.last_official_move)}setLastOfficialMove(){if(!this.dontStoreBoardHistory){if(!this.cur_move.trunk&&!("original_sgf"in this.config))throw new Error("Attempted to set official move to non-trunk move.");this.last_official_move=this.cur_move}}isLastOfficialMove(){return this.cur_move.is(this.last_official_move)}getMoveDiff(){const e=this.cur_move.getBranchPoint();let t=this.cur_move;const r=[];for(;t&&t.id!==e.id;)r.push({x:t.x,y:t.y,color:t.player,edited:t.edited}),t=t.parent;return r.reverse(),{from:e.getMoveIndex(),moves:(0,c.encodeMoves)(r)}}setAsCurrentReviewMove(){this.dontStoreBoardHistory||(this.cur_review_move=this.cur_move)}deleteCurMove(){if(this.cur_move.id===this.move_tree.id)return void console.log("Wont remove move tree itself.");if(this.cur_move.trunk)return void console.log("Wont remove trunk node");const e=this.cur_move.parent;this.cur_move.remove(),this.cur_move=e||this.move_tree,this.jumpTo(e)}gameCanBeCancelled(){if("play"!==this.phase)return!1;if("tournament_id"in this.config&&this.config.tournament_id)return!1;if("ladder_id"in this.config&&this.config.ladder_id)return!1;if(this.rengo&&this.rengo_casual_mode)return!1;return this.getMoveNumber()<5+(this.free_handicap_placement?this.handicap:1)}jumpToOfficialMoveNumber(e){if(!this.dontStoreBoardHistory){for(;this.showPrevious(););for(let t=0;t<e;++t)this.cur_move.next(!0)&&this.jumpTo(this.cur_move.next(!0))}}opponent(){return 1===this.player?2:1}captureGroup(e){for(let t=0;t<e.length;++t){const r=e[t].x,o=e[t].y;1===this.board[o][r]&&++this.white_prisoners,2===this.board[o][r]&&++this.black_prisoners,this.board[o][r]=0,this.goban_callback&&this.goban_callback.set(r,o,0)}return e.length}isParticipant(e){return(this.rengo&&this.rengo_teams?this.rengo_teams.black.concat(this.rengo_teams.white):[this.players.black,this.players.white]).map((e=>e.id)).includes(e)}isActivePlayer(e){return[this.players.black,this.players.white].map((e=>e.id)).includes(e)}playerToMoveOnOfficialBranch(){return 1===this.last_official_move.state.player?this.players.black.id:this.players.white.id}playerToMove(){return 1===this.player?this.players.black.id:this.players.white.id}playerNotToMove(){return 2===this.player?this.players.black.id:this.players.white.id}otherPlayer(){return 2===this.player?1:2}playerColor(e){return"number"==typeof e?e===this.players.black.id?"black":e===this.players.white.id?"white":"invalid":this.colorToMove()}colorToMove(){return 1===this.player?"black":"white"}colorNotToMove(){return 1!==this.player?"black":"white"}playerByColor(e){return"black"===e?1:"white"===e?2:1===e||2===e?e:0}place(e,t,r,o,i,n,s,h){let c=0;try{if(e>=0&&t>=0&&e<this.width&&t<this.height){if(this.board[t][e]){if("loading_sgf"in this&&this.loading_sgf)return this.board[t][e]!==this.player&&(console.log("Invalid duplicate stone placement at "+this.prettyCoordinates(e,t)+" board color: "+this.board[t][e]+" placed color: "+this.player+" - edit placing into new branch"),this.editPlace(e,t,this.player),this.player=this.opponent()),0;throw new a.GobanMoveError(this.game_id||this.review_id||0,this.cur_move?.move_number??-1,this.prettyCoordinates(e,t),"stone_already_placed_here")}this.board[t][e]=this.player;let s=!1;const l=this.getRawStoneString(e,t,!0),u=this.getNeighboringRawStoneStrings(l);for(let e=0;e<u.length;++e)0===this.countLiberties(u[e])&&(void 0!==h&&u[e].map((e=>h.push(e))),c+=this.captureGroup(u[e]));if(0===c&&0===this.countLiberties(l)){if(!this.allow_self_capture&&!n)throw this.board[t][e]=0,new a.GobanMoveError(this.game_id||this.review_id||0,this.cur_move?.move_number??-1,this.prettyCoordinates(e,t),"illegal_self_capture");c+=this.captureGroup(l),s=!0}if(r&&!this.allow_ko&&!this.cur_move.edited&&this.boardEquals(this.cur_move.index(-1).state))throw new a.GobanMoveError(this.game_id||this.review_id||0,this.cur_move?.move_number??-1,this.prettyCoordinates(e,t),"illegal_ko_move");if(this.board_is_repeating=!1,!i&&!this.allow_superko&&(this.board_is_repeating=this.isBoardRepeating(this.superko_algorithm),this.board_is_repeating&&o))throw new a.GobanMoveError(this.game_id||this.review_id||0,this.cur_move?.move_number??-1,this.prettyCoordinates(e,t),"illegal_board_repetition");s||this.goban_callback&&this.goban_callback.set(e,t,this.player)}if(e<0&&this.handicapMovesLeft()>0)return 0;const l=this.player;this.handicapMovesLeft()<2&&(this.player=this.opponent());const u=this.cur_move.move_number+1,d=!!s;this.cur_move=this.cur_move.move(e,t,d,!1,l,u,this.getState())}catch(l){throw this.jumpTo(this.cur_move),l}return c}isBoardRepeating(e){const t=this.player,r="ssk"===e;let o=this.cur_move.index(-2);for(let i=Math.min(30,this.cur_move.move_number-2);i>0;--i,o=o?.prev())if(o&&(!r||o.player===t)&&this.boardEquals(o.state))return!0;return!1}editPlace(e,t,r,o){const i=this.playerByColor(r);e>=0&&t>=0&&(this.board[t][e]=i,this.goban_callback&&this.goban_callback.set(e,t,i));const n=!!o;this.cur_move=this.cur_move.move(e,t,n,!0,i,this.cur_move.move_number,this.getState())}initialStatePlace(e,t,r,o){let i=null;const n=this.player;if(this.move_tree&&this.jumpTo(this.move_tree),this.player=n,e>=0&&t>=0&&(this.board[t][e]=r,this.goban_callback&&this.goban_callback.set(e,t,r)),!o){i=this.decodeMoves(this.initial_state?.black||"");for(let r=0;r<i.length;++r)if(i[r].x===e&&i[r].y===t){i.splice(r,1);break}this.initial_state.black=(0,c.encodeMoves)(i),i=this.decodeMoves(this.initial_state?.white||"");for(let r=0;r<i.length;++r)if(i[r].x===e&&i[r].y===t){i.splice(r,1);break}if(this.initial_state.white=(0,c.encodeMoves)(i),r){const o=this.decodeMoves(this.initial_state[1===r?"black":"white"]||"");o.push({x:e,y:t,color:r}),this.initial_state[1===r?"black":"white"]=(0,c.encodeMoves)(o)}}this.resetMoveTree()}resetMoveTree(){let e=null;this.move_tree&&(e=this.move_tree.getAllMarks()),this.move_tree=new h.MoveTree(this,!0,-1,-1,!1,0,0,null,this.getState()),this.cur_move=this.move_tree,this.last_official_move=this.cur_move,delete this.move_before_jump,e&&this.move_tree.setAllMarks(e),"initial_player"in this.config&&(this.player="white"===this.config.initial_player?2:1)}computeInitialStateForForkedGame(){let e="",t="";for(let r=0;r<this.height;++r)for(let o=0;o<this.width;++o)1===this.board[r][o]?e+=(0,c.encodeMove)(o,r):2===this.board[r][o]&&(t+=(0,c.encodeMove)(o,r));return{black:e,white:t}}setNeedsSealing(e,t,r){this.cur_move.getMarks(e,t).needs_sealing=r}getStoneRemovalString(){let e="";const t=[];for(let r=0;r<this.height;++r)for(let e=0;e<this.width;++e)this.removal[r][e]&&t.push((0,c.encodeMove)(e,r));for(let r=0;r<t.length;++r)e+=t[r];return(0,c.sortMoves)(e,this.width,this.height)}getMoveNumber(){return this.cur_move?this.cur_move.move_number:0}getCurrentMoveNumber(){return this.last_official_move.move_number}computeScore(e){const t={white:{total:0,stones:0,territory:0,prisoners:0,scoring_positions:"",handicap:this.getHandicapPointAdjustmentForWhite(),komi:this.komi},black:{total:0,stones:0,territory:0,prisoners:0,scoring_positions:"",handicap:0,komi:0}};if(e||this.score_prisoners){t.white.prisoners=this.white_prisoners,t.black.prisoners=this.black_prisoners;for(let e=0;e<this.height;++e)for(let r=0;r<this.width;++r)this.removal[e][r]&&(this.board[e][r]===u.JGOFNumericPlayerColor.BLACK&&(t.white.prisoners+=1),this.board[e][r]===u.JGOFNumericPlayerColor.WHITE&&(t.black.prisoners+=1))}if(!e){if(!this.score_territory)throw new Error("The score_territory flag should always be set to true");if(this.score_stones){const e=d.areaScoring(this.board,this.removal);for(let r=0;r<this.height;++r)for(let o=0;o<this.width;++o)e[r][o]===d.BLACK?(this.board[r][o]===u.JGOFNumericPlayerColor.BLACK?t.black.stones+=1:t.black.territory+=1,t.black.scoring_positions+=(0,c.encodeMove)(o,r)):e[r][o]===d.WHITE&&(this.board[r][o]===u.JGOFNumericPlayerColor.WHITE?t.white.stones+=1:t.white.territory+=1,t.white.scoring_positions+=(0,c.encodeMove)(o,r))}else{const e=d.territoryScoring(this.board,this.removal);for(let r=0;r<this.height;++r)for(let o=0;o<this.width;++o)e[r][o].isTerritoryFor===d.BLACK?(t.black.territory+=1,t.black.scoring_positions+=(0,c.encodeMove)(o,r)):e[r][o].isTerritoryFor===d.WHITE&&(t.white.territory+=1,t.white.scoring_positions+=(0,c.encodeMove)(o,r))}}t.black.total=t.black.stones+t.black.territory+t.black.prisoners+t.black.handicap+t.black.komi,t.white.total=t.white.stones+t.white.territory+t.white.prisoners+t.white.handicap+t.white.komi;try{if(this.outcome&&this.aga_handicap_scoring){parseFloat(this.outcome)-1===Math.abs(t.white.total-t.black.total)&&(t.white.handicap+=1)}}catch(r){console.log(r)}return this.jumpTo(this.cur_move),t}handicapMovesLeft(){return this.free_handicap_placement?Math.max(0,this.handicap-this.getMoveNumber()):0}static migrateConfig(e){if(e.ladder!==e.ladder_id&&(e.ladder_id=e.ladder),"ladder"in e&&delete e.ladder,"resign"!==e.outcome&&"r"!==e.outcome||(e.outcome="Resignation"),e.black_player_id||e.white_player_id){if(e.players||(e.players={black:{username:"black",id:e.black_player_id||NaN},white:{username:"white",id:e.white_player_id||NaN}}),!e.players||!e.players.black||!e.players.white)throw new Error(`config.players is invalid: ${JSON.stringify(e.players)}`);if(e.players.black.id=e.players.black.id??e.black_player_id,e.players.white.id=e.players.white.id??e.white_player_id,e.players.black.id!==e.black_player_id)throw new Error(`config.players.black.id (${e.players.black.id}) !== deprecated config.black_player_id (${e.black_player_id})`);if(e.players.white.id!==e.white_player_id)throw new Error(`config.players.white.id (${e.players.white.id}) !== deprecated config.white_player_id (${e.white_player_id})`)}return e}static fillDefaults(e){"phase"in e||(e.phase="play"),"rules"in e||(e.rules="japanese");const t={game_id:0,initial_player:"black",moves:[],width:19,height:19,rules:"chinese",allow_self_capture:!1,automatic_stone_removal:!1,handicap:0,free_handicap_placement:!1,aga_handicap_scoring:!1,allow_ko:!1,allow_superko:!1,superko_algorithm:"psk",players:{black:{username:"Black",id:NaN,rank:-1},white:{username:"White",id:NaN,rank:-1}},player_pool:{},disable_analysis:!1,score_territory:!0,score_territory_in_seki:!0,score_stones:!0,score_handicap:!1,score_prisoners:!0,score_passes:!0,white_must_pass_last:!1,opponent_plays_first_after_resume:!1};t.strict_seki_mode="finished"===e.phase;const r=e.rules||t.rules;switch(r.toLowerCase()){case"chinese":t.komi=7.5,t.score_prisoners=!1,t.allow_superko=!1,t.free_handicap_placement=!0,t.superko_algorithm="csk",t.score_handicap=!0,"ogs_import"in e&&(t.free_handicap_placement=!1);break;case"aga":t.komi=7.5,t.score_prisoners=!1,t.allow_superko=!1,t.superko_algorithm="ssk",t.white_must_pass_last=!0,t.aga_handicap_scoring=!0,t.score_handicap=!0;break;case"japanese":case"korean":t.komi=6.5,t.allow_superko=!0,t.score_territory_in_seki=!1,t.score_stones=!1,t.superko_algorithm="noresult",t.opponent_plays_first_after_resume=!0;break;case"ing":t.komi=7.5,t.score_prisoners=!1,t.allow_superko=!1,t.superko_algorithm="ing",t.free_handicap_placement=!0,t.allow_self_capture=!0,t.score_handicap=!0;break;case"nz":t.komi=7,t.score_prisoners=!1,t.allow_superko=!1,t.superko_algorithm="ssk",t.free_handicap_placement=!0,t.allow_self_capture=!0;break;default:console.log("Unsupported rule set: "+r+" error setting komi"),t.komi=0,t.score_prisoners=!1,t.allow_superko=!0,t.free_handicap_placement=!0,t.allow_self_capture=!0}!("komi"in e)&&e.handicap&&(t.komi-=Math.floor(t.komi));for(const o in t)o in e||(e[o]=t[o]);if(!("initial_state"in e)&&!("original_sgf"in e))if(19===e.width&&19===e.height||13===e.width&&13===e.height||9===e.width&&9===e.height||(e.free_handicap_placement=!0),e.handicap&&!e.free_handicap_placement){const t="";let r,o="";if(19===e.width&&(r=[[(0,c.encodeMove)(3,3),(0,c.encodeMove)(9,3),(0,c.encodeMove)(15,3)],[(0,c.encodeMove)(3,9),(0,c.encodeMove)(9,9),(0,c.encodeMove)(15,9)],[(0,c.encodeMove)(3,15),(0,c.encodeMove)(9,15),(0,c.encodeMove)(15,15)]]),13===e.width&&(r=[[(0,c.encodeMove)(3,3),(0,c.encodeMove)(6,3),(0,c.encodeMove)(9,3)],[(0,c.encodeMove)(3,6),(0,c.encodeMove)(6,6),(0,c.encodeMove)(9,6)],[(0,c.encodeMove)(3,9),(0,c.encodeMove)(6,9),(0,c.encodeMove)(9,9)]]),9===e.width&&(r=[[(0,c.encodeMove)(2,2),(0,c.encodeMove)(4,2),(0,c.encodeMove)(6,2)],[(0,c.encodeMove)(2,4),(0,c.encodeMove)(4,4),(0,c.encodeMove)(6,4)],[(0,c.encodeMove)(2,6),(0,c.encodeMove)(4,6),(0,c.encodeMove)(6,6)]]),r){switch(e.handicap){case 8:o+=r[0][1]+r[2][1];case 6:o+=r[1][0]+r[1][2];case 4:o+=r[0][0];case 3:o+=r[2][2];case 2:o+=r[0][2]+r[2][0],e.initial_player="white";break;case 9:o+=r[0][1]+r[2][1];case 7:o+=r[1][0]+r[1][2];case 5:o+=r[1][1],o+=r[0][0],o+=r[2][2],o+=r[0][2]+r[2][0],e.initial_player="white";break;default:e.free_handicap_placement=!0}"ogs_import"in e&&(2===e.handicap&&(o=r[0][0]+r[2][2]),3===e.handicap&&(o=r[0][0]+r[0][2]+r[2][2]))}else e.free_handicap_placement=!0;e.initial_state={black:o,white:t}}else e.initial_state={black:"",white:""};if("finished"===e.phase&&e.ogs&&e.score){const t=e.ogs;e.score.white.scoring_positions=("japanese"!==e.rules?t.white_stones:"")+t.white_territory,e.score.black.scoring_positions=("japanese"!==e.rules?t.black_stones:"")+t.black_territory;const r=t.black_seki_eyes+t.white_seki_eyes+t.black_dead_stones+t.white_dead_stones;e.players?.white&&(e.players.white.accepted_stones=r),e.players?.black&&(e.players.black.accepted_stones=r),e.removed=r}return e}static clearRuleSettings(e){return delete e.allow_self_capture,delete e.automatic_stone_removal,delete e.allow_ko,delete e.allow_superko,delete e.score_territory,delete e.score_territory_in_seki,delete e.strict_seki_mode,delete e.score_stones,delete e.score_prisoners,delete e.score_passes,delete e.white_must_pass_last,delete e.komi,e}parseSGF(e){const t=[],r=this;let o,i,n=0,s=1,a=!0,h=0;function c(){for(;" "===e[n]||"\t"===e[n]||"\n"===e[n]||"\r"===e[n];)"\n"===e[n]&&++s,++n}function l(){h++,h>1&&(a=!1);const o=[];if(c(),"("!==e[n])throw new Error("Expecting '(' to start a GameTree");++n;const i=function(){c();const t=[];for(;";"===e[n];){const e=d();t.push(e)}if(0===t.length)throw new Error("Expecting Sequence");return t}();for(o.push(i),c();"("===e[n];)s();function s(){let e;t.push((()=>{e=r.cur_move}));const i=l();o.push(i),t.push((()=>{r.jumpTo(e)}))}if(c(),")"!==e[n])throw new Error("Expecting ')' to end GameTree (found 0x"+e.charCodeAt(n)+")");return++n,c(),--h,o}function d(){const t=[];if(";"!==e[n])throw new Error("Expecting ';' to start a Node");for(++n,c();/[A-Za-z]/.test(e[n]);)t.push(_());return t}function _(){const h=[];let l="";for(;/[a-zA-Z]/.test(e[n]);)l+=e[n++];if(""===l)throw new Error("Expecting PropIdent");if(h.push(l),c(),"["!==e[n])throw new Error("Expecting '[' to start a PropValue");for(;"["===e[n];){++n;let t="";for(;"]"!==e[n];)"\n"===e[n]&&s++,"\\"===e[n]&&++n,t+=e[n++];if(h.push(t),"]"!==e[n])throw new Error("Expecting ']' to close a PropValue");++n,c()}return function(e,n){for(let t=1;t<n.length;++t)s(n[t]);function s(n){switch(e){case"AB":case"AW":a?(r.config.initial_state||(r.config.initial_state={black:"",white:""}),"AB"===e?r.config.initial_state.black+=n:r.config.initial_state.white+=n,r.config.free_handicap_placement=!1,r.free_handicap_placement=!1):t.push((()=>{if(""===n);else{const t=r.decodeMoves(n)[0];r.editPlace(t.x,t.y,"AB"===e?1:2)}}));break;case"W":case"B":i||(i="B"===e?"black":"white",r.config.initial_player=i),a=!1,t.push((()=>{""===n&&(n="..");const t=r.decodeMoves(n)[0];1===r.player&&"B"===e||1!==r.player&&"W"===e?r.place(t.x,t.y,!1,!1,!1,!0,!1):r.editPlace(t.x,t.y,"B"===e?1:2),r.cur_move&&(null==o||r.cur_move.move_number>o.move_number)&&(o=r.cur_move)}));break;case"C":t.push((()=>{r.cur_move.text+=n}));break;case"LB":case"TR":case"CR":case"SQ":case"XX":case"MA":t.push((()=>{try{const t=n.substr(0,2),o=n.substr(3),i=r.decodeMoves(t)[0],s=r.cur_move.getMarks(i.x,i.y);switch(e){case"LB":s.letter=o;break;case"TR":s.triangle=!0;break;case"CR":s.circle=!0;break;case"SQ":s.square=!0;break;case"XX":case"MA":s.cross=!0}}catch(t){console.error(t)}}));break;case"HA":t.push((()=>{r.handicap=parseInt(n),r.config.initial_player&&(r.player="black"===r.config.initial_player?u.JGOFNumericPlayerColor.BLACK:u.JGOFNumericPlayerColor.WHITE)}));break;case"RU":t.push((()=>{let e="japanese";switch(n.toLowerCase()){case"japanese":case"jp":e="japanese";break;case"chinese":case"cn":case"zh":e="chinese";break;case"nz":e="nz";break;case"aga":case"us":e="aga";break;case"korean":case"ko":e="korean";break;case"goe":case"ing":e="ing";break;default:console.warn(`Unknown rule set ${n}, defaulting to Japanese`)}r.rules=e}));break;case"RE":t.push((()=>{if(n.length>0&&("b"===n[0].toLowerCase()&&(r.winner="black"),"w"===n[0].toLowerCase()&&(r.winner="white")),""===r.outcome){let e;const t=n.match(/[BW]\+(.*)/);if(e=null===t?n:t[1],null!==t&&/[0-9.]+/.test(e))r.outcome=e;else switch(e||(e="V"),e[0].toUpperCase()){case"0":case"D":r.outcome="0";break;case"R":r.outcome="Resignation";break;case"T":r.outcome="Timeout";break;case"F":r.outcome="Disqualification";break;case"V":case"?":r.outcome="";break;default:r.outcome="",console.warn(`Unknown result: ${e}`)}}}));break;case"DT":r.config.game_date=n;break;case"GN":r.config.game_name=n;break;case"PW":r.config.players?.white&&(r.config.players.white.username=n);break;case"PB":r.config.players?.black&&(r.config.players.black.username=n);break;case"WR":r.config.players?.white&&(r.config.players.white.rank=f(n));break;case"BR":r.config.players?.black&&(r.config.players.black.rank=f(n));break;case"TB":t.push((()=>{r.territory_included_in_sgf=!0;const e=r.decodeMoves(n)[0];r.board[e.y][e.x]===u.JGOFNumericPlayerColor.WHITE&&r.setRemoved(e.x,e.y,!0)}));break;case"TW":t.push((()=>{r.territory_included_in_sgf=!0;const e=r.decodeMoves(n)[0];r.board[e.y][e.x]===u.JGOFNumericPlayerColor.BLACK&&r.setRemoved(e.x,e.y,!0)}))}}}(l,h),h}function f(e){const t=parseInt(e);return/[kK]/.test(e)?30-t:/[d]/.test(e)?29+t:/[p]/.test(e)?1036+t:-100}e.charCodeAt(0)>255&&(e=e.substr(1));try{!function(){const t=[];for(;n<e.length;)t.push(l()),a=!1}()}catch(p){console.log("Failed to parse SGF on line "+s+" at char '"+e[n]+"' (right after '"+e.substr(n-10,10)+"')"),console.log(p.stack)}return()=>{r.config.players=r.config.players||{white:{id:0,username:"White",rank:0},black:{id:0,username:"Black",rank:0}},t.map((e=>e())),this.move_tree.hoistFirstBranchToTrunk(),o&&r.jumpTo(o)}}estimateScore(e,t,r=!1,o=!1){return new l.ScoreEstimator(this,this.goban_callback,e,t,r,o).score()}getMoveByLocation(e,t,r){let o=null,i=this.cur_move;if(r)for(;!o&&i;)i.x===e&&i.y===t&&(o=i),i=i.next();for(i=this.cur_move.parent;!o&&i;)i.x===e&&i.y===t&&(o=i),i=i.parent;return o}exportAsPuzzle(){return{mode:"puzzle",name:this.name,puzzle_type:this.puzzle_type,width:this.width,height:this.height,initial_state:this.initial_state,puzzle_opponent_move_mode:this.puzzle_opponent_move_mode,puzzle_player_move_mode:this.puzzle_player_move_mode,puzzle_rank:this.puzzle_rank,puzzle_description:this.puzzle_description,puzzle_collection:this.puzzle_collection,initial_player:this.config.initial_player,move_tree:this.move_tree.toJson()}}getBlackPrisoners(){return this.black_prisoners}getWhitePrisoners(){return this.white_prisoners}getHandicapPointAdjustmentForWhite(){let e=0;return this.score_handicap&&(e=this.aga_handicap_scoring&&this.handicap>0?this.handicap-1:this.handicap),e}parentEventEmitter;emit(e,...t){let r=super.emit(e,...t);return this.parentEventEmitter&&(r=this.parentEventEmitter.emit(e,...t)||r),r}setRemoved(e,t,r,o=!0){this.cur_move.state.setRemoved(e,t,r,!1),super.setRemoved(e,t,r,o)}}t.GobanEngine=_},408:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.GobanMoveError=t.GobanError=void 0;class r extends Error{constructor(e){super(e),Object.setPrototypeOf(this,new.target.prototype)}}t.GobanError=r;t.GobanMoveError=class extends r{game_id;move_number;coords;message_id;constructor(e,t,r,o){super(`Move error in ${e} on move number ${t} at ${r}: ${o}`),this.game_id=e,this.move_number=t,this.coords=r,this.message_id=o}}},397:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.GobanSocket=void 0,t.closeErrorCodeToString=h;const o=r(228),i=r(460),n=[[50,50],[100,300],[250,750]],s=1e4;class a extends o.EventEmitter{url;clock_drift=0;latency=0;options;socket;last_request_id=0;promises_in_flight=new Map;reconnecting=!1;reconnect_tries=0;send_queue=[];ping_timer;timeout_timer;callbacks=new Map;authentication;manually_disconnected=!1;current_ping_interval;constructor(e,t={}){super(),this.options=t,e=e.replace(/^http/,"ws"),this.url=e,this.current_ping_interval=t.ping_interval||s,this.socket=this.connect(),this.on("net/pong",(({client:e,server:t})=>{const r=Date.now(),o=r-e,i=r-o/2-t;this.latency=o,this.clock_drift=i,this.emit("latency",o,i),this.timeout_timer&&clearTimeout(this.timeout_timer)}))}get connected(){return this.socket.readyState===WebSocket.OPEN}authenticate(e){this.authentication=e,this.send("authenticate",e)}sendAuthentication(){this.authentication&&this.send("authenticate",this.authentication)}signalTimeout=()=>{this.emit("timeout")};ping=()=>{this.options.dont_ping||(this.connected?(this.send("net/ping",{client:Date.now(),drift:this.clock_drift,latency:this.latency}),this.options.timeout_delay&&(this.timeout_timer=setTimeout(this.signalTimeout,this.options.timeout_delay)),this.options.ping_interval&&this.options.ping_interval!==this.current_ping_interval&&(this.ping_timer&&clearInterval(this.ping_timer),this.ping_timer=(0,i.niceInterval)(this.ping,this.options.ping_interval||s),this.current_ping_interval=this.options.ping_interval)):this.ping_timer&&(clearInterval(this.ping_timer),this.ping_timer=void 0))};startPing(){this.ping_timer&&clearInterval(this.ping_timer),this.timeout_timer&&clearTimeout(this.timeout_timer),this.ping_timer=(0,i.niceInterval)(this.ping,this.options.ping_interval||s),this.ping()}connect(){const e=new WebSocket(this.url);return e.addEventListener("open",(e=>{this.options.quiet||console.log("GobanSocket connected to "+this.url),this.reconnecting=!1,this.reconnect_tries=0,this.connected||console.error("GobanSocket connected but readyState !== OPEN");try{this.emit("connect")}catch(t){console.error("GobanSocket connect event handler error",t)}if(this.promises_in_flight.size>0)throw new Error("GobanSocket connected with promises in flight");this.sendAuthentication(),this.startPing();for(const r of this.send_queue)r();this.send_queue=[]})),e.addEventListener("error",(e=>{this.manually_disconnected||console.error(`GobanSocket error ${e?.message||e}`)})),e.addEventListener("close",(e=>{const t=e?.code;1e3===t||this.manually_disconnected||console.warn(`GobanSocket closed with code ${t}: ${h(t)}`),this.rejectPromisesInFlight();try{this.emit("disconnect",t)}catch(r){console.error("Error in disconnect handler",r)}if(!this.manually_disconnected){if(1014===t||1015===t)return console.error("OGS Socket closed with an unrecoverable error, not reconnecting"),void this.emit("unrecoverable_error",t,1014===t?"bad_gateway":1015===t?"tls_handshake":"unknown",h(t));this.reconnecting=!1,this.reconnect()}})),e.addEventListener("message",(e=>{let t;try{t=JSON.parse(e.data)}catch(n){throw console.error("Error parsing message",{event:e,data:e?.data,exception:n}),new Error("Error parsing message: "+e?.data)}const[r,o,i]=t;if("number"==typeof r){const e=this.callbacks.get(r);e&&(this.callbacks.delete(r),e(o,i))}else this.emit(r,o)})),e}reconnect(){if(this.manually_disconnected)return;if(this.reconnecting)return;this.reconnecting=!0;const e=n[Math.min(this.reconnect_tries,n.length-1)];++this.reconnect_tries;const t=Math.floor(Math.random()*(e[1]-e[0])+e[0]);this.options.quiet||console.info(`GobanSocket reconnecting in ${t}ms`),setTimeout((()=>{this.socket=this.connect()}),t)}rejectPromisesInFlight(){for(const[,{reject:t}]of this.promises_in_flight)try{t(`Socket closed with code ${this.socket.readyState}`)}catch(e){console.error("Error in reject handler",e)}this.promises_in_flight.clear()}send(e,t,r){const o=r?[e,t,++this.last_request_id]:t?[e,t]:[e];r&&this.callbacks.set(this.last_request_id,r);const i=JSON.stringify(o);if(this.connected)try{this.socket.send(i)}catch(n){this.send_queue.push((()=>{this.socket.send(i)}))}else this.send_queue.push((()=>{this.socket.send(i)}))}sendPromise(e,t){return new Promise(((r,o)=>{this.send(e,t,((e,t)=>{t?o(t):r(e)}))}))}disconnect(){this.manually_disconnected=!0,this.socket.close(),this.rejectPromisesInFlight();for(const e of this.callbacks)e[1](void 0,{code:"manually_disconnected",message:"Manually disconnected"})}}function h(e){if(e>=0&&e<=999)return"Not used";switch(e){case 1e3:return"Normal Closure";case 1001:return"Going Away";case 1002:return"Protocol error";case 1003:return"Unsupported Data";case 1004:return"Reserved";case 1005:return"No Status Received";case 1006:return"Abnormal Closure";case 1007:return"Invalid frame payload data";case 1008:return"Policy Violation";case 1009:return"Message Too Big";case 1010:return"Mandatory Ext.";case 1011:return"Internal Error";case 1012:return"Service Restart";case 1013:return"Try Again Later";case 1014:return"Bad Gateway";case 1015:return"TLS handshake"}return e>=1016&&e<=2999?"Unknown official error code: "+e:e>=3e3&&e<=3999?"Unknown library status code: "+e:e>=4e3&&e<=4999?"Unknown private error code: "+e:"Unknown error code: "+e}t.GobanSocket=a},862:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.MoveTree=void 0;const o=r(460),i=r(896),n=r(460);let s=0,a={};class h{static stone_radius=11;static stone_padding=3;static stone_square_size=2*(h.stone_radius+h.stone_padding);label="[unset]";move_number;pretty_coordinates;parent;id;trunk_next;branches;correct_answer=!1;wrong_answer=!1;hint_next;player;line_color;trunk;text;engine;x;y;edited;state;pen_marks=[];player_update;played_by;active_path_number=0;layout_cx=0;layout_cy=0;layout_x=0;layout_y=0;label_metrics;chat_log;marks;stashed_marks=[];isobranches;isobranch_hash;constructor(e,t,r,o,i,n,a,h,c){this.id=++s,this.x=r,this.y=o,this.pretty_coordinates=e.prettyCoordinates(r,o),this.layout_x=0,this.layout_y=0,this.engine=e,this.trunk=t,this.edited=i,this.player=n,this.parent=h,this.move_number=a,this.state=c,this.trunk_next=void 0,this.branches=[],this.active_path_number=0,this.line_color=-1,this.text=""}toJson(){const e={x:this.x,y:this.y};if(this.pen_marks&&this.pen_marks.length&&(e.pen_marks=this.pen_marks),this.hasMarks()&&(e.marks=[],this.foreachMarkedPosition(((t,r)=>{e.marks?.push({x:t,y:r,marks:this.getMarks(t,r)})}))),this.text&&(e.text=this.text),this.trunk_next&&(e.trunk_next=this.trunk_next.toJson()),this.branches.length){e.branches=[];for(let t=0;t<this.branches.length;++t)e.branches.push(this.branches[t].toJson())}return this.correct_answer&&(e.correct_answer=this.correct_answer),this.wrong_answer&&(e.wrong_answer=this.wrong_answer),e}loadJsonForThisNode(e){if(e.x!==this.x||e.y!==this.y)throw new Error("Node mismatch when unpacking json object in MoveTree.fromJson");if(this.correct_answer=!!e.correct_answer,this.wrong_answer=!!e.wrong_answer,this.text=e?.text?e.text:"",e.marks)for(let t=0;t<e.marks.length;++t){const r=e.marks[t];for(const e in r.marks)this.getMarks(r.x,r.y)[e]=r.marks[e]}e.pen_marks&&(this.pen_marks=e.pen_marks)}recomputeIsobranches(){if(this.parent)throw new Error("MoveTree.recomputeIsobranches needs to be called from the root node");a={};const e=t=>{const r=t.state.isobranch_hash?t.state.isobranch_hash:t.state.isobranch_hash=t.state.board.map((e=>e.join(""))).join("")+t.player;t.isobranch_hash=r,r in a||(a[r]=[]),a[r].push(t),t.trunk_next&&e(t.trunk_next);for(let o=0;o<t.branches.length;++o)e(t.branches[o])},t=e=>{if(e.isobranches=[],-1!==e.x)for(const t of a[e.isobranch_hash])if(e.id!==t.id){if(e.isAncestorOf(t)||t.isAncestorOf(e))continue;e.isobranches.push(t)}e.trunk_next&&t(e.trunk_next);for(let r=0;r<e.branches.length;++r)t(e.branches[r])};e(this),t(this)}lookupMove(e,t,r,o){if("number"!=typeof r)throw new Error(`Invalid player color: ${r}`);if(this.trunk_next&&this.trunk_next.x===e&&this.trunk_next.y===t&&this.trunk_next.edited===o&&(!o||this.trunk_next.player))return this.trunk_next;for(let i=0;i<this.branches.length;++i)if(this.branches[i].x===e&&this.branches[i].y===t&&(!o||this.branches[i].player===r)&&this.branches[i].edited===o)return this.branches[i];return null}move(e,t,r,o,i,n,s){if(void 0===i)throw new Error("Invalid player");if("number"!=typeof i)throw new Error(`Invalid player color: ${i}`);let a=this.lookupMove(e,t,i,o);if(a&&(a.trunk||!r))return a.state=s,a.move_number=n,a;if(a=new h(this.engine,r,e,t,o,i,n,this,s),this.engine.move_tree_layout_dirty=!0,r){if(!this.trunk)throw console.log("Attempted trunk move made on ",this),new Error("Attempted trunk move made on non-trunk");this.trunk_next?(a=this.trunk_next,a.edited=o,a.move_number=n,a.state=s,a.x=e,a.y=t,a.player=i):this.trunk_next=a;for(let r=0;r<this.branches.length;++r)if(this.branches[r].x===e&&this.branches[r].y===t&&this.branches[r].player===i){const e=this.branches[r].branches;for(let t=0;t<e.length;++t)e[t].parent=this.trunk_next,this.trunk_next.branches.push(e[t]);this.branches.splice(r,1);break}}else{let r=!1;for(let h=0;h<this.branches.length;++h)this.branches[h].x===e&&this.branches[h].y===t&&this.branches[h].player===i&&(r=!0,a=this.branches[h],a.edited=o,a.move_number=n,a.state=s);r||this.branches.push(a)}return a}traverse(e){e(this),this.trunk_next&&this.trunk_next.traverse(e);for(let t=0;t<this.branches.length;++t)this.branches[t].traverse(e)}fold(e,t){let r=t(e,this);this.trunk_next&&(r=this.trunk_next.fold(r,t));for(let o=0;o<this.branches.length;++o)r=this.branches[o].fold(r,t);return r}size(){return this.fold(0,((e,t)=>e+1))}next(e){if(this.trunk_next)return this.trunk_next;if(this.hint_next&&!e)for(let t=0;t<this.branches.length;++t)if(this.branches[t].id===this.hint_next.id)return this.hint_next;return this.branches.length?this.branches[0]:null}prev(){return this.parent&&(this.parent.hint_next=this),this.parent}index(e){let t=this;for(;t.prev()&&e<0;)t=t.prev(),++e;for(;t.next(!0)&&e>0;)t=t.next(!0),--e;return t}is(e){return!(!e||this.id!==e.id)}hasTheSameRootMoveAs(e){return this.x===e.x&&this.