#ifndef TETRIS_H
#define TETRIS_H 1
#include "util/intdef.h"
#include "util/atrb.h"

#define TET_WIDTH  10
#define TET_HEIGHT 24 /* height may be 16—24 */

/* Defines tetromino indices.
 * The `TET_R*` definitions specify various rotations.
 * This is designed to be OR'd with the tetromino shape index.
 * Shape index can be obtained via `val & 7`, and rotation index is
 * obtained via `val >> 3`. */
enum tetromino {
	TET_I = 0x00,
	TET_O = 0x01,
	TET_T = 0x02,
	TET_J = 0x03,
	TET_L = 0x04,
	TET_S = 0x05,
	TET_Z = 0x06,
	TET_R0 = 0x00,
	TET_R90 = 0x08,
	TET_R180 = 0x10,
	TET_R270 = 0x18,

	/* Used when storing blocks to the board;
	 * allows to identify non-empty indices from empty ones.
	 * This value should not be used during general computation. */
	TET_NON_EMPTY = 0x80,
};

/* Stores the co-ordinates of the four blocks in a 4x4 plane.
 * Each co-ordinate is 4 bits wide in total. (2 bits for each axis).
 * This is done over encoding the shape directly within the 16 bits (4²),
 * since this is more easily parsed in practice. */
extern const u16 tetromino_shapes[7][4];

/* Adds the block position data to the numbers in `positions`.
 * it is assumed `positions` has at least eight members and is initialised. `(X,Y)*4 = 8` */
void tetris_get_blocks(u8 tetromino, uint *restrict positions) NONNULL((2));

/* Initialises the rows of the Tetris play field.
 * `data` is assumed to point to data of at least `TET_WIDTH * TET_HEIGHT` members.
 * `out` is assumed to point to data of at least `TET_HEIGHT` members; the row pointers shall be outputted here. */
void tetris_init_rows(const u8 *restrict data, const u8 *restrict *restrict out) NONNULL((1, 2));

/* Finds up to 4 filled rows in `rows`, moving succeeding rows down and adding the cleared row on top.
 * It is assumed `rows[0]` is the bottom row and `rows[TET_WIDTH-1]` is the top row.
 * Returns the amount of rows cleared. */
int tetris_clear_rows(u8 *restrict *restrict rows) NONNULL((1));

/* Checks if `tetromino` intersects at (`x`, `y`) in the data within `rows` or is out-of-bounds,
 * returns `1` if it overlaps within `rows`, `2` if it is out-of-bounds, `0` if no intersection is found. */
int tetris_intersect(const u8 *restrict const *restrict rows, u8 tetromino, uint x, uint y) NONNULL((1));

/* Writes the blocks of `tetromino` to `rows` at position `x` and `y`. */
void tetris_place(u8 *restrict *restrict rows, u8 tetromino, uint x, uint y) NONNULL((1));
#endif
