【问题标题】:Javascript : optimize data structure for chess gameJavascript:优化国际象棋游戏的数据结构
【发布时间】:2017-08-13 08:15:51
【问题描述】:

试图弄清楚如何存储一些对棋类游戏编程有用的数据。

我决定将棋子发出的光线存储在 Raycaster 中;这个问题是关于这个结构的实现的。

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

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

  • Ray.NORMAL 或 Ray.FULL:它们由所有棋子发出,但不是棋子,以迭代方式(车、象、后)或不(骑士和国王)发出
  • Ray.CAPTURE:仅由 pawn、左前和/或右前捕获发射
  • 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 }

表示该射线实例可能被另一个棋子遮蔽的位置,以及另一条射线穿过它的位置,以检测可通过性和干扰(用于castling)

问题:

如何在 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)有何感受?

【问题讨论】:

  • 按方向和列/行/对角线存储光线。

标签: javascript dictionary chess


【解决方案1】:

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

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
}

剩下的工作只是在光线类中确定两条光线如何相互作用(交叉或着色)

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-04
    • 1970-01-01
    • 1970-01-01
    • 2015-05-02
    • 2023-04-07
    • 2015-07-16
    相关资源
    最近更新 更多