Skip to content

Commit 130f5bd

Browse files
Pos remains in hexagon
1 parent c69a7d3 commit 130f5bd

File tree

6 files changed

+139
-28
lines changed

6 files changed

+139
-28
lines changed

src/main/scala/abalone/Board.scala

+9-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@ case class Board(
1111
) {
1212

1313
def apply(at: Pos): Option[Piece] = pieces get at
14-
def apply(file: File, rank: Rank) = pieces get Pos(file, rank)
14+
def apply(file: File, rank: Rank): Option[Piece] = {
15+
val pos = Pos(file, rank)
16+
pos match {
17+
case Some(pos) => pieces get pos
18+
case None => None
19+
}
20+
}
1521

1622
lazy val actors: Map[Pos, Actor] = pieces map { case (pos, piece) =>
1723
(pos, Actor(piece, pos, this))
@@ -50,12 +56,12 @@ object Board {
5056
val width: Int,
5157
val height: Int
5258
) {
59+
val regular = false
5360

5461
val key = s"${width}x${height}"
5562
val sizes = List(width, height)
5663

57-
val validPos: List[Pos] =
58-
Pos.all.filter(p => p.file.index < width && p.rank.index < height)
64+
val validPos: List[Pos] = Pos.all
5965

6066
override def toString = key
6167

src/main/scala/abalone/File.scala

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
package strategygames.abalone
2+
23
case class File private (val index: Int) extends AnyVal with Ordered[File] {
34
@inline def -(that: File): Int = index - that.index
45
@inline override def compare(that: File) = this - that

src/main/scala/abalone/Pos.scala

+39-20
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,9 @@ Abalone official coordinates system and "standard start position" are drawn belo
7474
7575
*/
7676

77-
// Piotr is what is saved in Database and is used to in Uci
78-
// In the lookup val, we target as "FileAsLetterRowAsNumber" squares already defined in Pos object
79-
// The .index refer to the value that was given when the Pos was created, and is then associated to the char (which should match match src/main/scala/fairysf/Pos.scala for use in analysis and stratops)
77+
// Piotr is what is saved in Database and is used in Uci
78+
// In the lookup val, we target a "FileAsLetterRowAsNumber" square already defined in Pos object
79+
// The .index refer to the value that was given when the Pos was created, and is then associated to the char (which should match src/main/scala/fairysf/Pos.scala for use in analysis and stratops)
8080
object Piotr {
8181
val lookup: Map[Int, Char] = Map(
8282
Pos.A1.index -> 'a',
@@ -183,7 +183,7 @@ case class Pos private (index: Int) extends AnyVal {
183183
\ /
184184
- o -
185185
/ \
186-
*/
186+
*/
187187
def left: Option[Pos] = Pos.at(file.index - 1, rank.index)
188188
def downLeft: Option[Pos] = Pos.at(file.index - 1, rank.index - 1)
189189
def upLeft: Option[Pos] = Pos.at(file.index, rank.index + 1)
@@ -231,7 +231,7 @@ case class Pos private (index: Int) extends AnyVal {
231231
def piotr: Char = Piotr.lookup
232232
.get(index)
233233
.getOrElse(
234-
'?' // @TODO VFR: check if we really want this default value, or even a default value at all ??? Currently it returns the character in H8.
234+
'*' // will default to char in i9
235235
)
236236
def piotrStr = piotr.toString
237237

@@ -241,24 +241,44 @@ case class Pos private (index: Int) extends AnyVal {
241241
}
242242

243243
object Pos {
244+
/*
245+
row col
246+
9 - 72 73 74 75 & \' ( ) * 8: >3 (<9)
247+
8 - 63 64 65 7 8 9 ! ? ¥ 7: >2 (<9)
248+
7 - 54 55 Y Z 0 1 2 3 £ 6: >1 (<9)
249+
6 - 45 P Q R S T U V ¡ 5: >0 (<9)
250+
5 - G H I J K L M N } 4: <9
251+
4 - y z A B C D E F 35 3: <8
252+
3 - q r s t u v w 25 26 2: <7
253+
2 - i j k l m n 15 16 17 1: <6
254+
1 - a b c d e 5 6 7 8 0: <5
255+
| | | | | | | | |
256+
A B C D E F G H I
257+
*/
258+
def isInHexagon(index: Int): Boolean = {
259+
if (index < 0) return false
260+
val row = index / File.all.size
261+
val remainder = index % File.all.size
262+
if (index >= File.all.size * Rank.all.size) return false
263+
if (row < (File.all.size / 2 + 1)) {
264+
if (remainder >= (File.all.size / 2 + 1 + row)) return false
265+
} else {
266+
if (remainder <= (row - (File.all.size / 2 + 1))) return false
267+
}
268+
return true
269+
}
270+
244271
def apply(index: Int): Option[Pos] =
245-
if (0 <= index && index < File.all.size * Rank.all.size) Some(new Pos(index))
272+
if (isInHexagon(index)) Some(new Pos(index))
246273
else None
247274

248-
// @TODO VFR: determine if we want this code to work for hexagons or not (because we compute index based on a regular row size)
249-
def apply(file: File, rank: Rank): Pos = new Pos(file.index + File.all.size * rank.index)
275+
def apply(file: File, rank: Rank): Option[Pos] =
276+
if (isInHexagon(file.index + File.all.size * rank.index)) Some(new Pos(file.index + File.all.size * rank.index))
277+
else None
250278

251279
def at(x: Int, y: Int): Option[Pos] =
252-
if (0 <= x && x < File.all.size && 0 <= y && y < Rank.all.size) {
253-
if (Piotr.lookup.keySet.exists(_ == x + File.all.size * y))
254-
Some(new Pos(x + File.all.size * y))
255-
else None
256-
} else if (x == (File.all.size - 1) && 0 <= y && y < Rank.all.size) {
257-
if (Piotr.lookup.keySet.exists(_ == y + File.all.size * Rank.all.size))
258-
Some(new Pos(y + File.all.size * Rank.all.size))
259-
else None
260-
} else None
261-
280+
if (isInHexagon(x + File.all.size * y)) Some(new Pos(x + File.all.size * y))
281+
else None
262282

263283
def fromKey(key: String): Option[Pos] = allKeys get key
264284

@@ -359,8 +379,7 @@ object Pos {
359379
val H9 = new Pos(79)
360380
val I9 = new Pos(80)
361381

362-
// @TODO: does not generate the hexagon coordinates, just the 9x9 square - do we want it to generate the hexagon only ?
363-
val all: List[Pos] = (0 to (File.all.size * Rank.all.size) - 1).map(new Pos(_)).toList
382+
val all: List[Pos] = (0 to (File.all.size * Rank.all.size) - 1).map(new Pos(_)).toList.filter(i => isInHexagon(i.index))
364383

365384
val allKeys: Map[String, Pos] = all
366385
.map { pos =>

src/main/scala/abalone/format/Visual.scala

+4-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ object Visual {
4040
for (y <- Rank.allReversed) yield {
4141
for (x <- File.all) yield {
4242
val pos = Pos(x, y)
43-
markedPoss.get(pos) getOrElse board(pos).fold(' ')(_ forsyth)
43+
pos match {
44+
case Some(pos) => markedPoss.get(pos) getOrElse board(pos).fold(' ')(_ forsyth)
45+
case None => None
46+
}
4447
}
4548
} mkString
4649
} map { """\s*$""".r.replaceFirstIn(_, "") } mkString "\n"

src/main/scala/abalone/variant/Abalone.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ case object Abalone
2020

2121
override def baseVariant: Boolean = true
2222

23-
// pieces, turn, scoreP1, scoreP2, halfMovesSinceLastCapture (when = 100? => draw), total moves
23+
// pieces, scoreP1, scoreP2, turn, halfMovesSinceLastCapture (triggering condition could be when == 100 && total moves > 50 ? => draw), total moves
2424
override def initialFen = format.FEN("pp1PP/pppPPP/1pp1pp1/8/9/8/1PP1pp1/PPPppp/PP1pp 0 0 b 0 0")
2525

2626
// TODO: Abalone set

src/test/scala/abalone/AbalonePosTest.scala

+85-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,89 @@ import org.specs2.matcher.ValidatedMatchers
55
class AbalonePosTest extends AbaloneTest with ValidatedMatchers {
66
"grid coordinates" should {
77
"describe 61 positions" in {
8-
Pos.allPiotrs.size must_== 61
8+
Pos.all.size must_== 61
9+
}
10+
11+
"be shaped as an hexagon when accessed in 1D" in {
12+
Pos.isInHexagon(-1) must_== false
13+
14+
Pos.isInHexagon(0) must_== true
15+
Pos.isInHexagon(1) must_== true
16+
Pos.isInHexagon(4) must_== true
17+
Pos.isInHexagon(5) must_== false
18+
Pos.isInHexagon(6) must_== false
19+
Pos.isInHexagon(7) must_== false
20+
Pos.isInHexagon(8) must_== false
21+
22+
Pos.isInHexagon(9) must_== true
23+
Pos.isInHexagon(14) must_== true
24+
Pos.isInHexagon(15) must_== false
25+
Pos.isInHexagon(16) must_== false
26+
Pos.isInHexagon(17) must_== false
27+
28+
Pos.isInHexagon(18) must_== true
29+
Pos.isInHexagon(25) must_== false
30+
Pos.isInHexagon(26) must_== false
31+
32+
Pos.isInHexagon(35) must_== false
33+
Pos.isInHexagon(36) must_== true
34+
Pos.isInHexagon(44) must_== true
35+
36+
Pos.isInHexagon(45) must_== false
37+
Pos.isInHexagon(53) must_== true
38+
39+
Pos.isInHexagon(54) must_== false
40+
Pos.isInHexagon(55) must_== false
41+
Pos.isInHexagon(60) must_== true
42+
43+
Pos.isInHexagon(63) must_== false
44+
Pos.isInHexagon(54) must_== false
45+
Pos.isInHexagon(65) must_== false
46+
Pos.isInHexagon(71) must_== true
47+
48+
Pos.isInHexagon(72) must_== false
49+
Pos.isInHexagon(73) must_== false
50+
Pos.isInHexagon(74) must_== false
51+
Pos.isInHexagon(75) must_== false
52+
Pos.isInHexagon(80) must_== true
53+
54+
Pos.isInHexagon(81) must_== false
55+
Pos.isInHexagon(88) must_== false
56+
57+
Pos.isInHexagon(9001) must_== false
58+
}
59+
60+
"be shaped as an hexagon when accessed in 2D" in {
61+
// testing first row
62+
Pos(File(0).get, Rank(0).get) must_!= None
63+
Pos(File(1).get, Rank(0).get) must_!= None
64+
Pos(File(2).get, Rank(0).get) must_!= None
65+
Pos(File(3).get, Rank(0).get) must_!= None
66+
Pos(File(4).get, Rank(0).get) must_!= None
67+
Pos(File(5).get, Rank(0).get) must_== None
68+
Pos(File(6).get, Rank(0).get) must_== None
69+
Pos(File(7).get, Rank(0).get) must_== None
70+
Pos(File(8).get, Rank(0).get) must_== None
71+
72+
// testing last row
73+
Pos(File(0).get, Rank(8).get) must_== None
74+
Pos(File(1).get, Rank(8).get) must_== None
75+
Pos(File(2).get, Rank(8).get) must_== None
76+
Pos(File(3).get, Rank(8).get) must_== None
77+
Pos(File(4).get, Rank(8).get) must_!= None
78+
Pos(File(5).get, Rank(8).get) must_!= None
79+
Pos(File(6).get, Rank(8).get) must_!= None
80+
Pos(File(7).get, Rank(8).get) must_!= None
81+
Pos(File(8).get, Rank(8).get) must_!= None
82+
}
83+
84+
"compute its index based on a shape of square when accessed in 2D" in {
85+
Pos(File(0).get, Rank(0).get) must_== Pos(0)
86+
Pos(File(8).get, Rank(0).get) must_== Pos(8)
87+
88+
Pos(File(0).get, Rank(1).get) must_== Pos(9)
89+
90+
Pos(File(8).get, Rank(8).get) must_== Pos(80)
991
}
1092
}
1193

@@ -14,7 +96,7 @@ class AbalonePosTest extends AbaloneTest with ValidatedMatchers {
1496
Pos.E5.right must_== Some(Pos.F5)
1597
}
1698
"decrement letter only when moving to the left" in {
17-
Pos.E5.right must_== Some(Pos.F5)
99+
Pos.E5.left must_== Some(Pos.D5)
18100
}
19101
"increment number and letter when moving upRight" in {
20102
Pos.E5.upRight must_== Some(Pos.F6)
@@ -70,5 +152,5 @@ class AbalonePosTest extends AbaloneTest with ValidatedMatchers {
70152
Pos.C7.downRight must_== Some(Pos.C6)
71153
Pos.C7.upRight must_== Some(Pos.D8)
72154
}
73-
}
155+
}
74156
}

0 commit comments

Comments
 (0)