【问题标题】:How should I represent a chess bitboard in clojure?我应该如何在 clojure 中表示国际象棋位板?
【发布时间】:2013-02-15 18:48:43
【问题描述】:

在 Clojure (/Java) 中表示棋盘的可能方式有哪些?

http://pages.cs.wisc.edu/~psilord/blog/data/chess-pages/rep.html

我需要能够访问各个位并执行按位运算。

我曾想过使用 java.lang.Long 但这会导致 1x10^63 出现问题,因为标牌。我也不确定如何访问特定索引处的位?

我也看过 BitSet,但理想情况下我需要一个固定长度。

【问题讨论】:

  • '最好的方法' - 在codereview.stackexchange.com 上显示您的代码; “我应该怎么做”——没有建设性。你有什么代码?你有什么要求?你被困在哪里了?
  • @sehe 我试过使用 java.lang.Long 但遇到了 parseLong() 和 "10000...x63" - 1x10^63) 的问题另外,我不确定我是否可以访问特定索引处的位吗?我要求的是合理化的建议和想法,不一定是绝对的。
  • 您应该将这些详细信息编辑到您的问题中。
  • 这有助于理解位掩码:en.wikipedia.org/wiki/Mask_%28computing%29
  • 10^63?这不适合很长时间......

标签: java clojure chess


【解决方案1】:

没有理由不能使用直长。正如您所指出的,问题在于 java(以及因此 clojure)的 long 是有符号的,仅允许 63 位用于正数

默认情况下,Java 允许算术溢出而不会出错。 Clojure 默认情况下不允许算术溢出而没有错误(请参阅*unchecked-math* 标志)。它增加了对算术运算和强制转换的额外检查,因此,例如,(byte 128) 将导致异常。由于 clojure v1.3.0 有类似 (unchecked-byte) 的函数,它相当于 java 的功能......

(unchecked-byte 128)
;=> -128 ; 2s-complement of 10000000
(unchecked-byte 2r10000001)
;=> -127 ; 2s-complement of 10000001

有大量的unchecked-* 操作可用 (see clojuredocs)。

如果您使用直长和unchecked-* 操作,您大部分都在那里,然后您可以使用bit-* 操作来旋转/检查位。

最后将你的棋盘存储在一个原子中是有意义的,然后你用(swap! chessboard fn args)更新它

(2013 年 2 月 15 日更新,使用更惯用的 swap!调用)

例如

(inc Long/MAX_VALUE) ; java.lang.ArithmeticException

(unchecked-inc Long/MAX_VALUE) ; wraps.
-9223372036854775808

(def chessboard (atom 0))
@chessboard
;=> 0
(bit-test @chessboard 1)
;=> false
(swap! chessboard bit-flip 1)
;=> 2
(bit-test @chessboard 1)
;=> true
@chessboard
;=> 2
(reset! chessboard 0)
;=> 0
(swap! chessboard bit-flip 63)
;=> -9223372036854775808 
(bit-test @chessboard 63)
;=> true 

【讨论】:

  • 嗯,这应该是核心,但由于某种原因我得到:user=> (unchecked-byte 2r100101) java.lang.Exception: Unable to resolve symbol: unchecked-byte in this context (NO_SOURCE_FILE:4)
  • 我更新了答案,注意 unchecked-* 出现在 clojure 1.3.0
  • +1 以获得很好的答案。我唯一要补充的是,您可能想要使用 Java 原始长数组(因为通常您想要同时操作许多位板)。如果位板运算将占您 CPU 使用率的 90%,则值得使用原始数组以获得额外的速度和空间效率。
【解决方案2】:
=> (def chessboard (byte-array 8))
#'user/chessboard

=> (vec chessboard)
[0 0 0 0 0 0 0 0]

=> (for [row (range 8)] (aset-byte chessboard row (rand-int 8)))
(3 0 6 6 2 3 6 7)

=> (bigint chessboard)
216179404987106823N

=> (defn bigint-to-array
 [bi]
 (.toByteArray (biginteger bi)))

=> (vec (bigint-to-array 216179404987106823N))
[3 0 6 6 2 3 6 7]

Clojure 以这种方式支持您需要的大多数功能。像所有 clojure 数字一样,clojure.lang.BigInt 支持二进制操作(位等)。在字节数组上,您可以使用 java.util.Arrays 中的所有方法(搜索、填充、排序)。

注意 bigint fn 强制转换为 clojure.lang.BigInt,而 biginteger fn 强制转换为 java.math.BigInteger。如果你想使用java.math.BigInteger的方法,你需要通过biginteger来强制你的bigint或者byte-array。

【讨论】:

  • 谢谢,不知道在性能方面与使用 long 相比如何?我想它会更慢。
  • Clojure bigint 不支持位操作。 user=> (bit-and (bigint 5) (bigint 3)) IllegalArgumentException 位操作不支持:class clojure.lang.BigInt clojure.lang.Numbers.bitOpsCast (Numbers.java:1008)
猜你喜欢
  • 2021-04-24
  • 1970-01-01
  • 1970-01-01
  • 2022-06-17
  • 1970-01-01
  • 2014-03-02
  • 2021-08-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多