270 lines
8.0 KiB
Zig
270 lines
8.0 KiB
Zig
const std = @import("std");
|
|
const Grid = @import("Grid.zig");
|
|
const Piece = @import("Piece.zig");
|
|
|
|
fn checkDrop(grid: Grid, piece: Piece) Piece {
|
|
var new_piece = piece;
|
|
if (moveDown(grid, piece).timer_dropped.started) {
|
|
if (new_piece.timer_dropped.started) {
|
|
new_piece.timer_dropped.reset();
|
|
} else {
|
|
new_piece.timer_dropped.start();
|
|
}
|
|
} else {
|
|
new_piece.timer_dropped.stop();
|
|
}
|
|
return new_piece;
|
|
}
|
|
|
|
pub fn moveRight(grid: Grid, piece: Piece) Piece {
|
|
var new_piece = piece;
|
|
new_piece.col += 1;
|
|
if (checkCollision(grid, new_piece)) {
|
|
return piece;
|
|
} else {
|
|
new_piece = checkDrop(grid, new_piece);
|
|
return new_piece;
|
|
}
|
|
}
|
|
|
|
pub fn moveLeft(grid: Grid, piece: Piece) Piece {
|
|
var new_piece = piece;
|
|
new_piece.col -= 1;
|
|
if (checkCollision(grid, new_piece)) {
|
|
return piece;
|
|
} else {
|
|
new_piece = checkDrop(grid, new_piece);
|
|
return new_piece;
|
|
}
|
|
}
|
|
|
|
pub fn moveDown(grid: Grid, piece: Piece) Piece {
|
|
var new_piece = piece;
|
|
new_piece.row += 1;
|
|
if (checkCollision(grid, new_piece)) {
|
|
new_piece.row -= 1;
|
|
if (!new_piece.timer_dropped.started) {
|
|
new_piece.timer_dropped.start();
|
|
}
|
|
return new_piece;
|
|
} else {
|
|
new_piece.timer_dropped.stop();
|
|
return new_piece;
|
|
}
|
|
}
|
|
|
|
pub fn hardDrop(grid: Grid, piece: Piece) Piece {
|
|
var new_piece = piece;
|
|
while (!new_piece.timer_dropped.started) {
|
|
new_piece = moveDown(grid, new_piece);
|
|
}
|
|
new_piece.dropped = true;
|
|
return new_piece;
|
|
}
|
|
|
|
pub fn drop(grid: Grid, piece: Piece) Grid {
|
|
var new_grid = grid;
|
|
|
|
for (piece.structure) |_, y| {
|
|
for (piece.structure[y]) |_, x| {
|
|
if (piece.structure[y][x]) {
|
|
new_grid.cells[@intCast(usize, piece.row + @intCast(i32, y))][@intCast(usize, piece.col + @intCast(i32, x))].free = false;
|
|
new_grid.cells[@intCast(usize, piece.row + @intCast(i32, y))][@intCast(usize, piece.col + @intCast(i32, x))].color = piece.color;
|
|
}
|
|
}
|
|
}
|
|
|
|
return new_grid;
|
|
}
|
|
|
|
pub fn shadow(grid: Grid, piece: Piece) Piece {
|
|
var new_shadow = hardDrop(grid, piece);
|
|
return new_shadow;
|
|
}
|
|
|
|
fn checkCollision(grid: Grid, piece: Piece) bool {
|
|
for (piece.structure) |_, y| {
|
|
for (piece.structure[y]) |_, x| {
|
|
if (piece.structure[y][x] and
|
|
((@intCast(i32, x) + piece.col > Grid.ncolumns - 1) or
|
|
(@intCast(i32, x) + piece.col < 0) or
|
|
(@intCast(i32, y) + piece.row > Grid.nrows - 1) or
|
|
(@intCast(i32, y) + piece.row < 0) or
|
|
(!grid.cells[@intCast(usize, piece.row + @intCast(i32, y))][@intCast(usize, piece.col + @intCast(i32, x))].free)))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
pub fn rotateLeft(grid: Grid, piece: Piece) Piece {
|
|
var new_piece = piece.rotate(Piece.Rot.left);
|
|
new_piece = kick(grid, new_piece, piece);
|
|
new_piece = checkDrop(grid, new_piece);
|
|
return new_piece;
|
|
}
|
|
|
|
pub fn rotateRight(grid: Grid, piece: Piece) Piece {
|
|
var new_piece = piece.rotate(Piece.Rot.right);
|
|
new_piece = kick(grid, new_piece, piece);
|
|
new_piece = checkDrop(grid, new_piece);
|
|
return new_piece;
|
|
}
|
|
|
|
pub fn kick(grid: Grid, piece: Piece, prev_piece: Piece) Piece {
|
|
// O piece does not rotate
|
|
if (piece.piece_type == Piece.Type.o) return piece;
|
|
// Get the rotation stage for appropiate checks
|
|
const prev_stage = prev_piece.rot_stage;
|
|
const next_stage = piece.rot_stage;
|
|
var new_piece = piece;
|
|
|
|
// Test 1
|
|
if (!checkCollision(grid, new_piece)) {
|
|
// T TWIST DETECTION
|
|
_ = checkTTwist(grid, new_piece);
|
|
return new_piece;
|
|
}
|
|
|
|
var offsets: [4][2]i8 = undefined;
|
|
|
|
if (piece.piece_type == Piece.Type.i) {
|
|
if ((prev_stage == Piece.RotStage.init and
|
|
next_stage == Piece.RotStage.right) or
|
|
(prev_stage == Piece.RotStage.left and
|
|
next_stage == Piece.RotStage.flip))
|
|
{
|
|
offsets = .{ .{ -2, 0 }, .{ 1, 0 }, .{ -2, 1 }, .{ 1, -2 } };
|
|
} else if ((prev_stage == Piece.RotStage.right and
|
|
next_stage == Piece.RotStage.init) or
|
|
(prev_stage == Piece.RotStage.flip and
|
|
next_stage == Piece.RotStage.left))
|
|
{
|
|
offsets = .{ .{ 2, 0 }, .{ -1, 0 }, .{ 2, -1 }, .{ -1, 2 } };
|
|
} else if ((prev_stage == Piece.RotStage.right and
|
|
next_stage == Piece.RotStage.flip) or
|
|
(prev_stage == Piece.RotStage.init and
|
|
next_stage == Piece.RotStage.left))
|
|
{
|
|
offsets = .{ .{ -1, 0 }, .{ 2, 0 }, .{ -1, -2 }, .{ 2, 1 } };
|
|
} else {
|
|
offsets = .{ .{ 1, 0 }, .{ -2, 0 }, .{ 1, 2 }, .{ -2, -1 } };
|
|
}
|
|
} else {
|
|
if ((prev_stage == Piece.RotStage.init and
|
|
next_stage == Piece.RotStage.right) or
|
|
(prev_stage == Piece.RotStage.flip and
|
|
next_stage == Piece.RotStage.right))
|
|
{
|
|
offsets = .{ .{ -1, 0 }, .{ -1, -1 }, .{ 0, 2 }, .{ -1, 2 } };
|
|
} else if ((prev_stage == Piece.RotStage.right and
|
|
next_stage == Piece.RotStage.init) or
|
|
(prev_stage == Piece.RotStage.right and
|
|
next_stage == Piece.RotStage.flip))
|
|
{
|
|
offsets = .{ .{ 1, 0 }, .{ 1, 1 }, .{ 0, -2 }, .{ 1, -2 } };
|
|
} else if ((prev_stage == Piece.RotStage.flip and
|
|
next_stage == Piece.RotStage.left) or
|
|
(prev_stage == Piece.RotStage.init and
|
|
next_stage == Piece.RotStage.left))
|
|
{
|
|
offsets = .{ .{ 1, 0 }, .{ 1, -1 }, .{ 0, 2 }, .{ 1, 2 } };
|
|
} else {
|
|
offsets = .{ .{ -1, 0 }, .{ -1, 1 }, .{ 0, -2 }, .{ -1, -2 } };
|
|
}
|
|
}
|
|
|
|
// Try offsets
|
|
|
|
for (offsets) |offset| {
|
|
new_piece.col += offset[0];
|
|
new_piece.row += offset[1];
|
|
if (!checkCollision(grid, new_piece)) {
|
|
// T TWIST DETECTION
|
|
_ = checkTTwist(grid, new_piece);
|
|
return new_piece;
|
|
}
|
|
new_piece.col -= offset[0];
|
|
new_piece.row -= offset[1];
|
|
}
|
|
|
|
return prev_piece;
|
|
}
|
|
|
|
fn checkTTwist(grid: Grid, piece: Piece) bool {
|
|
if (piece.piece_type == Piece.Type.t) {
|
|
var diagonals: u8 = 0;
|
|
|
|
// [x][-][-]
|
|
// [-][-][-]
|
|
// [-][-][-]
|
|
//
|
|
// [-][-][-]
|
|
// [-][-][-]
|
|
// [x][-][-]
|
|
//
|
|
// [-][-][x]
|
|
// [-][-][-]
|
|
// [-][-][-]
|
|
//
|
|
// [-][-][-]
|
|
// [-][-][-]
|
|
// [-][-][x]
|
|
//
|
|
const rows = [_]i32{ 0, 2, 0, 2 };
|
|
const cols = [_]i32{ 0, 0, 2, 2 };
|
|
for (rows) |_, i| {
|
|
var row = piece.row + rows[i];
|
|
var col = piece.col + cols[i];
|
|
if ((row > 0 and row < Grid.nrows and col > 0 and col < Grid.ncolumns) and
|
|
!grid.cells[@intCast(usize, row)][@intCast(usize, col)].free)
|
|
{
|
|
std.debug.print("Hit\n", .{});
|
|
diagonals += 1;
|
|
}
|
|
}
|
|
if (diagonals > 2) {
|
|
std.debug.print("T-Twist\n", .{});
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
pub fn isToppedOut(grid: Grid) bool {
|
|
|
|
// First check if a cell in the first rows are occupied
|
|
// const row_limit = 5;
|
|
// var i: usize = 0; // Go through rows
|
|
// var j: usize = 0; // Go through columns
|
|
// while(i < row_limit) {
|
|
// while (j < Grid.ncols) {
|
|
// if (!grid.cells[i][j].free) {
|
|
// return true;
|
|
// }
|
|
// }
|
|
// j = 0;
|
|
// }
|
|
|
|
// Must check certain cells (where pieces spawn)
|
|
// rows 20, 21, 22, 23, columns 3, 4, 5, 6
|
|
//
|
|
const cells_to_check = .{
|
|
.{7, 3},.{7, 4},.{7, 5},.{7, 6},
|
|
.{8, 3},.{8, 4},.{8, 5},.{8, 6},
|
|
.{9, 3},.{9, 4},.{9, 5},.{9, 6},
|
|
.{10, 3},.{10, 4},.{10, 5},.{10, 6},
|
|
};
|
|
inline for (cells_to_check) |cell| {
|
|
const row = cell[0];
|
|
const col = cell[1];
|
|
if (!grid.cells[row][col].free) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
|
|
}
|