private static bool TryApplyInstruction(ref SimpleBoard board, Piece piece, Instruction inst, out Piece result, NativeArray <int4x4> pieceShapes) { switch (inst) { case Left: result = piece.WithOffset(-1, 0); return(!board.CollidesFast(result, pieceShapes)); case Right: result = piece.WithOffset(1, 0); return(!board.CollidesFast(result, pieceShapes)); case Cw: var t = SRSNoAlloc.TryRotate(piece, ref board, true, pieceShapes, out var r1, out var r1Result); result = piece.kind == T?r1Result.WithTSpinStatus(board.CheckTSpin(r1Result, r1)) : r1Result; return(t); case Ccw: var s = SRSNoAlloc.TryRotate(piece, ref board, false, pieceShapes, out var r2, out var r2Result); result = piece.kind == T?r2Result.WithTSpinStatus(board.CheckTSpin(r2Result, r2)) : r2Result; return(s); case SonicDrop: var originY = piece.y; result = board.SonicDropFast(piece, pieceShapes); return(originY != result.y); default: throw new ArgumentOutOfRangeException(nameof(inst), inst, null); } }
private static void Attempt(ref SimpleBoard board, Move move, ref NativeHashMap <Piece, bool> alreadyPassed, ref NativePriorityQueue <Move> checkQueue, Instruction instruction, int maxBoardHeight, NativeArray <int4x4> pieceShapes, bool repeat = false) { if (repeat && !(instruction == Left || instruction == Right)) { throw new ArgumentException(); } var piece = move.piece; if (!TryApplyInstruction(ref board, piece, instruction, out var result, pieceShapes)) { return; } piece = result; var t = 0; if (instruction == SonicDrop) { t += 2 * move.piece.y - result.y; } else { t = 1; } if (move.length != 0 && move.GetInstructionAt(move.length - 1) == instruction) { t += 1; } move.Append(instruction, t, result); while (repeat && !move.IsFull && TryApplyInstruction(ref board, piece, instruction, out result, pieceShapes)) { piece = result; move.Append(instruction, 2, result); } if (result.tSpin != TSpinStatus.None || !IsAboveStacking(result, maxBoardHeight)) { // We should do further checks if (alreadyPassed.TryAdd(result, true) && !move.IsFull) { var dropped = board.SonicDropFast(piece, pieceShapes); if (piece.y != dropped.y) { move.Append(SonicDrop, (piece.y - dropped.y) * 2, dropped); } checkQueue.Enqueue(move); } } }
public static NativeHashMap <Piece, Move> Generate(ref SimpleBoard board, Piece spawned, NativeArray <int4x4> pieceShapes, bool holdUse) { var columns = stackalloc int[10]; var maxHeights = stackalloc byte[10]; board.GetColumns(columns, maxHeights); var lookup = new NativeHashMap <Piece, Move>(200, Allocator.Temp); var passed = new NativeHashMap <Piece, bool>(200, Allocator.Temp); var checkQueue = new NativePriorityQueue <Move>(false, 100, Allocator.Temp); var maxHeight = 0; for (var i = 0; i < 10; i++) { if (maxHeights[i] > maxHeight) { maxHeight = maxHeights[i]; } } if (maxHeight < 16) { var starts = GenerateStarts(spawned.kind, holdUse); for (var i = 0; i < starts.Length; i++) { var start = starts[i]; var originY = start.piece.y; var piece = board.SonicDropFast(start.piece, pieceShapes); start.piece = piece; Confirm(ref board, ref lookup, start, pieceShapes); var m2 = start; var dY = originY - piece.y; m2.instructions[m2.length++] = (byte)SonicDrop; m2.time += dY * 2; checkQueue.Enqueue(m2); } starts.Dispose(); } else { var p = new Piece(spawned.kind); var d = board.SonicDropFast(p, pieceShapes); var m = new Move(); m.hold = holdUse; m.piece = d; m.instructions[0] = (byte)SonicDrop; m.length = 1; m.time = 2 * (p.y - d.y); checkQueue.Enqueue(m); } while (checkQueue.TryDequeue(out var mv)) { if (!mv.IsFull) { Attempt(ref board, mv, ref passed, ref checkQueue, Left, maxHeight, pieceShapes); Attempt(ref board, mv, ref passed, ref checkQueue, Right, maxHeight, pieceShapes); if (mv.piece.kind != O) { Attempt(ref board, mv, ref passed, ref checkQueue, Cw, maxHeight, pieceShapes); Attempt(ref board, mv, ref passed, ref checkQueue, Ccw, maxHeight, pieceShapes); } Attempt(ref board, mv, ref passed, ref checkQueue, Left, maxHeight, pieceShapes, true); Attempt(ref board, mv, ref passed, ref checkQueue, Right, maxHeight, pieceShapes, true); Attempt(ref board, mv, ref passed, ref checkQueue, SonicDrop, maxHeight, pieceShapes); } //Finally add this placement(harddropped) to return array var pl = board.SonicDropFast(mv.piece, pieceShapes); var mHard = mv; mHard.piece = pl; Confirm(ref board, ref lookup, mHard, pieceShapes); } passed.Dispose(); checkQueue.Dispose(); return(lookup); }