79 lines
2.7 KiB
Nim
79 lines
2.7 KiB
Nim
## Low-level handling of squares, board indeces and pieces
|
|
import std/strutils
|
|
import std/strformat
|
|
|
|
|
|
type
|
|
Square* = distinct int8
|
|
## A square
|
|
|
|
PieceColor* = enum
|
|
## A piece color enumeration
|
|
White = 0'i8
|
|
Black = 1
|
|
None
|
|
|
|
PieceKind* = enum
|
|
## A chess piece enumeration
|
|
Bishop = 0'i8
|
|
King = 1
|
|
Knight = 2
|
|
Pawn = 3
|
|
Queen = 4
|
|
Rook = 5
|
|
Empty = 6 # No piece
|
|
|
|
|
|
Piece* = object
|
|
## A chess piece
|
|
color*: PieceColor
|
|
kind*: PieceKind
|
|
|
|
|
|
func nullPiece*: Piece {.inline.} = Piece(kind: Empty, color: None)
|
|
func nullSquare*: Square {.inline.} = Square(-1'i8)
|
|
func opposite*(c: PieceColor): PieceColor {.inline.} = (if c == White: Black else: White)
|
|
func isValid*(a: Square): bool {.inline.} = a.int8 in 0..63
|
|
func isLightSquare*(a: Square): bool {.inline.} = (a.int8 and 2) == 0
|
|
func `==`*(a, b: Square): bool {.inline.} = a.int8 == b.int8
|
|
func `!=`*(a, b: Square): bool {.inline.} = a.int8 != b.int8
|
|
func `-`*(a, b: Square): Square {.inline.} = Square(a.int8 - b.int8)
|
|
func `-`*(a: Square, b: SomeInteger): Square {.inline.} = Square(a.int8 - b.int8)
|
|
func `-`*(a: SomeInteger, b: Square): Square {.inline.} = Square(a.int8 - b.int8)
|
|
func `+`*(a, b: Square): Square {.inline.} = Square(a.int8 + b.int8)
|
|
func `+`*(a: Square, b: SomeInteger): Square {.inline.} = Square(a.int8 + b.int8)
|
|
func `+`*(a: SomeInteger, b: Square): Square {.inline.} = Square(a.int8 + b.int8)
|
|
|
|
func fileFromSquare*(square: Square): int8 = square.int8 mod 8
|
|
func rankFromSquare*(square: Square): int8 = square.int8 div 8
|
|
|
|
|
|
func makeSquare*(rank, file: SomeInteger): Square = Square((rank * 8) + file)
|
|
|
|
|
|
proc toSquare*(s: string): Square {.discardable.} =
|
|
## Converts a square square from algebraic
|
|
## notation to its corresponding row and column
|
|
## in the chess grid (0 indexed)
|
|
if len(s) != 2:
|
|
raise newException(ValueError, "algebraic position must be of length 2")
|
|
|
|
var s = s.toLowerAscii()
|
|
if s[0] notin 'a'..'h':
|
|
raise newException(ValueError, &"algebraic position has invalid first character ('{s[0]}')")
|
|
if s[1] notin '1'..'8':
|
|
raise newException(ValueError, &"algebraic position has invalid second character ('{s[1]}')")
|
|
|
|
return Square((s[0].uint8 - uint8('a')) + ((s[1].uint8 - uint8('1')) xor 7) * 8)
|
|
|
|
|
|
proc toAlgebraic*(square: Square): string {.inline.} =
|
|
## Converts a square from our internal rank/file
|
|
## notation to a square in algebraic notation
|
|
let
|
|
file = char('a'.uint8 + (square.uint64 and 7))
|
|
rank = char('1'.uint8 + ((square.uint64 div 8) xor 7))
|
|
return &"{file}{rank}"
|
|
|
|
|
|
proc `$`*(square: Square): string = square.toAlgebraic() |