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; }