usg/src/Game/movement.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;
}