• Stars
    star
    376
  • Rank 113,810 (Top 3 %)
  • Language
    Swift
  • License
    Apache License 2.0
  • Created over 8 years ago
  • Updated about 6 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A cross-platform chess library for Swift

Deprecated

This project is no longer in development. I am currently developing a chess engine, Hexe. It is written in Rust, which is very similar to Swift in many ways. There also exists Hexe.swift, a Swift wrapper for Hexe.

Sage is not a chess engine; it's a move generator. Hexe, on the other hand, is able to both generate moves and evaluate them.


Sage

Swift 2.2 | 3.0 Platforms Gitter Apache 2.0 License

CocoaPods Carthage Swift Package Manager Documented

Sage is a cross-platform chess library for Swift.

Development happens in the develop branch.

Build Status

Branch Status
master Build Status
develop Build Status

Features

  • Chess game management
  • Chess board structuring
  • Move generation / validation
  • En passant and castling
  • Pawn promotions
  • FEN for games and boards
  • PGN parsing and exporting
  • Documentation

Installation

Compatibility

  • Platforms:
    • macOS 10.9+
    • iOS 8.0+
    • watchOS 2.0+
    • tvOS 9.0+
    • Linux
  • Xcode 7.3 and 8.0
  • Swift 2.2 and 3.0

Install Using Swift Package Manager

The Swift Package Manager is a decentralized dependency manager for Swift.

  1. Add the project to your Package.swift.

    import PackageDescription
    
    let package = Package(
        name: "MyAwesomeProject",
        dependencies: [
            .Package(url: "https://github.com/nvzqz/Sage.git",
                     majorVersion: 2)
        ]
    )
  2. Import the Sage module.

    import Sage

Install Using CocoaPods

CocoaPods is a centralized dependency manager for Objective-C and Swift. Go here to learn more.

  1. Add the project to your Podfile.

    use_frameworks!
    
    pod 'Sage', '~> 2.0.0'

    If you want to be on the bleeding edge, replace the last line with:

    pod 'Sage', :git => 'https://github.com/nvzqz/Sage.git'
  2. Run pod install and open the .xcworkspace file to launch Xcode.

  3. Import the Sage framework.

    import Sage

Install Using Carthage

Carthage is a decentralized dependency manager for Objective-C and Swift.

  1. Add the project to your Cartfile.

    github "nvzqz/Sage"
    
  2. Run carthage update and follow the additional steps in order to add Sage to your project.

  3. Import the Sage framework.

    import Sage

Install Manually

  1. Download and drop the /Sources folder into your project.

  2. Congratulations!

Usage

Game Management

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

import Sage

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

Sage 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

Sage 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.

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.

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.

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.

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.

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.

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.

[.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

To use Sage.playground, first open Sage.xcodeproj and build the OS X target. You can then use the playground from within the project.

Board Quick Look

Board conforms to the CustomPlaygroundQuickLookable protocol.

Playground quick look

Donation

I work on this in my free time and do my best to make it as great as it can be. If you want to help me keep pushing out awesome libraries like this, a donation would be greatly appreciated. 😄

paypal

License

Sage is published under version 2.0 of the Apache License.

More Repositories

1

FileKit

Simple and expressive file management in Swift
Swift
2,289
star
2

RandomKit

Random data generation in Swift
Swift
1,473
star
3

divan

Fast and simple benchmarking for Rust projects
Rust
895
star
4

static-assertions

Ensure correct assumptions about constants, types, and more in Rust
Rust
566
star
5

impls

A Rust macro to determine if a type implements a logical trait expression
Rust
246
star
6

Menubar-Colors

A macOS app for convenient access to the system color panel
Swift
175
star
7

fruity

Rusty bindings for Apple libraries
Rust
169
star
8

swift-bindgen

Bridging the gap between Swift and Rust
Rust
149
star
9

Unreachable

Unreachable code path optimization hint for Swift
Swift
103
star
10

Threadly

Type-safe thread-local storage in Swift
Swift
74
star
11

condtype

Choose Rust types at compile-time via constants
Rust
59
star
12

embed-plist-rs

Embed property list files like Info.plist directly in your Rust executable binary
Rust
39
star
13

Roman

Seamless Roman numeral conversion in Swift
Swift
36
star
14

rosy

Rust and Ruby, sitting in a tree 🌹
Rust
23
star
15

byte-set-rs

Efficient sets of bytes for Rust
Rust
19
star
16

cargo-emit

Talk to Cargo easily at build time
Rust
16
star
17

Clockmoji

Simple and intuitive time formatting using clock emoji.
Swift
13
star
18

XO

A cross-platform tic-tac-toe library for Swift
Swift
13
star
19

Lazy

Save the hard work for later, lazily evaluate values anywhere
Swift
12
star
20

Weak

Weak and Unowned as native Swift types
Swift
10
star
21

typebool

Type-level booleans in Rust for compile-time hackery
Rust
8
star
22

c-utf8-rs

UTF-8 encoded C strings for Rust
Rust
6
star
23

malloced

A malloc-ed box pointer type for Rust
Rust
5
star
24

dotfiles

Personal dotfiles
Shell
5
star
25

aloxide

Compile Rubies on Linux, macOS, and Windows
Rust
5
star
26

mods

Simpler Rust module declaration
Rust
5
star
27

bit-collection-rs

Iterate over bits in Rust
Rust
5
star
28

unsafe-unwrap-rs

Unsafely unwrap Result and Option types without checking in Rust
Rust
5
star
29

uncon-rs

Unchecked and unsafe type conversions in Rust
Rust
4
star
30

head-rs

Common Rust types with inline headers, such as HeaderVec for Vec
Rust
4
star
31

bad-rs

Unlicensed bad ideas
Rust
4
star
32

rust-workshop

A workshop on the Rust programming language
3
star
33

OneOrMore

A Swift collection of one or more elements
Swift
3
star
34

fmty

Rust library of composable `core::fmt` utilities
Rust
3
star
35

mem-cmp-rs

Safe memory comparison between types in Rust
Rust
2
star
36

ShiftOperations

A µframework for a needed ShiftOperations protocol that does not appear in the Swift standard library
Swift
1
star
37

rust-selector-example

My attempt at creating Objective-C selectors in Rust at compile time
Shell
1
star
38

asygnal

Handle signals (e.g. ctrl-c) efficiently and asynchronously in Rust
Rust
1
star
39

chance-rs

Random number generation in Rust
Rust
1
star