~/bend-docscommunity

game.bend checks

raw source on the hub · import 0x6d15da24c6555ddee2181d043774a796/game.bend as Game

# TinyChess — the game. # # chess.bend says how a piece steps on an empty board. This file is the # rest: what stands where, what a capture is, when a king is attacked, # and when a side is mated. Everything here is computable and has no # holes, so the checker can settle a claim about a position by running # it rather than by being argued with. # # The opening position, black at the top: # # a b c d # 4 ♟ ♟ ♚ ♟ 12 13 14 15 # 3 · · · · 8 9 10 11 # 2 · · · · 4 5 6 7 # 1 ♙ ♔ ♙ ♙ 0 1 2 3 # # Both back ranks are full and the kings stand on different files, so # neither side begins in opposition and every pawn has somewhere to go. # # Sizes are the point of every loop below. There are sixteen squares and # eight pieces, so a scan is sixteen steps, an attack test is sixteen # scans, and the whole "can white win on the first move" question is a # few tens of thousands of steps. That is small enough for the checker # to simply evaluate, which is why the law about it needs no argument.

2 imports
import Base
import ./chess.bend as C

Types

type Piece source · line 31 · raw

Data

type Cells source · line 120 · raw

Data

the sixteen squares, a1 first. Base's List is kind-polymorphic and a plain Data field wants a plain Data list, so this one is its own.

type Board source · line 124 · raw

Data

type Step source · line 127 · raw

Data

Definitions

def is_white source · line 42 · raw

@p:Piece -> Bool

def is_empty_piece source · line 63 · raw

@p:Piece -> Bool

def is_king source · line 84 · raw

@p:Piece -> Bool

def mine source · line 106 · raw

@+white:Bool -> @+p:Piece -> Bool

whether a piece belongs to the side to move

def theirs source · line 113 · raw

@+white:Bool -> @+p:Piece -> Bool

def Step.from source · line 130 · raw

@m:Step -> Nat

def Step.to source · line 135 · raw

@m:Step -> Nat

def cell source · line 140 · raw

@c:Cells -> @s:Nat -> Piece

def put_cell source · line 151 · raw

@c:Cells -> @s:Nat -> @+p:Piece -> Cells

def occupant source · line 164 · raw

@+b:Board -> @+s:Nat -> Piece

what stands on a square. Off the board reads as empty, which is what makes the scans below safe to run past the last square.

def place source · line 169 · raw

@+b:Board -> @+s:Nat -> @+p:Piece -> Board

def pick_nat source · line 175 · raw

@c:Bool -> @+a:Nat -> @+b:Nat -> Nat

choosing between two numbers, which the scans need and Bool.pick is not

def mid3 source · line 186 · raw

@+x:Nat -> @+y:Nat -> @+z:Nat -> Bool

y lies between x and z along one axis: strictly, or all three equal, which is the case where the move does not travel on that axis at all

def between source · line 196 · raw

@+a:Nat -> @+s:Nat -> @+b:Nat -> Bool

s is strictly inside the line from a to b. On a board four wide there are at most two such squares, so testing all sixteen is cheaper than working out a direction and stepping along it.

def clear_go source · line 202 · raw

@+bd:Board -> @+a:Nat -> @+b:Nat -> @n:Nat -> Bool

def clear source · line 212 · raw

@+bd:Board -> @+a:Nat -> @+b:Nat -> Bool

nothing stands between a and b

def attacks_as source · line 222 · raw

@p:Piece -> @+bd:Board -> @+from:Nat -> @+to:Nat -> Bool

whether the piece standing on from attacks to. A pawn attacks only where it could take, never where it could push, which is the rule that makes pawn structure mean anything. the checker will not match on a computed value, so the piece arrives as a parameter and the lookup happens in the caller

def attacks source · line 243 · raw

@+bd:Board -> @+from:Nat -> @+to:Nat -> Bool

def attacked_go source · line 246 · raw

@+bd:Board -> @+w:Bool -> @+s:Nat -> @n:Nat -> Bool

def attacked source · line 256 · raw

@+bd:Board -> @+w:Bool -> @+s:Nat -> Bool

whether the given side attacks a square

def king_go source · line 259 · raw

@+bd:Board -> @+w:Bool -> @n:Nat -> Nat

def king_square source · line 270 · raw

@+bd:Board -> @+w:Bool -> Nat

where the given side's king stands. A board with no king answers 16, which is off the board and therefore attacked by nothing.

def in_check source · line 273 · raw

@+bd:Board -> @+w:Bool -> Bool

def play source · line 278 · raw

@+bd:Board -> @+m:Step -> Board

def shape_ok source · line 287 · raw

@moving:Piece -> @+target:Piece -> @+bd:Board -> @+w:Bool -> @+f:Nat -> @+t:Nat -> Bool

the geometry, plus what the position allows: your own piece is not a target, a queen needs a clear line, a pawn pushes only onto an empty square and takes only onto an occupied one.

def any_to source · line 327 · raw

@+bd:Board -> @+w:Bool -> @+f:Nat -> @n:Nat -> Bool

def any_from source · line 335 · raw

@+bd:Board -> @+w:Bool -> @n:Nat -> Bool

def is_checkmate source · line 347 · raw

@+bd:Board -> @+w:Bool -> Bool

in check, and nothing to do about it

def is_stalemate source · line 350 · raw

@+bd:Board -> @+w:Bool -> Bool

def no_move source · line 357 · raw

Step

"there isn't one". Square 16 is off the board, so no real move can collide with it, and a failed law prints this against the move it found.

def found source · line 360 · raw

@+m:Step -> Bool

def pick_move source · line 363 · raw

@c:Bool -> @+a:Step -> @+b:Step -> Step

def wins_to source · line 370 · raw

@+bd:Board -> @+f:Nat -> @n:Nat -> Step

def wins_from source · line 380 · raw

@+bd:Board -> @n:Nat -> Step

def winning_first_move source · line 392 · raw

@+bd:Board -> Step

The move that mates, or no_move() when there is none. Returning the move rather than a Bool is what lets a broken law name its own counterexample: the checker prints what it observed, so the error carries Step{from, to}.

def white_wins_in_one source · line 396 · raw

@+bd:Board -> Bool

whether white has a first move that mates black on the spot

def row source · line 401 · raw

@a:Piece -> @b:Piece -> @c:Piece -> @d:Piece -> @rest:Cells -> Cells

def empty_row source · line 404 · raw

@rest:Cells -> Cells

def initial source · line 409 · raw

Board

rank 1 first: white pawn, white king, white pawn, white pawn, then two empty ranks, then black's pawn, pawn, king, pawn

def initial_with_queen source · line 416 · raw

Board

the same, with the pawn beside white's king traded for a queen

def initial_with_queens source · line 424 · raw

Board

a queen each, on the square beside each king, so the position stays symmetric under turning the board around

def initial_with_knight source · line 431 · raw

Board

a knight for white alone, on the square the queen took

def initial_with_knights source · line 438 · raw

Board

and the same two squares, knights instead