-
-
Notifications
You must be signed in to change notification settings - Fork 227
Expand file tree
/
Copy pathBitboard.scala
More file actions
256 lines (206 loc) · 7.13 KB
/
Copy pathBitboard.scala
File metadata and controls
256 lines (206 loc) · 7.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
package chess
import scala.annotation.targetName
import bitboard.Attacks.*
opaque type Bitboard = Long
object Bitboard:
inline def apply(inline l: Long): Bitboard = l
inline def apply(inline xs: Iterable[Square]): Bitboard = xs.foldLeft(empty)((b, s) => b | s.bl)
inline def apply(inline xs: Square*): Bitboard = apply(xs.toList)
def fromKeys(keys: String*): Bitboard = Bitboard(keys.flatMap(Square.fromKey))
val empty: Bitboard = 0L
val all: Bitboard = -1L
// E4, D4, E5, D5
val center = 0x1818000000L
val firstRank: Bitboard = 0xffL
val lastRank: Bitboard = 0xffL << 56
// all light squares
val lightSquares: Bitboard = 0x55aa55aa55aa55aaL
// all dark squares
val darkSquares: Bitboard = 0xaa55aa55aa55aa55L
inline def file(inline f: File): Bitboard = FILES(f.value)
inline def rank(inline r: Rank): Bitboard = RANKS(r.value)
inline def ray(inline from: Square, inline to: Square): Bitboard = RAYS(from.value)(to.value)
def aligned(a: Square, b: Square, c: Square): Boolean = ray(a, b).contains(c)
def between(a: Square, b: Square): Bitboard = BETWEEN(a.value)(b.value)
extension (l: Long)
private def lsb: Square = Square.unsafe(java.lang.Long.numberOfTrailingZeros(l))
private def msb: Square = Square.unsafe(63 - java.lang.Long.numberOfLeadingZeros(l))
extension (a: Bitboard)
inline def value: Long = a
inline def unary_~ : Bitboard = (~a)
inline infix def &(inline o: Long): Bitboard = (a & o)
inline infix def ^(inline o: Long): Bitboard = (a ^ o)
inline infix def |(inline o: Long): Bitboard = (a | o)
inline infix def <<(inline o: Int): Bitboard = (a << o)
inline infix def >>>(inline o: Int): Bitboard = (a >>> o)
@targetName("and")
inline infix def &(o: Bitboard): Bitboard = (a & o)
@targetName("xor")
inline infix def ^(o: Bitboard): Bitboard = (a ^ o)
@targetName("or")
inline infix def |(o: Bitboard): Bitboard = (a | o)
inline def isEmpty: Boolean = a == 0L
inline def nonEmpty: Boolean = !isEmpty
inline def supersetOf(l: Long): Boolean =
(a & l) == l
@targetName("superSetOfB")
inline def supersetOf(o: Bitboard): Boolean =
(a & o) == o
inline def subsetOf(l: Long): Boolean =
(a & l) == a
@targetName("subSetOfB")
inline def subsetOf(o: Bitboard): Boolean =
(a & o) == a
inline def contains(square: Square): Boolean =
(a & (1L << square.value)) != 0L
inline def contains(file: File, rank: Rank): Boolean =
(a & file.bb & rank.bb) != 0L
def add(square: Square): Bitboard = a | square.bl
def remove(square: Square): Bitboard = a & ~square.bl
def move(from: Square, to: Square): Bitboard =
a & ~from.bl | to.bl
def moreThanOne: Boolean =
(a & (a - 1L)) != 0L
// Gets the only square in the set, if there is exactly one.
def singleSquare: Option[Square] =
if moreThanOne then None
else first
// total non empty squares
def count: Int = java.lang.Long.bitCount(a)
// the first non empty square (the least significant bit/ the rightmost bit)
def first: Option[Square] = Square(java.lang.Long.numberOfTrailingZeros(a))
// the last non empty square (the most significant bit / the leftmost bit)
def last: Option[Square] = Square(63 - java.lang.Long.numberOfLeadingZeros(a))
// remove the first/smallest non empty square
def removeFirst: Bitboard = a & (a - 1L)
// remove the last/largest non empty square
def removeLast: Bitboard = a & ~a.msb.bl
def isolateFirst: Bitboard = a & -a
def isolateLast: Bitboard = last.fold(empty)(_.bl)
inline def intersects(inline o: Long): Boolean =
(a & o) != 0L
@targetName("intersectsB")
inline def intersects(o: Bitboard): Boolean =
(a & o).nonEmpty
inline def isDisjoint(inline o: Long): Boolean =
(a & o).isEmpty
@targetName("isDisjointB")
inline def isDisjoint(o: Bitboard): Boolean =
(a & o).isEmpty
// return list of square that sorted ascendingly
def squares: List[Square] =
var b = a
val builder = List.newBuilder[Square]
while b != 0L
do
builder += b.lsb
b &= (b - 1L)
builder.result
def toSet: Set[Square] =
squares.toSet
def first[B](f: Square => Option[B]): Option[B] =
var b = a
var result: Option[B] = None
while b != 0L && result.isEmpty
do
result = f(b.lsb)
b &= (b - 1L)
result
def last[B](f: Square => Option[B]): Option[B] =
var b = a
var result: Option[B] = None
while b != 0L && result.isEmpty
do
result = f(b.msb)
b &= ~b.msb.bl
result
// the smallest square that satisfies the predicate
def find(f: Square => Boolean): Option[Square] =
var b = a
var result: Option[Square] = None
while b != 0L && result.isEmpty
do
if f(b.lsb) then result = Some(b.lsb)
b &= (b - 1L)
result
// the larget square that satisfies the predicate
def findLast(f: Square => Boolean): Option[Square] =
var b = a
var result: Option[Square] = None
while b != 0L && result.isEmpty
do
if f(b.msb) then result = Some(b.msb)
b &= ~b.msb.bl
result
def fold[B](init: B)(f: (B, Square) => B): B =
var b = a
var result = init
while b != 0L
do
result = f(result, b.lsb)
b &= (b - 1L)
result
def filter(f: Square => Boolean): List[Square] =
val builder = List.newBuilder[Square]
var b = a
while b != 0L
do
if f(b.lsb) then builder += b.lsb
b &= (b - 1L)
builder.result
def withFilter(f: Square => Boolean): List[Square] =
filter(f)
def foreach[U](f: Square => U): Unit =
var b = a
while b != 0L
do
f(b.lsb)
b &= (b - 1L)
def forall(f: Square => Boolean): Boolean =
var b = a
var result = true
while b != 0L && result
do
result = f(b.lsb)
b &= (b - 1L)
result
def exists(f: Square => Boolean): Boolean =
var b = a
var result = false
while b != 0L && !result
do
result = f(b.lsb)
b &= (b - 1L)
result
def flatMap[B](f: Square => IterableOnce[B]): List[B] =
var b = a
val builder = List.newBuilder[B]
while b != 0L
do
builder ++= f(b.lsb)
b &= (b - 1L)
builder.result
def map[B](f: Square => B): List[B] =
var b = a
val builder = List.newBuilder[B]
while b != 0L
do
builder += f(b.lsb)
b &= (b - 1L)
builder.result
def iterator: Iterator[Square] = new:
private var b = a
override inline def hasNext: Boolean = b != 0L
override inline def next: Square =
val result = b.lsb
b &= (b - 1L)
result
def debug: String =
val builder = StringBuilder()
Rank.allReversed.foreach: r =>
File.all.foreach: f =>
val s = Square(f, r)
builder ++= (if contains(s) then "1" else ".")
if f != File.H then builder ++= " "
else if s != Square.H1 then builder ++= "\n"
builder.result