-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
fe5a941
commit d89e62c
Showing
10 changed files
with
1,653 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
# fiveoutofnine | ||
**fiveoutofnine** is the first **100% on-chain** chess engine, where minters **play against the smart | ||
contract**. Each move is minted as an NFT, and accompanied by a generative art piece. The majority of | ||
the project's development and beauty is in its algorithms and code that enable such complex | ||
computing, so the art highlights its design and implementation. All metadata and art is generated | ||
and stored 100% on-chain as well (see [`fiveoutofnineART.sol`](https://github.com/fiveoutofnine/fiveoutofnine-chess/tree/main/src/fiveoutofnineART.sol)). | ||
|
||
![](sample-art.png) | ||
|
||
A live version has been [deployed on mainnet](https://etherscan.io/address/0xb543f9043b387ce5b3d1f0d916e42d8ea2eba2e0#code). | ||
|
||
## Installation | ||
To install with [Foundry](https://github.com/gakonst/foundry): | ||
|
||
``` | ||
forge install fiveoutofnine/fiveoutofnine-chess | ||
``` | ||
|
||
## Bugs | ||
1. The engine may make a move that leaves its king in check. Pretty minor bug because the game can | ||
progress. Just... without black's king. The fix would be to do 1 more depth of search than the input | ||
depth. Any illegal black moves (moves that result in black's king being checked) would be eliminated | ||
lazily in the extra depth. [<u>Example</u>](https://etherscan.io/tx/0x057b4807662481a3244a25553b52e979c6c5bb3c177344b8585ff17a2a5e0222). | ||
|
||
2. The engine evaluates any queen/king move crossing the board's center incorrectly. `toIndex` and | ||
`fromIndex` must be evaluated in separate if/else blocks because they are not related. i.e. | ||
|
||
```js | ||
if (fromIndex < 0x12) { // Piece is queen or king and in the closer half | ||
oldPst = (getPstTwo(pieceAtFromIndex) >> (0xC * fromIndex)) & 0xFFF; | ||
newPst = (getPstTwo(pieceAtFromIndex) >> (0xC * toIndex)) & 0xFFF; | ||
} else { // Piece is queen or king and in the further half | ||
oldPst = (getPst(pieceAtFromIndex) >> (0xC * (fromIndex - 0x12))) & 0xFFF; | ||
newPst = (getPst(pieceAtFromIndex) >> (0xC * (toIndex - 0x12))) & 0xFFF; | ||
} | ||
``` | ||
|
||
should be | ||
|
||
```js | ||
if (fromIndex < 0x12) { // Piece is queen or king and moves from the closer half | ||
oldPst = (getPstTwo(pieceAtFromIndex) >> (0xC * fromIndex)) & 0xFFF; | ||
} else { // Piece is queen or king and in the further half | ||
oldPst = (getPst(pieceAtFromIndex) >> (0xC * (fromIndex - 0x12))) & 0xFFF; | ||
} | ||
if (toIndex < 0x12) { | ||
newPst = (getPstTwo(pieceAtFromIndex) >> (0xC * toIndex)) & 0xFFF; | ||
} else { | ||
newPst = (getPst(pieceAtFromIndex) >> (0xC * (toIndex - 0x12))) & 0xFFF; | ||
} | ||
``` | ||
|
||
There are some minor inaccuracies when the wrong PST is read from fortoIndex. A major inaccuracy | ||
occurs when `toIndex` is greater than `0x12`, it underflows (because it is a `uint256`) and | ||
bitshifts the corresponding PST to `0`. When this happens, any queen/king move is evaluated as a | ||
"very bad" move. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
@openzeppelin/=lib/openzeppelin-contracts/contracts |
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.9; | ||
|
||
/// @title Base64 | ||
/// @author Brecht Devos - <brecht@loopring.org> | ||
/// @notice Provides a function for encoding some bytes in base64 | ||
library Base64 { | ||
string internal constant TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678" | ||
"9+/"; | ||
|
||
function encode(bytes memory data) internal pure returns (string memory) { | ||
if (data.length == 0) return ""; | ||
string memory table = TABLE; | ||
uint256 encodedLength = ((data.length + 2) / 3) << 2; | ||
string memory result = new string(encodedLength + 0x20); | ||
|
||
assembly { | ||
mstore(result, encodedLength) | ||
let tablePtr := add(table, 1) | ||
let dataPtr := data | ||
let endPtr := add(dataPtr, mload(data)) | ||
let resultPtr := add(result, 0x20) | ||
for {} lt(dataPtr, endPtr) {} | ||
{ | ||
dataPtr := add(dataPtr, 3) | ||
let input := mload(dataPtr) | ||
mstore(resultPtr, shl(0xF8, mload(add(tablePtr, and(shr(0x12, input), 0x3F))))) | ||
resultPtr := add(resultPtr, 1) | ||
mstore(resultPtr, shl(0xF8, mload(add(tablePtr, and(shr(0xC, input), 0x3F))))) | ||
resultPtr := add(resultPtr, 1) | ||
mstore(resultPtr, shl(0xF8, mload(add(tablePtr, and(shr(6, input), 0x3F))))) | ||
resultPtr := add(resultPtr, 1) | ||
mstore(resultPtr, shl(0xF8, mload(add(tablePtr, and(input, 0x3F))))) | ||
resultPtr := add(resultPtr, 1) | ||
} | ||
switch mod(mload(data), 3) | ||
case 1 { mstore(sub(resultPtr, 2), shl(0xF0, 0x3D3D)) } | ||
case 2 { mstore(sub(resultPtr, 1), shl(0xF8, 0x3D)) } | ||
} | ||
|
||
return result; | ||
} | ||
} |
Oops, something went wrong.