Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
art generation
/// @title A library that generates HTML art for fiveoutofnine (an on-chain 6x6 chess engine)
/// The art is generated as HTML code with in-line CSS (0 JS)
contract fiveoutofnineART {
/// @notice Takes in data for a given fiveoutofnine NFT and outputs its metadata in JSON form.
/// @param _internalId A bitpacked uint256 where the first 128 bits are the game ID, and the
/// last 128 bits are the move ID within the game.
/// @param _move A struct with information about the player's move and engine's response (see
/// {Chess-Move}).
/// @return Base 64-encoded JSON of metadata generated from `_internalId` and `_move`.
function getMetadata(uint256 _internalId, Chess.Move memory _move)
internal pure
returns (string memory)
{
string memory description;
string memory image;
string memory attributes;
uint256 depth;
// ... SKIPPED: lots of if statements, complex code,
// and lots of manual string concatenations to correctly generate
// description, image, and attributes.
return string(
abi.encodePacked(
"data:application/json;base64,",
Base64.encode(
abi.encodePacked(
'{"name":"Game #',
Strings.toString(_internalId >> 0x80),
", Move #",
Strings.toString(uint128(_internalId)),
'",'
'"description":"',
description,
'","animation_url":"data:text/html;base64,',
image,
'","attributes":[{"trait_type":"Depth","value":',
depth.toString(),
"},",
attributes,
"]}"
)
)
)
);
}
/// @notice Generates the HTML image and its attributes for a given board/seed according to the
/// table described in {fiveoutofnineART}.
/// @dev The output of the image is base 64-encoded.
/// @param _board The board after the player's and engine's move are played.
/// @param _numSquares The dimension of the board.
/// @param _seed A hash of the game ID, move ID, board position, and metadata.
/// @param _pieceCaptured Whether or not any piees were captured.
/// @return Base 64-encoded image (in HTML) and its attributes.
function getImage(uint256 _board, uint256 _numSquares, uint256 _seed, bool _pieceCaptured)
internal pure
returns (string memory, string memory)
{
// ... SKIPPED: again, lots of if statements,
// and manual string concatenations to correctly generate HTML for image
unchecked {
for (uint256 i; i < 23; ++i) {
styles = string(
abi.encodePacked(
styles,
".r",
i.toString(),
"{top:calc(var(--o) + ",
i.toString(),
"*(var(--n)/2 + var(--c)))}"
".c",
i.toString(),
"{left:calc(var(--p) ",
i < 11 ? "-" : "+",
" 0.866*",
i < 11 ? (11 - i).toString() : (i - 11).toString(),
"*(var(--n) + var(--c)))}"
)
);
}
string memory image;
for (/* row loop */) {
for (/* column loop */) {
image = string(abi.encodePacked(
image,
getPillarHtml(_board, 12 / _numSquares, row, col)));
}
}
return (Base64.encode(abi.encodePacked(
styles,
"</style><section>",
image,
"</section>")),
attributes);
}
}
/// @notice Returns the HTML for a particular pillar within the image.
/// @param _board The board after the player's and engine's move are played.
/// @param _dim The dimension of the bits within a pillar.
/// @param _row The row index of the pillar.
/// @param _col The column index of the pillar.
/// @return The HTML for the pillar described by the parameters.
function getPillarHtml(uint256 _board, uint256 _dim, uint256 _row, uint256 _col)
internal pure
returns (string memory)
{
string memory pillar = string(
abi.encodePacked(
'<div class="c r',
_row.toString(),
" c",
_col.toString(),
'"><div></div><div></div><div>'
)
);
unchecked {
for (/* row loop */) {
for (/* column loop */) {
pillar = string(abi.encodePacked(
pillar,
'<div id="',
(
_board
>> (Chess.getAdjustedIndex(6 * (y >> 1) + (x >> 1)) << 2)
>> (((0xD8 >> ((x & 1) << 2)) >> ((y & 1) << 1)) & 3)
)
& 1 == 0
? "h"
: "i",
'"></div>'));
}
}
}
return string(abi.encodePacked(pillar, "</div></div>"));
}
/// @notice Draws out a move being played out on a board position as a string with unicode
/// characters to represent pieces. Files and rows are labeled with standard algebraic
/// notation. For example:
/// ```
/// 6 ♜ ♝ ♛ ♚ ♝ ♜
/// 5 ♟ ♟ ♟ ♟ ♟ ♟
/// 4 · · · · · ·
/// 3 · · ♙ · · ·
/// 2 ♙ ♙ * ♙ ♙ ♙
/// 1 ♖ ♘ ♕ ♔ ♘ ♖
/// a b c d e f
/// ```
/// * indicates the square the piece moved from.
/// @param _board The board the move is played on.
/// @param _fromIndex The from index of the move.
/// @return The string showing the move played out on the board.
function drawMove(uint256 _board, uint256 _fromIndex) internal pure returns (string memory) {
// ... SKIPPED
}
/// @notice Maps piece type to its corresponding name.
/// @param _type A piece type defined in {Chess}.
/// @return The name corresponding to `_type`.
function getPieceName(uint256 _type) internal pure returns (string memory) {
if (_type == 1) return "pawn";
else if (_type == 2) return "bishop";
else if (_type == 3) return "rook";
else if (_type == 4) return "knight";
else if (_type == 5) return "queen";
return "king";
}
/// @notice Maps pieces to its corresponding unicode character.
/// @param _piece A piece.
/// @return The unicode character corresponding to `_piece`. It returns ``.'' otherwise.
function getPieceChar(uint256 _piece) internal pure returns (string memory) {
if (_piece == 1) return unicode"♟";
if (_piece == 2) return unicode"♝";
if (_piece == 3) return unicode"♜";
if (_piece == 4) return unicode"♞";
if (_piece == 5) return unicode"♛";
if (_piece == 6) return unicode"♚";
if (_piece == 9) return unicode"♙";
if (_piece == 0xA) return unicode"♗";
if (_piece == 0xB) return unicode"♖";
if (_piece == 0xC) return unicode"♘";
if (_piece == 0xD) return unicode"♕";
if (_piece == 0xE) return unicode"♔";
return unicode"·";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment