import java.io.File; import java.util.Scanner; /** * @author: ______your name here (SID)_________ * * For the instruction of the assignment please refer to the assignment * GitHub. * * Plagiarism is a serious offense and can be easily detected. Please * don't share your code to your classmate even if they are threatening * you with your friendship. If they don't have the ability to work on * something that can compile, they would not be able to change your * code to a state that we can't detect the act of plagiarism. For the * first commit of plagiarism, regardless you shared your code or * copied code from others, you will receive 0 with an addition of 5 * mark penalty. If you commit plagiarism twice, your case will be * presented in the exam board and you will receive a F directly. * * Terms about generative AI: * You are not allowed to use any generative AI in this assignment. * The reason is straight forward. If you use generative AI, you are * unable to practice your coding skills. We would like you to get * familiar with the syntax and the logic of the Java programming. * We will examine your code using detection software as well as * inspecting your code with our eyes. Using generative AI tool * may fail your assignment. * * If you cannot work out the logic of the assignment, simply contact * us on Discord. The teaching team is more the eager to provide * you help. We can extend your submission due if it is really * necessary. Just please, don't give up. */ public class l { /** * The following constants are variables that you can use in your code. * Use them whenever possible. Try to avoid writing something like: * if (input == 'W') ... * instead * if (input == UP) ... */ public static final char a = 'W'; public static final char b = 'S'; public static final char c = 'A'; public static final char d = 'D'; public static final char e = 'o'; public static final char f = '@'; public static final char g = '#'; public static final char h = '.'; public static final char i = '%'; /** * Finished. You are not allowed to touch this method. * The main method. */ public static void main(String[] arrstring) { new l().a(); } /** * All coding of this method has been finished. * You are not supposed to add or change any code in this method. * However, you are required to add comments after every // to explain the code below. */ public void a() { String string = "map1.txt"; char[][] arrc = this.b(string); char[][] arrc2 = this.b(string); if (arrc == null) { System.out.println("Map file not found"); return; } int[] arrn = this.b(arrc); if (arrn.length == 0) { System.out.println("Player not found"); return; } int n2 = arrn[0]; int n3 = arrn[1]; while (!this.a(arrc)) { this.c(arrc); System.out.println("\nPlease enter a move (WASD): "); char c2 = this.c(); if (c2 == 'q') break; if (c2 == 'r') { arrc = this.b(string); n2 = arrn[0]; n3 = arrn[1]; continue; } if (c2 == 'h') { this.b(); } if (!this.c(arrc, n2, n3, c2)) continue; this.b(arrc, n2, n3, c2); this.a(arrc, arrc2); int[] arrn2 = this.b(arrc); n2 = arrn2[0]; n3 = arrn2[1]; } System.out.println("Bye!"); } /** * Print the Help menu. * TODO: * * Inspect the code in runApp() and find out the function of each characters. * The first one has been done for you. */ public void b() { System.out.println("Sokoban Help:"); System.out.println("Move up: W"); System.out.println("Move down: S"); System.out.println("Move left: A"); System.out.println("Move right: D"); System.out.println("Restart level: r"); System.out.println("Quit game: q"); System.out.println("Help: h"); } /** * Reading a valid input from the user. * * TODO * * This method will return a character that the user has entered. However, if a user enter an invalid character (e.g. 'x'), * the method should keep prompting the user until a valid character is entered. Noted, there are all together 7 valid characters * which you need to figure out yourself. */ public char c() { char c2; Scanner scanner = new Scanner(System.in); while (true) { String string; if ((string = scanner.nextLine()).length() == 0) { continue; } c2 = string.charAt(0); if (c2 == 'W' || c2 == 'S' || c2 == 'A' || c2 == 'D' || c2 == 'q' || c2 == 'r' || c2 == 'h') break; System.out.println("Invalid input, please enter again: "); } return c2; } /** * Mysterious method. * * TODO * * We know this method is to "fix" the map. But we don't know how it does and why it is needed. * You need to figure out the function of this method and implement it accordingly. * * You are given an additional demo program that does not implement this method. * You can run them to see the difference between the two demo programs. */ // public void fixMap(_________________________) { // } public void a(char[][] arrc, char[][] arrc2) { for (int i2 = 0; i2 < arrc.length; ++i2) { for (int i3 = 0; i3 < arrc[i2].length; ++i3) { if (arrc2[i2][i3] != '.' && arrc2[i2][i3] != '%' || arrc[i2][i3] != ' ') continue; arrc[i2][i3] = 46; } } } /** * To move a box in a map. * * TODO * * This method will move a box in the map. The box will be moved to the direction specified by the parameter "direction". * You must call this method somewhere in movePlayer() method. * * After this method, a box should be moved to the new position from the coordinate [row, col] according to the direction. * For example, if [row, col] is [2, 5] and the direction is 'S', the box should be moved to [3, 5]. * * If a box is moved to a goal, the box should be marked as BOXONGOAL. * If a box is moved to a non-goal, the box should be marked as BOX. * You should set the original position of the box to ' ' in this method. * * Note, you may always assume that this method is called when the box can be moved to the direction. * During grading, we will never call this method when the box cannot be moved to the direction. */ public void a(char[][] arrc, int n2, int n3, char c2) { int n4; int[] arrn = this.a(n2, n3, c2); int n5 = arrn[0]; arrc[n5][n4] = arrc[n5][n4 = arrn[1]] == '.' ? 37 : 64; arrc[n2][n3] = arrc[n2][n3] == '%' ? 46 : 32; } /** * To move the player in the map. * * TODO * * This method will move the player in the map. The player will be moved to the direction specified by the parameter "direction". * * After this method, the player should be moved to the new position from the coordinate [row, col] according to the direction. * At the same time, the original position of the player should be set to ' '. * * During the move of the player, it is also possible that a box is also moved. * * Note, you may always assume that this method is called when the player can be moved to the direction. * During grading, we will never call this method when the player cannot be moved to the direction. */ public void b(char[][] arrc, int n2, int n3, char c2) { int n4; int[] arrn = this.a(n2, n3, c2); int n5 = arrn[0]; if (arrc[n5][n4 = arrn[1]] == '@' || arrc[n5][n4] == '%') { this.a(arrc, n5, n4, c2); } arrc[n5][n4] = 111; arrc[n2][n3] = 32; } /** * To check if the game is over. * * TODO * * This method should return true if the game is over, false otherwise. * The condition for game over is that there is no goal left in the map that is not covered by a box. * * According to this definition, if the number of goal is actually more than the number of boxes, * the game will never end even through all boxes are placed on the goals. */ public boolean a(char[][] arrc) { for (int i2 = 0; i2 < arrc.length; ++i2) { for (int i3 = 0; i3 < arrc[i2].length; ++i3) { if (arrc[i2][i3] != '.') continue; return false; } } return true; } /** * To count the number of rows in a file. * * TODO * * This method should return the number of rows in the file which filename is stated in the argument. * If the file is not found, it should return -1. */ public int a(String string) { try { Scanner scanner = new Scanner(new File(string)); int n2 = 0; while (scanner.hasNextLine()) { ++n2; scanner.nextLine(); } return n2; } catch (Exception exception) { return -1; } } /** * To read a map from a file. * * TODO * * This method should return a 2D array of characters which represents the map. * This 2D array should be read from the file which filename is stated in the argument. * If the file is not found, it should return null. * * The number of columns in each row may be different. However, there is no restriction on * the number of columns that is declared in the array. You can declare the number of columns * in your array as you wish, as long as it is enough to store the map. * * That is, if the map is as follow, * #### * #.@o# * # # * ### * your array may be declared as * char[][] map = {{'#', '#', '#', '#'}, * {'#', '.', '@', 'o', '#'}, * {'#', ' ', ' ', '#'}, * {'#', '#', '#'} }; * or something like * char[][] map = {{'#', '#', '#', '#', ' ', ' ', ' '}, * {'#', '.', '@', 'o', '#', ' ', ' '}, * {'#', ' ', ' ', '#', ' ', ' ', ' '}, * {'#', '#', '#', ' ', ' ', ' ', ' '} }; */ public char[][] b(String string) { int n2 = this.a(string); if (n2 == -1) { return null; } char[][] arrarrc = new char[n2][]; try (Scanner scanner = new Scanner(new File(string));){ int n3 = 0; while (true) { int n4; String string2; Object object; if (scanner.hasNextLine()) { object = scanner.nextLine(); string2 = ""; } else { object = arrarrc; return object; } for (n4 = ((String)object).length() - 1; n4 >= 0 && ((String)object).charAt(n4) == ' '; --n4) { } for (int i2 = 0; i2 <= n4; ++i2) { string2 = string2 + ((String)object).charAt(i2); } arrarrc[n3] = string2.toCharArray(); ++n3; } } catch (Exception exception) { return null; } } /** * To find the coordinate of player in the map. * * TODO * * This method should return a 2D array that stores the [row, col] of the player in the map. * For example, if the map is as follow, * #### * #.@o# * # # * ### * this method should return {1, 3}. * * In case there is no player in the map, this method should return null. */ public int[] b(char[][] arrc) { for (int i2 = 0; i2 < arrc.length; ++i2) { for (int i3 = 0; i3 < arrc[i2].length; ++i3) { if (arrc[i2][i3] != 'o') continue; int[] arrn = new int[]{i2, i3}; return arrn; } } int[] arrn = new int[]{-1, -1}; return arrn; } /** * To check if a move is valid. * * TODO * * This method should return true if the move is valid, false otherwise. * The parameter "map" represents the map. * The parameter "row" and "col" indicates where the player is. * The parameter "direction" indicates the direction of the move. * At the end of the method, this method should not change any content of the map. * * The physics of the game is as follow: * 1. The player can only move to a position that is not occupied by a wall or a box. * 2. If the player is moving to a position that is occupied by a box, the box can only be moved to a position that is not occupied by a wall or a box. * * Thus, in the following condition, the player can move to the right * o # <-- there is a space * o@ # <-- there is a space right to the box. * In the following condition, the player cannot move to the right * o# <-- there is a wall * o@# <-- there is a wall right to the box. * o@@ # <-- there is a box right to the box. */ public boolean c(char[][] arrc, int n2, int n3, char c2) { return this.a(arrc, n2, n3, c2, true); } /** * To print the map. * * TODO * * This method should print the map in the console. * At the top row, it should print a space followed by the last digit of the column indexes. * At the leftmost column, it should print the last two digits of row indexes, aligning to the left. */ public void c(char[][] arrc) { int n2; if (arrc == null) { return; } int n3 = arrc[0].length; for (n2 = 1; n2 < arrc.length; ++n2) { if (n3 >= arrc[n2].length) continue; n3 = arrc[n2].length; } System.out.print(" "); for (n2 = 0; n2 < n3; ++n2) { System.out.print(n2 % 10); } System.out.println(); for (n2 = 0; n2 < arrc.length; ++n2) { System.out.printf("%-2d", n2 % 100); for (int i2 = 0; i2 < arrc[n2].length; ++i2) { System.out.print(arrc[n2][i2]); } System.out.println(); } } private int[] a(int n2, int n3, int n4) { int[] arrn = new int[]{n2, n3}; switch (n4) { case 87: { arrn[0] = arrn[0] - 1; break; } case 83: { arrn[0] = arrn[0] + 1; break; } case 65: { arrn[1] = arrn[1] - 1; break; } case 68: { arrn[1] = arrn[1] + 1; } } return arrn; } private boolean a(char[][] arrc, int n2, int n3, char c2, boolean bl) { int[] arrn = this.a(n2, n3, c2); int n4 = arrn[0]; int n5 = arrn[1]; if (n4 < 0 || n4 >= arrc.length || n5 < 0 || n5 >= arrc[n4].length) { return false; } if (arrc[n4][n5] == '#') { return false; } if (arrc[n4][n5] == '@' || arrc[n4][n5] == '%') { if (bl) { return this.a(arrc, n4, n5, c2, false); } return false; } return true; } }