From 86dc3b70dbc06f2c49657598f3978c65d752d450 Mon Sep 17 00:00:00 2001 From: Muhab Abubaker <69986855+Muhab2001@users.noreply.github.com> Date: Sun, 12 Jun 2022 00:31:07 +0300 Subject: [PATCH 1/3] Medium level solution my solution for the medium level challenge using dart --- submittions/Muhab2001-69986855 | 131 +++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 submittions/Muhab2001-69986855 diff --git a/submittions/Muhab2001-69986855 b/submittions/Muhab2001-69986855 new file mode 100644 index 0000000..899f3b5 --- /dev/null +++ b/submittions/Muhab2001-69986855 @@ -0,0 +1,131 @@ +class BishopSolver { + /** + * medium mode with dynamio coordinates boundaries + * we will extend all diagonals for both placements + * case 1: if there is no intersection between the two diagonals, not possible + * case 2: there is an intersection and the 2 placements do not appear as an intersection, 2 moves + * case 3: an intersection with one of the 2 placements in the intersection, 1 move + */ + + static List lettersBoundary = []; + static List numbersBoundary = []; + + // utility to generate the boundary + static intializeBoundary(int n, int m) { + for (int i = 1; i <= n; i++) { + numbersBoundary.add(i); + } + var letter = "a"; + for (int i = 0; i < n; i++) { + lettersBoundary.add(shiftLetter(letter, i)); + } + } + + // pathfinder function + static List getBishopPath(int n, int m, String start, String dest) { + intializeBoundary(n, m); + + var startLetter = start[0]; + var startNumber = int.parse(start.substring(1)); + + var endLetter = dest[0]; + var endNumber = int.parse(dest.substring(1)); + + // generate diagonals + var startDiagonals = + generateDiagonals(startLetter, startNumber).union({start}); + var destDiagonals = generateDiagonals(endLetter, endNumber).union({dest}); + // find intersection + final commonElements = startDiagonals.intersection(destDiagonals); + + // case #1 + if (commonElements.isEmpty) { + return []; // cannot be done + } + + // case #3: we check for the starting placements presence in intersection + if (commonElements.contains(start)) { + return [start, dest]; + } + + // case #2 + // sometimes we can have 2 paths, select the first option + return [start, commonElements.first, dest]; + } + + // finding all diagonal positions for a specified position + static Set generateDiagonals( + String letterCoordinate, int numberCoordinate) { + List result = []; + + var letter = letterCoordinate; + var num = numberCoordinate; + // top right diagonal + while (true) { + if (lettersBoundary.contains(shiftLetter(letter, 1)) && + numbersBoundary.contains(num + 1)) { + result.add('${shiftLetter(letter, 1)}${num + 1}'); + } else { + break; + } + + letter = shiftLetter(letter, 1); + num += 1; + } + + letter = letterCoordinate; + num = numberCoordinate; + // top left diagonal + while (true) { + if (lettersBoundary.contains(shiftLetter(letter, -1)) && + numbersBoundary.contains(num + 1)) { + result.add('${shiftLetter(letter, -1)}${num + 1}'); + } else { + break; + } + letter = shiftLetter(letter, -1); + num += 1; + } + + letter = letterCoordinate; + num = numberCoordinate; + // bottom left diagonal + while (true) { + if (lettersBoundary.contains(shiftLetter(letter, -1)) && + numbersBoundary.contains(num - 1)) { + result.add('${shiftLetter(letter, -1)}${num - 1}'); + } else { + break; + } + + letter = shiftLetter(letter, -1); + num -= 1; + } + + letter = letterCoordinate; + num = numberCoordinate; + // bottom right diagonal + while (true) { + if (lettersBoundary.contains(shiftLetter(letter, 1)) && + numbersBoundary.contains(num - 1)) { + result.add('${shiftLetter(letter, 1)}${num - 1}'); + } else { + break; + } + + letter = shiftLetter(letter, 1); + num -= 1; + } + + return result.toSet(); + } + + // utility to shift letter unicode + static shiftLetter(String letter, int num) { + return String.fromCharCode(letter.codeUnitAt(0) + num); + } +} +// runner +void main(List args) { + print(BishopSolver.getBishopPath(18, 18, "a1", "i9").toString()); +} From 40f90541ccfd357873e09964a81f215b3063689c Mon Sep 17 00:00:00 2001 From: Muhab Abubaker <69986855+Muhab2001@users.noreply.github.com> Date: Sun, 12 Jun 2022 00:38:04 +0300 Subject: [PATCH 2/3] fixing extension --- submittions/{Muhab2001-69986855 => Muhab2001-69986855.dart} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename submittions/{Muhab2001-69986855 => Muhab2001-69986855.dart} (100%) diff --git a/submittions/Muhab2001-69986855 b/submittions/Muhab2001-69986855.dart similarity index 100% rename from submittions/Muhab2001-69986855 rename to submittions/Muhab2001-69986855.dart From 9932990161c013248613d33bf02935e198ded4d9 Mon Sep 17 00:00:00 2001 From: Muhab Abubaker <69986855+Muhab2001@users.noreply.github.com> Date: Sat, 18 Jun 2022 10:16:52 +0300 Subject: [PATCH 3/3] edited solution Sorry for the very late submission. I thought someone already solved it and didn't bother to send my corrected code --- submittions/Muhab2001-69986855.dart | 259 +++++++++++++++++----------- 1 file changed, 163 insertions(+), 96 deletions(-) diff --git a/submittions/Muhab2001-69986855.dart b/submittions/Muhab2001-69986855.dart index 899f3b5..a563278 100644 --- a/submittions/Muhab2001-69986855.dart +++ b/submittions/Muhab2001-69986855.dart @@ -1,131 +1,198 @@ +import 'dart:math'; + +// last 4 elements are for alignment detection only +enum Direction { + TOP_RIGHT, + TOP_LEFT, + BOTTOM_RIGHT, + BOTTOM_LEFT, + TOP, + BOTTOM, + RIGHT, + LEFT +} + class BishopSolver { /** - * medium mode with dynamio coordinates boundaries - * we will extend all diagonals for both placements - * case 1: if there is no intersection between the two diagonals, not possible - * case 2: there is an intersection and the 2 placements do not appear as an intersection, 2 moves - * case 3: an intersection with one of the 2 placements in the intersection, 1 move + * medium mode with dynamic coordinates boundaries + * repatedly check for a 2-move finishing move, if not + * make the largest possible leap in the direction of the destination */ - static List lettersBoundary = []; - static List numbersBoundary = []; + static List coulmns = []; + static List rows = []; + // map to define coordinate shift direction for each move on an xy plane + static final Map> shifter = { + Direction.BOTTOM_LEFT: [-1, -1], + Direction.BOTTOM_RIGHT: [1, -1], + Direction.TOP_RIGHT: [1, 1], + Direction.TOP_LEFT: [-1, 1], + }; - // utility to generate the boundary - static intializeBoundary(int n, int m) { - for (int i = 1; i <= n; i++) { - numbersBoundary.add(i); + // pathfinder function + static List getBishopPath(int n, int m, String start, String dest) { + if (start == dest) { + return [start]; } - var letter = "a"; - for (int i = 0; i < n; i++) { - lettersBoundary.add(shiftLetter(letter, i)); + if (n == 1 || m == 1) { + return []; } - } - // pathfinder function - static List getBishopPath(int n, int m, String start, String dest) { - intializeBoundary(n, m); + int maxDimension = max(n, m); + + var startColumn = (start[0].toUpperCase().codeUnitAt(0) - 64); + var startRow = int.parse(start.substring(1)); - var startLetter = start[0]; - var startNumber = int.parse(start.substring(1)); + var destColumn = dest[0].toUpperCase().codeUnitAt(0) - 64; + var destRow = int.parse(dest.substring(1)); + + if (!inBoundary(startColumn.toDouble(), startRow.toDouble(), n, m) || + !inBoundary(destColumn.toDouble(), destRow.toDouble(), n, m)) { + return []; + } - var endLetter = dest[0]; - var endNumber = int.parse(dest.substring(1)); + // check if it is possible to reach the target on a square boundary before moving + // (different colors can never be reached) - // generate diagonals - var startDiagonals = - generateDiagonals(startLetter, startNumber).union({start}); - var destDiagonals = generateDiagonals(endLetter, endNumber).union({dest}); - // find intersection - final commonElements = startDiagonals.intersection(destDiagonals); + var check = isDone( + startColumn, startRow, destColumn, destRow, maxDimension, maxDimension); - // case #1 - if (commonElements.isEmpty) { - return []; // cannot be done + if (check.isEmpty) { + return []; // different colors } + // if n != m check if it is possible to reach after reducing to actual boundary in 1 or 2 moves + var result = [ + [startColumn, startRow] + ]; + var shiftedLocation; + var direction; + check = isDone(startColumn, startRow, destColumn, destRow, n, m); + // looping by leaping in diagonals till you reach a 2-move finisher + while (check.isEmpty) { + direction = getDirection(destColumn - startColumn, destRow - startRow); + if (direction.length == 1) { + shiftedLocation = + generateDiagonal(startColumn, startRow, direction[0], n, m).last; + } else { + var diagonal1 = + generateDiagonal(startColumn, startRow, direction[0], n, m); + var diagonal2 = + generateDiagonal(startColumn, startRow, direction[1], n, m); + // chosing the largest leap for aligned positions + shiftedLocation = + max(diagonal1.length, diagonal2.length) == diagonal1.length + ? diagonal1.last + : diagonal2.last; + } + startColumn = shiftedLocation[0]; + startRow = shiftedLocation[1]; + result.add(shiftedLocation); + check = isDone(startColumn, startRow, destColumn, destRow, n, m); + } + // add the final destination coordinate + check.removeAt(0); + result.addAll(check); + return result + .map((e) => '${String.fromCharCode(e[0] + 64)}${e[1]}') + .toList(); + } - // case #3: we check for the starting placements presence in intersection - if (commonElements.contains(start)) { - return [start, dest]; + static List> isDone( + int startCol, int startRow, int destCol, int destRow, int n, int m) { + // calculating differnece for relative location of both tiles + int colDiff = startCol - destCol; + int rowDiff = startRow - destRow; + // works only for 1 move - finish + if (rowDiff / colDiff == 1 || rowDiff / colDiff == -1) { + return [ + [startCol, startRow], + [destCol, destRow] + ]; } - // case #2 - // sometimes we can have 2 paths, select the first option - return [start, commonElements.first, dest]; - } + var middle_row = (startRow - startCol + destCol + destRow) / 2; - // finding all diagonal positions for a specified position - static Set generateDiagonals( - String letterCoordinate, int numberCoordinate) { - List result = []; + var middle_col = max(startRow - startCol, destCol + destRow) - middle_row; - var letter = letterCoordinate; - var num = numberCoordinate; - // top right diagonal - while (true) { - if (lettersBoundary.contains(shiftLetter(letter, 1)) && - numbersBoundary.contains(num + 1)) { - result.add('${shiftLetter(letter, 1)}${num + 1}'); - } else { - break; - } + if (inBoundary(middle_col, middle_row, n, m)) { + return [ + [startCol, startRow], + [middle_col.toInt(), middle_row.toInt()], + [destCol, destRow] + ]; + } - letter = shiftLetter(letter, 1); - num += 1; + middle_row = (destRow - destCol + startCol + startRow) / 2; + middle_col = max(destRow - destCol, startCol + startRow) - middle_row; + + if (inBoundary(middle_col, middle_row, n, m)) { + return [ + [startCol, startRow], + [middle_col.toInt(), middle_row.toInt()], + [destCol, destRow] + ]; } - letter = letterCoordinate; - num = numberCoordinate; - // top left diagonal - while (true) { - if (lettersBoundary.contains(shiftLetter(letter, -1)) && - numbersBoundary.contains(num + 1)) { - result.add('${shiftLetter(letter, -1)}${num + 1}'); + return []; + } + + static bool inBoundary(double col, double row, int n, int m) { + return (col > 0 && col <= m) && + (row > 0 && row <= n) && + (col.floor() == col) && + (row.floor() == row); + } + + static List getDirection(int collDifference, int rowDifference) { + if (collDifference > 0) { + if (rowDifference > 0) { + return [Direction.TOP_RIGHT]; + } else if (rowDifference < 0) { + return [Direction.BOTTOM_RIGHT]; } else { - break; + return [Direction.TOP_RIGHT, Direction.BOTTOM_RIGHT]; } - letter = shiftLetter(letter, -1); - num += 1; - } - - letter = letterCoordinate; - num = numberCoordinate; - // bottom left diagonal - while (true) { - if (lettersBoundary.contains(shiftLetter(letter, -1)) && - numbersBoundary.contains(num - 1)) { - result.add('${shiftLetter(letter, -1)}${num - 1}'); + } else if (collDifference < 0) { + if (rowDifference > 0) { + return [Direction.TOP_LEFT]; + } else if (rowDifference < 0) { + return [Direction.BOTTOM_LEFT]; } else { - break; + return [Direction.TOP_LEFT, Direction.BOTTOM_LEFT]; + } + } else { + if (rowDifference > 0) { + return [Direction.TOP_RIGHT, Direction.TOP_LEFT]; + } else { + return [Direction.BOTTOM_RIGHT, Direction.BOTTOM_LEFT]; + // impossible for both diffs to be zero at this point } - - letter = shiftLetter(letter, -1); - num -= 1; } + } - letter = letterCoordinate; - num = numberCoordinate; - // bottom right diagonal + // finding all diagonal positions for a specified position + static List> generateDiagonal(int columnCoordinate, + int rowCoordinate, Direction direction, int n, int m) { + List> path = []; // used to choose the largest leap + var col = columnCoordinate; + var row = rowCoordinate; + // a diagonal that is within the boundaries while (true) { - if (lettersBoundary.contains(shiftLetter(letter, 1)) && - numbersBoundary.contains(num - 1)) { - result.add('${shiftLetter(letter, 1)}${num - 1}'); + if ((col + shifter[direction]![0]) <= m && + (col + shifter[direction]![0]) > 0 && + (row + shifter[direction]![1]) <= n && + row + shifter[direction]![1] > 0) { + path.add([col + shifter[direction]![0], row + shifter[direction]![1]]); } else { - break; + return path; } - - letter = shiftLetter(letter, 1); - num -= 1; + col += shifter[direction]![0]; + row += shifter[direction]![1]; } - - return result.toSet(); - } - - // utility to shift letter unicode - static shiftLetter(String letter, int num) { - return String.fromCharCode(letter.codeUnitAt(0) + num); } } -// runner + +// runner void main(List args) { - print(BishopSolver.getBishopPath(18, 18, "a1", "i9").toString()); + print(BishopSolver.getBishopPath(1, 26, "a1", "g1")); }