shogi-player
Version:
Shogi board web components has functions for replaying, manipulating, and editing
176 lines (138 loc) • 4 kB
JavaScript
import _ from "lodash"
import { Board } from "./board"
import { PlaceYomiageInfo } from "./place_yomiage_info.js"
export class Place {
static ANY_TO_NUMBER_REPLACE_TABLE = {
"1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9,
"一": 1, "二": 2, "三": 3, "四": 4, "五": 5, "六": 6, "七": 7, "八": 8, "九": 9,
"a": 1, "b": 2, "c": 3, "d": 4, "e": 5, "f": 6, "g": 7, "h": 8, "i": 9,
}
static TO_KANJI_REPLACE_TABLE_X = {1: "1", 2: "2", 3: "3", 4: "4", 5: "5", 6: "6", 7: "7", 8: "8", 9: "9"}
static TO_KANJI_REPLACE_TABLE_Y = {1: "一", 2: "二", 3: "三", 4: "四", 5: "五", 6: "六", 7: "七", 8: "八", 9: "九"}
static TO_SFEN_REPLACE_TABLE_Y = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
static fetch(v) {
if (v instanceof this) {
return v
}
return Object.freeze(new Place(v))
}
static xy_valid_p(x, y) {
return 0 <= x && x < Board.dimension && 0 <= y && y < Board.dimension
}
static xy_invalid_p(x, y) {
return !this.xy_valid_p(x, y)
}
constructor(value) {
let x, y
if (typeof value === "string") {
[x, y] = this.__parse_from_string(value)
} else {
[x, y] = value // valus is array
}
[this._x, this._y] = [x, y]
}
get key() {
return [this._x, this._y].toString()
}
get x() {
return this._x
}
get y() {
return this._y
}
get to_a() {
return [this.x, this.y]
}
get to_h() {
return { x: this.x, y: this.y }
}
get human_x() {
return Board.dimension - this._x
}
get kanji_human_x() {
return Place.TO_KANJI_REPLACE_TABLE_X[this.human_x]
}
get kanji_human_y() {
return Place.TO_KANJI_REPLACE_TABLE_Y[this.human_y]
}
get yomiage_x() {
return PlaceYomiageInfo.fetch(this.human_x.toString()).yomiage
}
get yomiage_y() {
return PlaceYomiageInfo.fetch(this.human_y.toString()).yomiage
}
get human_y() {
return this._y + 1
}
get flip_all() {
return Place.fetch([Board.dimension - 1 - this._x, Board.dimension - 1 - this._y])
}
get flop() {
return Place.fetch([Board.dimension - 1 - this._x, this._y])
}
flop_if(v) {
if (v) {
return this.flop
} else {
return this
}
}
sp_flip_if_white(location) {
if (location.key === "white") {
return this.flip_all
} else {
return this
}
}
get to_sfen() {
return [Board.dimension - this._x, Place.TO_SFEN_REPLACE_TABLE_Y[this._y]].join("")
}
// "place_7_6"
get css_place_key() {
return ["place", this.human_x, this.human_y].join("_")
}
// [7, 6]
get human_xy_ary() {
return [this.human_x, this.human_y]
}
get kanji_human() {
return [this.kanji_human_x, this.kanji_human_y].join("")
}
// "76"
get digit_human() {
return this.human_xy_ary.join("")
}
// 盤と駒台を含めたユニークな位置情報の文字列を返す
// "7_6"
get to_mark_pos_key() {
return this.human_xy_ary.join("_")
}
get even_p() {
return ((this.human_x + this.human_y) & 1) === 0
}
get odd_p() {
return !this.even_p
}
get tennozan_p() {
return this.x === Math.trunc(Board.dimension / 2) && this.y === Math.trunc(Board.dimension / 2)
}
// x, y を足した新しい位置を返す
// はみでたのは反対側の座標とする
rotate_add(x, y) {
const nx = this.__new_pos(this._x, x)
const ny = this.__new_pos(this._y, y)
return Place.fetch([nx, ny])
}
// private
__new_pos(origin, v) {
return Math.trunc((origin + v + Board.dimension) % Board.dimension) // (x + 1).modulo(dimension)
}
__parse_from_string(s) {
const [x, y] = s.split("").map(e => Number(Place.ANY_TO_NUMBER_REPLACE_TABLE[e] ?? e))
return [Board.dimension - x, y - 1]
}
}
if (typeof process !== "undefined" && process.argv[1] === __filename) {
console.log(Place.fetch("6a").key)
console.log(Place.fetch([1, 2]).key)
}