// import 'dart:convert'; // import 'dart:developer' as developer; // import 'dart:ffi'; // import 'dart:math'; // import 'package:logging/logging.dart' as logging; // import 'package:vector_math/vector_math_64.dart'; // import 'dart:io'; // import 'tetrio_multiplayer_replay.dart'; // class HandlingHandler{ // double das; // double arr; // late double dasLeft; // frames // late double arrLeft; // frames // bool sdfActive = false; // bool activeLeft = false; // bool activeRight = false; // int direction = 0; // -1 - left, 1 - right, 0 - none // HandlingHandler(this.das, this.arr){ // dasLeft = das; // arrLeft = arr; // } // @override // String toString(){ // return "das: ${das}f; arr: ${arr}f"; // } // int movementKeyPressed(bool left, bool right, double subframe){ // if (left) { // activeLeft = left; // direction = -1; // } // if (right) { // activeRight = right; // direction = 1; // } // dasLeft = das - (1 - subframe); // return direction; // } // void movementKeyReleased(bool left, bool right, double subframe){ // if (left) { // activeLeft = !left; // } // if (right) { // activeRight = !right; // } // if (activeLeft) { // direction = -1; // } // if (activeRight) { // direction = 1; // } // if (activeLeft && activeRight){ // arrLeft = arr; // dasLeft = das; // direction = 0; // } // } // int processMovenent(double delta){ // if (!activeLeft && !activeRight) return 0; // if (dasLeft > 0.0) { // dasLeft -= delta; // if (dasLeft < 0.0) { // arrLeft += dasLeft; // dasLeft = 0.0; // return direction; // }else{ // return 0; // } // }else{ // arrLeft -= delta; // if (arr == 0.0) return direction*10; // if (arrLeft < 0.0) { // arrLeft += arr; // return direction; // }else { // return 0; // } // } // } // } // class Board{ // int width; // int height; // int bufferHeight; // late List> board; // late int totalHeight; // Board(this.width, this.height, this.bufferHeight){ // totalHeight = height+bufferHeight; // board = [for (var i = 0 ; i < totalHeight; i++) [for (var i = 0 ; i < width; i++) Tetromino.empty]]; // } // @override // String toString() { // String result = ""; // for (var row in board.reversed){ // for (var cell in row) result += cell.name[0]; // result += "\n"; // } // return result; // } // bool isOccupied(Coords coords) // { // if (coords.x < 0 || coords.x >= width || // coords.y < 0 || coords.y >= totalHeight || // board[coords.y][coords.x] != Tetromino.empty) return true; // return false; // } // bool positionIsValid(Tetromino type, Coords coords, int r){ // List shape = shapes[type.index][r]; // for (Coords mino in shape){ // if (isOccupied(coords+mino)) return false; // } // return true; // } // bool wasATSpin(Tetromino type, Coords coords, int rot){ // if (!(positionIsValid(type, Coords(coords.x+1, coords.y), rot) || // positionIsValid(type, Coords(coords.x-1, coords.y), rot) || // positionIsValid(type, Coords(coords.x, coords.y+1), rot) || // positionIsValid(type, Coords(coords.x, coords.y-1), rot)) // ){ // return true; // } // return false; // } // void writeToBoard(Tetromino type, Coords coords, int rot) { // if (!positionIsValid(type, coords, rot)) throw Exception("Attempted to write $type to $coords in $rot rot"); // List shape = shapes[type.index][rot]; // for (Coords mino in shape){ // var finalCoords = coords+mino; // board[finalCoords.y][finalCoords.x] = type; // } // } // void writeGarbage(GarbageData data, [int? amt]){ // List> garbage = [for (int i = 0; i < (amt??data.amt!); i++) [for (int k = 0; k < width; k++) k == data.column! ? Tetromino.empty : Tetromino.garbage]]; // board.insertAll(0, garbage); // board.removeRange(height-garbage.length, height); // } // List clearFullLines(){ // int linesCleared = 0; // int garbageLines = 0; // int difficultLineClear = 0; // for (int i = 0; i < board.length; i++){ // if (board[i-linesCleared].every((element) => element != Tetromino.empty)){ // if (board[i-linesCleared].any((element) => element == Tetromino.garbage)) garbageLines++; // board.removeAt(i-linesCleared); // List emptyRow = [for (int t = 0; t < width; t++) Tetromino.empty]; // board.add(emptyRow); // linesCleared += 1; // } // } // if (linesCleared >= 4) difficultLineClear = 1; // return [linesCleared, garbageLines, difficultLineClear]; // } // } // class IncomingGarbage{ // int? frameOfThreat; // will enter board after this frame, null if unconfirmed // GarbageData data; // IncomingGarbage(this.data); // @override // String toString(){ // return "f$frameOfThreat: col${data.column} amt${data.amt}"; // } // void confirm(int confirmationFrame, int garbageSpeed){ // frameOfThreat = confirmationFrame+garbageSpeed; // } // } // class LineClearResult{ // int linesCleared; // Tetromino piece; // bool spin; // int garbageCleared; // int column; // int attackProduced; // LineClearResult(this.linesCleared, this.piece, this.spin, this.garbageCleared, this.column, this.attackProduced); // } // class Stats{ // int combo = -1; // int btb = -1; // int attackRecived = 0; // int attackTanked = 0; // LineClearResult processLineClear(List clearFullLinesResult, Tetromino current, Coords pos, bool spinWasLastMove, bool tspin){ // if (clearFullLinesResult[0] > 0) combo++; // else combo = -1; // if (clearFullLinesResult[2] > 0) btb++; // else btb = -1; // int attack = 0; // switch (clearFullLinesResult[0]){ // case 0: // if (spinWasLastMove && tspin) { // attack = garbage['t-spin']!; // } // break; // case 1: // if (spinWasLastMove && tspin) { // attack = garbage['t-spin single']!; // }else{ // attack = garbage['single']!; // } // break; // case 2: // if (spinWasLastMove && tspin) { // attack = garbage['t-spin double']!; // }else{ // attack = garbage['double']!; // } // break; // case 3: // if (spinWasLastMove && tspin) { // attack = garbage['t-spin triple']!; // }else{ // attack = garbage['triple']!; // } // break; // case 4: // if (spinWasLastMove && tspin) { // attack = garbage['t-spin quad']!; // }else{ // attack = garbage['quad']!; // } // break; // case 5: // if (spinWasLastMove && tspin) { // attack = garbage['t-spin penta']!; // }else{ // attack = garbage['penta']!; // } // break; // case _: // developer.log("${clearFullLinesResult[0]} lines cleared"); // break; // } // return LineClearResult(clearFullLinesResult[0], Tetromino.empty, false, clearFullLinesResult[1], 0, attack); // } // } // class Simulation{ // } // // That thing allows me to test my new staff i'm trying to implement // void main() async { // var replayJson = jsonDecode(File("/home/dan63047/Документы/replays/6550eecf2ffc5604e6224fc5.ttrm").readAsStringSync()); // // frame 994: garbage lost // // frame 1550: T-spin failed // ReplayData replay = ReplayData.fromJson(replayJson); // TetrioRNG rng = TetrioRNG(replay.stats[0][0].seed); // List queue = rng.shuffleList(tetrominoes.toList()); // List events = readEventList(replay.rawJson); // DataFullOptions? settings; // HandlingHandler? handling; // Map activeKeypresses = {}; // int currentFrame = 0; // double subframesWent = 0; // events.removeAt(0); // get rig of Event.start // Event nextEvent = events.removeAt(0); // Stats stats = Stats(); // Board board = Board(10, 20, 20); // KicksetBase kickset = SRSPlus(); // List garbageQueue = []; // Tetromino? hold; // int rot = 0; // bool spinWasLastMove = false; // Coords coords = Coords(3, 21); // double lockDelay = 30; // frames // int lockResets = 15; // bool floored = false; // double gravityBucket = 1.0; // developer.log("Seed is ${replay.stats[0][0].seed}, first bag is $queue"); // Tetromino current = queue.removeAt(0); // //developer.log("Second bag is ${rng.shuffleList(tetrominoes)}"); // int sonicDrop(){ // int height = coords.y; // while (board.positionIsValid(current, Coords(coords.x, height), rot)){ // height -= 1; // } // height += 1; // return height; // } // Tetromino getNewOne(){ // if (queue.length <= 1) { // List nextPieces = rng.shuffleList(tetrominoes.toList()); // queue.addAll(nextPieces); // } // //developer.log("Next queue is $queue"); // rot = 0; // lockResets = 15; // lockDelay = 30; // floored = false; // gravityBucket = 1.0; // return queue.removeAt(0); // } // bool handleRotation(int r){ // if (r == 0) return true; // int futureRotation = (rot + r) % 4; // List tests = (current == Tetromino.I ? kickset.kickTableI : kickset.kickTable)[rot][r == -1 ? 0 : r]; // for (Coords test in tests){ // if (board.positionIsValid(current, coords+test, futureRotation)){ // coords += test; // rot = futureRotation; // return true; // } // } // return false; // } // void handleHardDrop(){ // board.writeToBoard(current, coords, rot); // bool tspin = board.wasATSpin(current, coords, rot); // LineClearResult lineClear = stats.processLineClear(board.clearFullLines(), current, coords, spinWasLastMove, tspin); // print("${lineClear.linesCleared} lines, ${lineClear.garbageCleared} garbage"); // if (garbageQueue.isNotEmpty) { // if (lineClear.linesCleared > 0){ // int garbageToDelete = lineClear.attackProduced; // for (IncomingGarbage garbage in garbageQueue){ // if (garbage.data.amt! >= garbageToDelete) { // garbageToDelete -= garbage.data.amt!; // lineClear.attackProduced = garbageToDelete; // garbage.data.amt = 0; // }else{ // garbage.data.amt = garbage.data.amt! - garbageToDelete; // lineClear.attackProduced = 0; // break; // } // } // }else{ // int needToTake = settings!.garbageCap!; // for (IncomingGarbage garbage in garbageQueue){ // if ((garbage.frameOfThreat??99999999) > currentFrame) break; // if (garbage.data.amt! > needToTake) { // board.writeGarbage(garbage.data, needToTake); // garbage.data.amt = garbage.data.amt! - needToTake; // break; // } else { // board.writeGarbage(garbage.data); // needToTake -= garbage.data.amt!; // garbage.data.amt = 0; // } // } // } // garbageQueue.removeWhere((element) => element.data.amt == 0); // } // current = getNewOne(); // coords = Coords(3, 21) + spawnPositionFixes[current.index]; // } // void handleGravity(double frames){ // if (frames == 0) return; // gravityBucket += settings != null ? (handling!.sdfActive ? max(settings.g! * settings.handling!.sdf, 0.05 * settings.handling!.sdf) : settings.g!) * frames : 0; // int gravityImpact = 0; // if (gravityBucket >= 1.0){ // gravityImpact = gravityBucket.truncate(); // gravityBucket -= gravityBucket.truncate(); // } // while (gravityImpact > 0){ // if (board.positionIsValid(current, Coords(coords.x, coords.y-1), rot)) {coords.y -= 1; floored = false;} // else floored = true; // gravityImpact--; // } // if (floored) lockDelay -= frames; // if (lockDelay <= 0 && floored){ // handleHardDrop(); // } // } // void handleMovement(double frames){ // if (frames == 0 || handling == null) return; // int movement = handling.processMovenent(frames); // while (movement.abs() > 0){ // if (board.positionIsValid(current, Coords(movement.isNegative ? coords.x-1 : coords.x+1, coords.y), rot)) movement.isNegative ? coords.x-- : coords.x++; // movement.isNegative ? movement++ : movement--; // } // } // coords += spawnPositionFixes[current.index]; // for (currentFrame; currentFrame <= replay.roundLengths[0]; currentFrame++){ // handleMovement(1-subframesWent); // handleGravity(1-subframesWent); // subframesWent = 0; // if (settings?.handling?.sdf == 41) coords.y = sonicDrop(); // print("$currentFrame: $current at $coords\n$board"); // //print(stats.combo); // if (currentFrame == nextEvent.frame){ // while (currentFrame == nextEvent.frame){ // print("Processing $nextEvent"); // switch (nextEvent.type){ // case EventType.start: // developer.log("go"); // break; // case EventType.full: // settings = (nextEvent as EventFull).data.options; // handling = HandlingHandler(settings!.handling!.das.toDouble(), settings.handling!.arr.toDouble()); // lockDelay = settings.locktime!.toDouble(); // lockResets = settings.lockresets!; // break; // case EventType.keydown: // nextEvent as EventKeyPress; // double subframesDiff = nextEvent.data.subframe - subframesWent; // subframesWent += subframesDiff; // handleMovement(subframesDiff); // handleGravity(subframesDiff); // //activeKeypresses[nextEvent.data.key] = nextEvent; // switch (nextEvent.data.key){ // case KeyType.rotateCCW: // handleRotation(-1); // break; // case KeyType.rotateCW: // handleRotation(1); // break; // case KeyType.rotate180: // handleRotation(2); // break; // case KeyType.moveLeft: // case KeyType.moveRight: // int pontencialMovement = handling!.movementKeyPressed(nextEvent.data.key == KeyType.moveLeft, nextEvent.data.key == KeyType.moveRight, nextEvent.data.subframe); // if (board.positionIsValid(current, Coords(coords.x+pontencialMovement, coords.y), rot)) coords.x += pontencialMovement; // break; // case KeyType.softDrop: // handling!.sdfActive = true; // break; // case KeyType.hardDrop: // coords.y = sonicDrop(); // handleHardDrop(); // case KeyType.hold: // switch (hold){ // case null: // hold = current; // current = getNewOne(); // break; // case _: // Tetromino temp; // temp = hold; // hold = current; // current = temp; // rot = 0; // lockResets = 15; // lockDelay = 30; // gravityBucket = 1.0; // floored = false; // coords = Coords(3, 21) + spawnPositionFixes[current.index]; // break; // } // break; // case KeyType.chat: // // TODO: Handle this case. // case KeyType.exit: // // TODO: Handle this case. // case KeyType.retry: // // TODO: Handle this case. // default: // developer.log(nextEvent.data.key.name); // } // if (nextEvent.data.key == KeyType.rotateCW && nextEvent.data.key == KeyType.rotateCW && nextEvent.data.key == KeyType.rotateCW){ // spinWasLastMove = true; // }else{ // spinWasLastMove = false; // } // break; // case EventType.keyup: // nextEvent as EventKeyPress; // double subframesDiff = nextEvent.data.subframe - subframesWent; // subframesWent += subframesDiff; // handleMovement(subframesDiff); // handleGravity(subframesDiff); // switch (nextEvent.data.key){ // case KeyType.moveLeft: // case KeyType.moveRight: // handling!.movementKeyReleased(nextEvent.data.key == KeyType.moveLeft, nextEvent.data.key == KeyType.moveRight, nextEvent.data.subframe); // break; // case KeyType.softDrop: // handling?.sdfActive = false; // break; // case KeyType.rotateCCW: // // TODO: Handle this case. // case KeyType.rotateCW: // // TODO: Handle this case. // case KeyType.rotate180: // // TODO: Handle this case. // case KeyType.hardDrop: // // TODO: Handle this case. // case KeyType.hold: // // TODO: Handle this case. // case KeyType.chat: // // TODO: Handle this case. // case KeyType.exit: // // TODO: Handle this case. // case KeyType.retry: // // TODO: Handle this case. // } // activeKeypresses.remove(nextEvent.data.key); // break; // case EventType.end: // currentFrame = replay.roundLengths[0]+1; // break; // case EventType.ige: // nextEvent as EventIGE; // switch (nextEvent.data.data.type){ // case "interaction": // garbageQueue.add(IncomingGarbage((nextEvent.data.data as IGEdataInteraction).data)); // case "interaction_confirm": // GarbageData data = (nextEvent.data.data as IGEdataInteraction).data; // if(data.type != "targeted") garbageQueue.firstWhere((element) => element.data.iid == data.iid).confirm(currentFrame, settings!.garbageSpeed!); // case "allow_targeting": // case "target": // default: // developer.log("Unknown IGE type: ${nextEvent.data.type}", level: 900); // break; // } // // garbage speed counts from interaction comfirm // break; // default: // developer.log("Event wasn't processed: ${nextEvent}", level: 900); // } // try{ // nextEvent = events.removeAt(0); // } // catch (e){ // developer.log(e.toString()); // } // } // //developer.log("Next is: $nextEvent"); // } // } // exit(0); // }