Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/navanchauhan/swift-chess-neo

Cross-Platform Swift Chess Library
https://github.com/navanchauhan/swift-chess-neo

Last synced: 2 days ago
JSON representation

Cross-Platform Swift Chess Library

Awesome Lists containing this project

README

        

# SwiftChessNeo

**WIP: I am actively developing swift-chess-neo while writing iWatchChess for iOS/macOS**

Fork of [Sage by @nvzqz](https://github.com/nvzqz/Sage) along with [@SuperGeroy](https://github.com/SuperGeroy)'s patches. This fork adds SwiftUI views, and other QoL improvements. Due to some technical difficulties, I ended up copying the files in the `Sources` folder and adding them to my project.

- [Usage](#usage)
- [Game Management](#game-management)
- [Move Execution](#move-execution)
- [Move Generation](#move-generation)
- [Move Validation](#move-validation)
- [Undo and Redo Moves](#undo-and-redo-moves)
- [Promotion Handling](#promotion-handling)
- [Pretty Printing](#pretty-printing)
- [Forsyth–Edwards Notation](#forsythedwards-notation)
- [Iterating Through a Board](#iterating-through-a-board)
- [Squares to Moves](#squares-to-moves)
- [Playground Usage](#playground-usage)
- [Board Quick Look](#board-quick-look)

## Usage

### Game Management

Running a chess game can be as simple as setting up a loop.

```swift
import SwiftChessNeo

let game = Game()

while !game.isFinished {
let move = ...
try game.execute(move: move)
}
```

### Move Execution

Moves for a `Game` instance can be executed with `execute(move:)` and its unsafe
(yet faster) sibling, `execute(uncheckedMove:)`.

The `execute(uncheckedMove:)` method assumes that the passed move is legal. It
should only be called if you *absolutely* know this is true. Such a case is when
using a move returned by `availableMoves()`. Otherwise use `execute(move:)`,
which checks the legality of the passed move.

### Move Generation

SwiftChessNeo is capable of generating legal moves for the current player with full
support for special moves such as en passant and castling.

- `availableMoves()` will return all moves currently available.

- `movesForPiece(at:)` will return all moves for a piece at a square.

- `movesBitboardForPiece(at:)` will return a `Bitboard` containing all of the
squares a piece at a square can move to.

### Move Validation

SwiftChessNeo can also validate whether a move is legal with the `isLegal(move:)`
method for a `Game` state.

The `execute(move:)` family of methods calls this method, so it would be faster
to execute the move directly and catch any error from an illegal move.

### Undo and Redo Moves

Move undo and redo operations are done with the `undoMove()` and `redoMove()`
methods. The undone or redone move is returned.

To just check what moves are to be undone or redone, the `moveToUndo()` and
`moveToRedo()` methods are available.

### Promotion Handling

The `execute(move:promotion:)` method takes a closure that returns a promotion
piece kind. This allows for the app to prompt the user for a promotion piece or
perform any other operations before choosing a promotion piece kind.

```swift
try game.execute(move: move) {
...
return .queen
}
```

The closure is only executed if the move is a pawn promotion. An error is thrown
if the promotion piece kind cannot promote a pawn, such as with a king or pawn.

A piece kind can also be given without a closure. The default is a queen.

```swift
try game.execute(move: move, promotion: .queen)
```

### Pretty Printing

The `Board` and `Bitboard` types both have an `ascii` property that can be used
to print a visual board.

```swift
let board = Board()

board.ascii
// +-----------------+
// 8 | r n b q k b n r |
// 7 | p p p p p p p p |
// 6 | . . . . . . . . |
// 5 | . . . . . . . . |
// 4 | . . . . . . . . |
// 3 | . . . . . . . . |
// 2 | P P P P P P P P |
// 1 | R N B Q K B N R |
// +-----------------+
// a b c d e f g h

board.occupiedSpaces.ascii
// +-----------------+
// 8 | 1 1 1 1 1 1 1 1 |
// 7 | 1 1 1 1 1 1 1 1 |
// 6 | . . . . . . . . |
// 5 | . . . . . . . . |
// 4 | . . . . . . . . |
// 3 | . . . . . . . . |
// 2 | 1 1 1 1 1 1 1 1 |
// 1 | 1 1 1 1 1 1 1 1 |
// +-----------------+
// a b c d e f g h
```

### Forsyth–Edwards Notation

The `Game.Position` and `Board` types can both generate a FEN string.

```swift
let game = Game()

game.position.fen()
// rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1

game.board.fen()
// rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR
```

They can also be initialized from a FEN string.

```swift
assert(Board(fen: game.board.fen()) == game.board)

assert(Game.Position(fen: game.position.fen()) == game.position)
```

### Iterating Through a Board

The `Board` type conforms to `Sequence`, making iterating through its spaces
seamless.

```swift
for space in Board() {
if let piece = space.piece {
print("\(piece) at \(space.square)")
}
}
```

### Squares to Moves

`Sequence` and `Square` have two methods that return an array of moves that go
from/to `self` to/from the parameter.

```swift
[.a1, .h3, .b5].moves(from: .b4)
// [b4 >>> a1, b4 >>> h3, b4 >>> b5]

[.c3, .d2, .f1].moves(to: .a6)
// [c3 >>> a6, d2 >>> a6, f1 >>> a6]

Square.d4.moves(from: [.c2, .f8, .h2])
// [c2 >>> d4, f8 >>> d4, h2 >>> d4]

Square.a4.moves(to: [.c3, .d4, .f6])
// [a4 >>> c3, a4 >>> d4, a4 >>> f6]
```

### Playground Usage

#### Board Quick Look

`Board` conforms to the `CustomPlaygroundDisplayConvertible` protocol.

![Playground quick look](https://raw.githubusercontent.com/SuperGeroy/Sage/assets/BoardPlaygroundView.png)

## To-Do

- [ ] SwiftUI Views (In-Progress)
- [ ] UCI Chess Engine Support
- [ ] SVG Resources
- Move Handling
- [ ] Enhance PGN Parsing
- [ ] Comprehensive PGN Support
- [ ] Support for different lines
- [ ] GameplayKit Support

### Possible Misc Enhancements

- Integrated Lichess Client (?)
- Player Database (?)

## License

Original Notice:

> Sage and its modifications are published under [version 2.0 of the Apache License](https://www.apache.org/licenses/LICENSE-2.0).