Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

movegen.gno

2.75 Kb · 124 lines
  1package minichess
  2
  3func lastRank(c Color) int {
  4	if c == White {
  5		return Size - 1
  6	}
  7	return 0
  8}
  9
 10// Attacked reports whether square sq is attacked by any piece of colour by.
 11func (p Position) Attacked(sq int, by Color) bool {
 12	return newEngine(&p).attacked(sq, by)
 13}
 14
 15// InCheck reports whether the side to move is in check.
 16func (p Position) InCheck() bool {
 17	return newEngine(&p).inCheck()
 18}
 19
 20// LegalMoves returns all legal moves for the side to move.
 21func (p Position) LegalMoves() []Move {
 22	enc := newEngine(&p).legal()
 23	out := make([]Move, len(enc))
 24	for i, m := range enc {
 25		out[i] = decode(m)
 26	}
 27	return out
 28}
 29
 30// Play applies a move without validating it and returns the new position.
 31// Callers must only pass moves obtained from LegalMoves or FindLegal.
 32func (p Position) Play(m Move) Position {
 33	e := newEngine(&p)
 34	e.make(m.encode())
 35	full := p.Fullmove
 36	if p.Turn == Black {
 37		full++
 38	}
 39	return e.position(full)
 40}
 41
 42// IsIrreversible reports whether m is a capture or pawn move (resets the
 43// repetition history and the 50-move counter).
 44func (p Position) IsIrreversible(m Move) bool {
 45	return p.Board[m.From].Type() == Pawn || p.Board[m.To] != Empty
 46}
 47
 48// FindLegal matches m against the legal moves. A promotion move given
 49// without a piece defaults to a queen. Returns false if m is illegal.
 50func (p Position) FindLegal(m Move) (Move, bool) {
 51	if m.Promo == Empty {
 52		pc := p.Board[m.From]
 53		if pc.Type() == Pawn && pc.Color() == p.Turn && m.To/Size == lastRank(p.Turn) {
 54			m.Promo = Queen
 55		}
 56	}
 57	want := m.encode()
 58	for _, lm := range newEngine(&p).legal() {
 59		if lm == want {
 60			return m, true
 61		}
 62	}
 63	return m, false
 64}
 65
 66// Status describes whether the game is still going and how it ended.
 67type Status int
 68
 69const (
 70	Ongoing Status = iota
 71	Checkmate
 72	Stalemate
 73	FiftyMoveDraw
 74	InsufficientMaterial
 75)
 76
 77func (s Status) String() string {
 78	switch s {
 79	case Ongoing:
 80		return "ongoing"
 81	case Checkmate:
 82		return "checkmate"
 83	case Stalemate:
 84		return "stalemate"
 85	case FiftyMoveDraw:
 86		return "50-move rule"
 87	case InsufficientMaterial:
 88		return "insufficient material"
 89	}
 90	return "unknown"
 91}
 92
 93// Status computes the game status from the position alone. Threefold
 94// repetition needs move history and is handled by the caller.
 95func (p Position) Status() Status {
 96	e := newEngine(&p)
 97	if len(e.legal()) == 0 {
 98		if e.inCheck() {
 99			return Checkmate
100		}
101		return Stalemate
102	}
103	if p.insufficientMaterial() {
104		return InsufficientMaterial
105	}
106	if p.Halfmove >= 100 {
107		return FiftyMoveDraw
108	}
109	return Ongoing
110}
111
112// insufficientMaterial: only kings, or kings plus a single minor piece.
113func (p Position) insufficientMaterial() bool {
114	minors := 0
115	for _, pc := range p.Board {
116		switch pc.Type() {
117		case Pawn, Rook, Queen:
118			return false
119		case Knight, Bishop:
120			minors++
121		}
122	}
123	return minors <= 1
124}