Skip to content

Instantly share code, notes, and snippets.

@ToJans
Created Apr 22, 2021
Embed
What would you like to do?
using System;
using System.Collections.Generic;
using System.Linq;
/**
Chess: potential moves etc by @ToJans
Spiked in a couple of hours of late-night code for a tweet by @gregyoung
https://twitter.com/gregyoung/status/1385285718113722374
** unfinished & untested, most likely contains bugs **
**/
public class Vector {
public int X, Y;
public Vector(int x=0, int y=0) {
this.X = x;
this.Y = y;
}
public Vector Clone() {
return new Vector{ X = this.X , Y = this.Y};
}
public Vector[] In4Quadrants() {
return new Vector[]{this,new Vector(this.X,-this.Y), new Vector(-this.X,-this.Y), new Vector(-this.X,this.Y)};
}
public static Vector operator +(Vector left, Vector right) { return Apply(left,right,(l,r)=> l+r);}
public static Vector operator -(Vector left, Vector right) { return Apply(left,right,(l,r)=> l-r);}
private static Vector Apply(Vector left, Vector right, Func<int,int,int> fn) {
return new Vector(fn(left.X,right.X), fn(left.Y, right.Y));
}
public static Vector Up = new Vector(-1,0);
public static Vector Down = new Vector(1,0);
public static Vector Left = new Vector(0,-1);
public static Vector Right = new Vector(1,0);
public static Vector UpLeft = Up+Left;
public static Vector UpRight = Up+Right;
public static Vector DownLeft = Up+Left;
public static Vector DownRight = Up+Right;
public static Vector[] Cartesian = Up.In4Quadrants();
public static Vector[] Diagonal = UpLeft.In4Quadrants();
public static Vector[] AllDirections = Cartesian.Concat(Diagonal).ToArray();
}
public class ChessPosition:Vector {
public ChessPosition(int row = -1, int column = -1):base(row,column) {}
public bool IsOutOfBounds { get { return this.X<0 || this.X> 7 || this.Y < 0 | this.Y > 7; } }
public static ChessPosition operator +(ChessPosition left, Vector right) { return Apply(left,right,(l,r)=> l+r);}
public static ChessPosition operator -(ChessPosition left, Vector right) { return Apply(left,right,(l,r)=> l-r);}
private static ChessPosition Apply(ChessPosition left, Vector right, Func<int,int,int> fn) {
if (left.IsOutOfBounds) return left;
return new ChessPosition(fn(left.X,right.X), fn(left.Y, right.Y));
}
public IEnumerable<ChessPosition> ValidMovesInDirection(Vector direction) {
var current = this+direction;
while (!current.IsOutOfBounds) {
yield return current;
current+=direction;
}
}
public IEnumerable<IEnumerable<ChessPosition>> ValidMovesInMultipleDirections(IEnumerable<Vector> directions) {
return directions.Select(dir=>this.ValidMovesInDirection(dir));
}
}
enum Piece : byte {
Empty=0,
Pawn=1,
Tower=2,
Knight=3,
Bishop=4,
King=5,
Queen=6,
Black=8
}
class Move {
public ChessPosition From, To;
}
static class IEnumerableExtensions {
public static IEnumerable<T> TakeWhileInclusive<T>(this IEnumerable<T> items, Predicate<T> predicate) {
foreach(T item in items)
{
if(predicate(item))
{
yield return item;
}
else
{
yield return item;
yield break;
}
}
}
}
class Board {
Piece[,] board;
Board(Piece[,] board) {
this.board = board;
}
static Board Setup() {
var board = new Piece[8,8];
for (int y=0;y<8;y++) {
for (int x=0;x<8;x++) {
board[x,y] = y>5?Piece.Black:Piece.Empty;
switch (y) {
case 1: case 6: board[x,y] |= Piece.Pawn; break;
case 0: case 7:
switch (x) {
case 0: case 7: board[x,y] |= Piece.Tower; break;
case 1: case 6: board[x,y] |= Piece.Knight; break;
case 2: case 5: board[x,y] |= Piece.Bishop; break;
case 3: board[x,y] |= Piece.King; break;
case 4: board[x,y] |= Piece.Queen; break;
}
break;
default:
board[x,y] = Piece.Empty;
break;
}
}
}
return new Board(board);
}
public Piece this[ChessPosition position] {
get {
return position.IsOutOfBounds ? Piece.Empty:this.board[position.X,position.Y];
}
set {
if (!position.IsOutOfBounds) {
this.board[position.X,position.Y] = value;
}
}
}
IEnumerable<ChessPosition> PotentialMoves(ChessPosition position) {
var piece = this[position];
var positions = new List<ChessPosition>();
switch(piece) {
case Piece.Tower:
positions.AddRange(position
.ValidMovesInMultipleDirections(Vector.Cartesian)
.SelectMany(x=>x.TakeWhileInclusive(p=>this[p] == Piece.Empty)));
break;
case Piece.Bishop:
positions.AddRange(position
.ValidMovesInMultipleDirections(Vector.Diagonal)
.SelectMany(x=>x.TakeWhileInclusive(p=>this[p] == Piece.Empty)));
break;
case Piece.Queen:
positions.AddRange(position
.ValidMovesInMultipleDirections(Vector.AllDirections)
.SelectMany(x=>x.TakeWhileInclusive(p=>this[p] == Piece.Empty)));
break;
case Piece.Knight:
positions.AddRange(new Vector(3,2).In4Quadrants().Concat(new Vector(2,3).In4Quadrants())
.Select(v=>position + v).Where(p=>!p.IsOutOfBounds));
break;
case Piece.King:
positions.AddRange(Vector.AllDirections.Select(v=>position + v).Where(p=>!p.IsOutOfBounds));
// TODO: rochade?
break;
case Piece.Pawn:
case Piece.Pawn|Piece.Black:
var forward = (piece & Piece.Black) == Piece.Black ? Vector.Up:Vector.Down;
// TODO: pawn movement: opening, striking pieces etc
break;
}
// TODO: filter out moves that result in check
return positions;
}
}
public class Program
{
public static void Main()
{
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment