Javascript:优化国际象棋游戏的数据结构

时间:2017-08-13 08:15:52

标签: javascript dictionary chess

试图弄清楚如何为国际象棋游戏编程存储一些有用的数据。

我决定在Raycaster中存放由车载西洋棋棋子发出的光线;这个问题是关于这种结构的实施。

TL; DR(仅限国际象棋游戏玩家......)

首先,我确定了三种射线:

  • Ray.NORMAL或Ray.FULL:它们是由所有西洋棋棋子发出但不是棋子,以反复的方式(车,主教,女王)或不(骑士和国王)
  • Ray.CAPTURE:仅由棋子发出,左前方和/或前方右侧捕获
  • Ray.OFFSET:向前移动时由棋子发射,为国王/国王开球

因此,光线的定义如下:

class Ray {

  constructor (owner, kind) {
    this.owner = owner // chessman which emits ray
    this.kind = kind
    this.ref = null
    this.sequence = []
  }

  // is computed afetr construction
  expand (ref, sequence) {
    this.ref = ref // starting ref (origin of the ray)
    this.sequence = sequence // array of refs
  }

  // is called when ray is inserted into raycaster
  interact (otherRay) {
    //  to be implemented
  }
}

光线还有两个特殊的复合属性:

  • 遮蔽{ray:null,idx:-1}
  • 穿越{ray:null,idx:-1}

表示此射线实例可能被另一个棋子遮挡的地方,以及另一条射线穿过它的位置,以检测可通行性和干扰(用于铸造)

问题:

如何在RayCaster中高效存储光线?

以优化操作的方式,例如:

    1. 添加新计算的光线,计算与先前存储的光线的相互作用,以最低成本计算?
    1. 从给定的起始参考确定所有目标牌/参考?
    1. 轻松确定哪些光线瞄准给定的光线,以计算此瓷砖上的压力平衡?

建议的解决方案/替代方案

  • 单个光线阵列:最差情况下64 * 63个元素,寻找光线和计算交互成本很高
  • 数组映射:Map.set(startingRef,[list_of_emtted_rays_from_startingRef])
  • 数组映射:Map.set(endingRef,[list_of_targetinhg_rays_to_endingRef])

也许是个好人:

维护2个数组映射,一个用于发射,一个用于定位

class RayCaster {
  constructor() {
    this.startings = new Map()
    this.endings = new Map()
  }

  cast(board) { ...iterate through board and casts individual rays }

  add(ray) { ... }

  getRefsAttackedBy(ref) { ... }

  getRefsAttacking(ref) { ... }
}

那么您对此数据结构(RayCaster)的看法是什么?

1 个答案:

答案 0 :(得分:0)

最后,由于地图是时间常数访问,我考虑了双地图实现:

constructor() {
  this.startings = new Map()
  this.endings = new Map()
  this.counters = { rays: 0, interactions: 0 }
}

每张地图都由电路板参考,来自" a1"到" h8"

casts(board) {
  this.counters = {
    rays: this.raysFrom(board),
    interactions: this.computeInteractions()
  }
}

添加射线是直截了当的:

raysFrom(board) {
  let counter = 0;

  board.traverse((ref, chessman) => {
    let rays = chessman.cast(ref)

    for(let ray of rays) {
      this.add(ray)
    }

    counter  += rays.length
  })

  return counter
}

一个简单的光线:

add (ray) {
  let skey = ray.ref
  let sRays = this.startings.get(sKey)

  if(sRays.indexOf(ray) === -1) {
    sRays.push(ray)
  }

  ray.traverse((seqIdx, seqRef) => {
    let seqKey = seqRef.key
    let eRays = this.endings.get(seqKey)

    if (eRays.indexOf(ray) === -1) {
      eRays.push(ray)
    }
  })
}

计算光线相互作用(交叉和阴影)更复杂:

computeInteractions() {
  let counter = 0

  // consider all starting rays
  for (let {sRef, sRays} of this.startings) {
    for (let sRay of sRays) {
      sRay.traverse((seqIdx, seqRef) => {

        // consider all possible intersections
        // into the endings map
        let eRays = this.endings.get(seqRef.ref)

        for(let eRay of eRays) {
          // ensure that rays are different
          if (sRay !== eRay) {
            sRay.interact(eRay)
            eRay.interact(sRay)
          }
        }
      })
    }
  }

  return counter
}

其余工作只是在光线类中确定两条光线如何相互作用(交叉或阴影)

感谢您的建议,最好的问候!