sp24-proj3-g121 / proj3 / src / core / AutograderBuddy.java
AutograderBuddy.java
Raw
package core;

import tileengine.TETile;
import tileengine.Tileset;

import java.io.*;
import java.util.ArrayList;
import java.util.Random;

public class AutograderBuddy {

    /**
     * Simulates a game, but doesn't render anything or call any StdDraw
     * methods. Instead, returns the world that would result if the input string
     * had been typed on the keyboard.
     *
     * Recall that strings ending in ":q" should cause the game to quit and
     * save. To "quit" in this method, save the game to a file, then just return
     * the TETile[][]. Do not call System.exit(0) in this method.
     *
     * @param input the input string to feed to your program
     * @return the 2D TETile[][] representing the state of the world
     */
    private int DEFAULT_WIDTH = 5 * 2 * 3 * 3;
    private int DEFAULT_HEIGHT = (5 * 5 * 2) + 1;
    private TETile[][] autograderBuddyWorld;
    private long realSeed;
    private Random random;

    private int xAvatar;
    private int yAvatar;

    private final double MAX_EMPTY_TILES = 0.58;

    private File savedWorld;

    private int countsOfRandom;


    public static TETile[][] getWorldFromInput(String input) {
        AutograderBuddy auto = new AutograderBuddy();
        return auto.generateWorld(input);
    }

    private TETile[][] generateWorld(String input) {
        autograderBuddyWorld = new TETile[DEFAULT_WIDTH][DEFAULT_HEIGHT];
        StringBuilder seedFromText = new StringBuilder("");
        int index = 0;
        char checkFirst = Character.toUpperCase(input.charAt(0));
        index++;
        if (checkFirst == 'N') {
            for (int i = 1; Character.toUpperCase(input.charAt(i)) != 'S'; i++) {
                index++;
                seedFromText.append(input.charAt(i));
            }
            index++;
            realSeed = Long.valueOf(String.valueOf(seedFromText));
            random = new Random(realSeed);
            autograderBuddyWorld = returnTileWorld();
            spawnAvatar();
        }
        if (checkFirst == 'L') {
            autograderBuddyWorld = loadWorld();
        }
        avatarDisplayer(input, index);
        return autograderBuddyWorld;
    }

    private TETile[][] returnTileWorld() {
        autograderBuddyWorld = new TETile[DEFAULT_WIDTH][DEFAULT_HEIGHT];
        ArrayList<Room> roomList = new ArrayList<>();

        for (int i = 0; i < DEFAULT_WIDTH; i++) {
            for (int j = 0; j < DEFAULT_HEIGHT; j++) {
                autograderBuddyWorld[i][j] = Tileset.NOTHING;
            }
        }
        Room first = createRoomFirst();
        roomList.add(first);
        for (int i = 0; i < (5 * 5 * 4); i++) {
            for (int j = 0; j < (5 * 5 * 4 * 4 * 2); j++) {
                Room randomRoom = createRoom();
                int randomIndex;
                int realIndex = 0;
                if (roomList.size() == 1) {
                    randomIndex = 0;
                } else if (roomList.size() == 2) {
                    randomIndex = 1;
                } else {
                    randomIndex = roomList.size() - 1;
                    realIndex = random.nextInt(roomList.size() - 1);
                    countsOfRandom++;
                }
                if (connectableViaHallways(roomList.get(randomIndex), randomRoom)
                        && connectableViaHallways(roomList.get(realIndex), randomRoom)
                        && roomsAreInProximity(roomList.get(roomList.size() - 1), randomRoom)
                        && tilesToBeUsedAreEmpty(randomRoom.getBottomLeft().getxPos(),
                                randomRoom.getBottomLeft().getyPos(),
                                randomRoom.getBottomRight().getxPos(),
                                randomRoom.getTopLeft().getyPos())) {
                    writeRandomRoomToWorld(randomRoom);
                    connectViaHallways(randomRoom, roomList.get(randomIndex));
                    connectViaHallways(randomRoom, roomList.get(realIndex));
                    roomList.add(randomRoom);
                    break;
                }
            }
        }
        double percentOfEmptyTiles = emptyTilesCount();
        while (percentOfEmptyTiles > MAX_EMPTY_TILES) {
            clearWorld();
            autograderBuddyWorld = returnTileWorld();
            percentOfEmptyTiles = emptyTilesCount();
        }
        return autograderBuddyWorld;
    }

    private void writeRandomRoomToWorld(Room randomRoom) {
        for (int i = randomRoom.getBottomLeft().getxPos(); i < randomRoom.getBottomRight().getxPos(); i++) {
            for (int j = randomRoom.getBottomLeft().getyPos(); j < randomRoom.getTopRight().getyPos(); j++) {
                autograderBuddyWorld[i][j] = Tileset.FLOOR;
            }
        }
        for (int i = randomRoom.getBottomLeft().getxPos(); i <= randomRoom.getBottomRight().getxPos(); i++) {
            autograderBuddyWorld[i][randomRoom.getBottomLeft().getyPos()] = Tileset.WALL;
            autograderBuddyWorld[i][randomRoom.getTopLeft().getyPos()] = Tileset.WALL;
        }
        for (int j = randomRoom.getBottomLeft().getyPos(); j <= randomRoom.getTopLeft().getyPos(); j++) {
            autograderBuddyWorld[randomRoom.getBottomLeft().getxPos()][j] = Tileset.WALL;
            autograderBuddyWorld[randomRoom.getBottomRight().getxPos()][j] = Tileset.WALL;
        }
    }

    private Room createRoomFirst() {
        int minRoomWidth = 6;
        int maxRoomWidth = 6 * 2;
        int minRoomHeight = 6;
        int maxRoomHeight = 6 * 2;
        int roomWidth = random.nextInt(maxRoomWidth - minRoomWidth + 1) + minRoomWidth;
        countsOfRandom++;
        int roomHeight = random.nextInt(maxRoomHeight - minRoomHeight + 1) + minRoomHeight;
        countsOfRandom++;
        ArrayList<Coordinates> retrievedCoordinates = retrieveCoordinates(roomWidth, roomHeight);
        Coordinates topLeft = retrievedCoordinates.get(0);
        Coordinates topRight = retrievedCoordinates.get(1);
        Coordinates bottomLeft = retrievedCoordinates.get(2);
        Coordinates bottomRight = retrievedCoordinates.get(3);

        Room roomFirst = new Room(roomWidth, roomHeight, topLeft, topRight, bottomLeft, bottomRight);

        /* set tiles of room to floors */
        for (int i = roomFirst.getBottomLeft().getxPos(); i <= roomFirst.getBottomRight().getxPos(); i++) {
            for (int j = roomFirst.getBottomLeft().getyPos(); j <= roomFirst.getTopLeft().getyPos(); j++) {
                autograderBuddyWorld[i][j] = Tileset.FLOOR;
            }
        }

        /* set edges of room to walls */
        int yBottom = roomFirst.getBottomLeft().getyPos();
        int yTop = roomFirst.getTopLeft().getyPos();
        for (int i = roomFirst.getBottomLeft().getxPos(); i <= roomFirst.getBottomRight().getxPos(); i++) {
            autograderBuddyWorld[i][yBottom] = Tileset.WALL;
            autograderBuddyWorld[i][yTop] = Tileset.WALL;
        }

        int xLeft = roomFirst.getBottomLeft().getxPos();
        int xRight = roomFirst.getBottomRight().getxPos();
        for (int j = roomFirst.getBottomLeft().getyPos(); j <= roomFirst.getTopLeft().getyPos(); j++) {
            autograderBuddyWorld[xLeft][j] = Tileset.WALL;
            autograderBuddyWorld[xRight][j] = Tileset.WALL;
        }
        return roomFirst;
    }

    private ArrayList<Coordinates> retrieveCoordinates(int widthOfRoom, int heightOfRoom) {
        ArrayList<Coordinates> coordinatesArrayList = new ArrayList<>();
        Coordinates topLeft;
        Coordinates topRight;
        Coordinates bottomLeft;
        Coordinates bottomRight;
        int randomPlace = random.nextInt(4);
        countsOfRandom++;
        /* room goes to any of the following positions p0, p1, p2, or p3
        p2            p3


        p0            p1
        */
        if (randomPlace == 0) {
            bottomLeft = new Coordinates(1, 1);
            bottomRight = new Coordinates(1 + widthOfRoom, 1);
            topLeft = new Coordinates(1, 1 + heightOfRoom);
            topRight = new Coordinates(1 + widthOfRoom, 1 + heightOfRoom);
        } else if (randomPlace == 1) {
            bottomLeft = new Coordinates(DEFAULT_WIDTH - widthOfRoom - 1, 1);
            bottomRight = new Coordinates(DEFAULT_WIDTH - 1, 1);
            topLeft = new Coordinates(DEFAULT_WIDTH - widthOfRoom - 1, 1 + heightOfRoom);
            topRight = new Coordinates(DEFAULT_WIDTH - 1, 1 + heightOfRoom);
        } else if (randomPlace == 2) {
            bottomLeft = new Coordinates(1, DEFAULT_HEIGHT - heightOfRoom - 1);
            bottomRight = new Coordinates(1 + widthOfRoom, DEFAULT_HEIGHT - widthOfRoom - 1);
            topLeft = new Coordinates(1, DEFAULT_HEIGHT - 1);
            topRight = new Coordinates(1 + widthOfRoom, DEFAULT_HEIGHT - 1);
        } else {
            bottomLeft = new Coordinates(DEFAULT_WIDTH - widthOfRoom - 1, DEFAULT_HEIGHT - heightOfRoom - 1);
            bottomRight = new Coordinates(DEFAULT_WIDTH - 1, DEFAULT_HEIGHT - heightOfRoom - 1);
            topLeft = new Coordinates(DEFAULT_WIDTH - widthOfRoom - 1, DEFAULT_HEIGHT - 1);
            topRight = new Coordinates(DEFAULT_WIDTH - 1, DEFAULT_HEIGHT - 1);
        }
        coordinatesArrayList.add(topLeft);
        coordinatesArrayList.add(topRight);
        coordinatesArrayList.add(bottomLeft);
        coordinatesArrayList.add(bottomRight);
        return coordinatesArrayList;
    }

    private Room createRoom() {
        int minRoomWidth = 6;
        int maxRoomWidth = 6 * 2;
        int minRoomHeight = 6;
        int maxRoomHeight = 6 * 2;
        int roomWidth = random.nextInt(maxRoomWidth - minRoomWidth + 1) + minRoomWidth;
        countsOfRandom++;
        int roomHeight = random.nextInt(maxRoomHeight - minRoomHeight + 1) + minRoomHeight;
        countsOfRandom++;

        int xBottomLeft = 0;
        int yBottomLeft = 0;
        while (xBottomLeft < 1 || xBottomLeft >= DEFAULT_WIDTH - roomWidth - 1) {
            xBottomLeft = random.nextInt(DEFAULT_WIDTH - roomWidth - 1);
            countsOfRandom++;
        }
        while (yBottomLeft < 1 || yBottomLeft >= DEFAULT_HEIGHT - roomHeight - 1) {
            yBottomLeft = random.nextInt(DEFAULT_WIDTH - roomWidth - 1);
            countsOfRandom++;
        }
        int xTopLeft = xBottomLeft;
        int yBottomRight = yBottomLeft;
        int xBottomRight = xBottomLeft + roomWidth;
        int xTopRight = xBottomRight;
        int yTopLeft = yBottomLeft + roomHeight;
        int yTopRight = yTopLeft;
        Coordinates topLeft = new Coordinates(xTopLeft, yTopLeft);
        Coordinates topRight = new Coordinates(xTopRight, yTopRight);
        Coordinates bottomLeft = new Coordinates(xBottomLeft, yBottomLeft);
        Coordinates bottomRight = new Coordinates(xBottomRight, yBottomRight);

        Room newRoom = new Room(roomWidth, roomHeight, topLeft, topRight, bottomLeft, bottomRight);
        return newRoom;
    }

    private boolean tilesToBeUsedAreEmpty(int xBLeft, int yBLeft, int xBRight, int yTLeft) {
        for (int i = xBLeft - 1; i <= xBRight + 1; i++) {
            for (int j = yBLeft - 1; j <= yTLeft + 1; j++) {
                if (autograderBuddyWorld[i][j] != Tileset.NOTHING) {
                    return false;
                }
            }
        }
        return true;
    }

    private boolean connectableViaHallways(Room r1, Room r2) {
        Coordinates r1Center = new Coordinates(getCenterX(r1), getCenterY(r1));
        Coordinates r2Center = new Coordinates(getCenterX(r2), getCenterY(r2));
        int pathLengthX = Math.abs(r1Center.getxPos() - r2Center.getxPos());
        int pathLengthY = Math.abs(r1Center.getyPos() - r2Center.getyPos());
        Room begin = findBegin(r1, r2).get(0);
        Room end = findBegin(r1, r2).get(1);

        if (pathLengthY != 0 && pathLengthX != 0) {
            if (getCenterY(end) < getCenterY(begin)) {
                for (int x = getCenterX(begin) + begin.getWidth() / 2 + 1; x < getCenterX(end); x++) {
                    if (autograderBuddyWorld[x][getCenterY(begin)] != Tileset.NOTHING
                            || autograderBuddyWorld[x][getCenterY(begin) - 1] != Tileset.NOTHING
                            || autograderBuddyWorld[x][getCenterY(begin) + 1] != Tileset.NOTHING) {
                        return false;
                    }
                }
                for (int y = getCenterY(begin); y <= getCenterY(end) - end.getHeight() / 2 - 1; y++) {
                    if (autograderBuddyWorld[getCenterX(begin) - 1][y] != Tileset.NOTHING
                            || autograderBuddyWorld[getCenterX(begin) + 1][y] != Tileset.NOTHING
                            || autograderBuddyWorld[getCenterX(begin)][y] != Tileset.NOTHING) {
                        return false;
                    }
                }
                if (autograderBuddyWorld[getCenterX(end)][getCenterY(begin) - 1] != Tileset.NOTHING) {
                    return false;
                }
                if (autograderBuddyWorld[getCenterX(end) + 1][getCenterY(begin) - 1] != Tileset.NOTHING) {
                    return false;
                }
                return true;
            } else {
                for (int x = getCenterX(begin) + begin.getWidth() / 2 + 1; x < getCenterX(end); x++) {
                    if (autograderBuddyWorld[x][getCenterY(begin)] != Tileset.NOTHING
                            || autograderBuddyWorld[x][getCenterY(begin) - 1] != Tileset.NOTHING
                            || autograderBuddyWorld[x][getCenterY(begin) + 1] != Tileset.NOTHING) {
                        return false;
                    }
                }
                for (int y = getCenterY(end) + end.getHeight() / 2 + 1; y <= getCenterY(begin); y++) {
                    if (autograderBuddyWorld[getCenterX(end) - 1][y] != Tileset.NOTHING
                            || autograderBuddyWorld[getCenterX(end) + 1][y] != Tileset.NOTHING
                            || autograderBuddyWorld[getCenterX(end)][y] != Tileset.NOTHING) {
                        return false;
                    }
                }
                if (autograderBuddyWorld[getCenterX(end)][getCenterY(begin) + 1] != Tileset.NOTHING) {
                    return false;
                }
                if (autograderBuddyWorld[getCenterX(end) + 1][getCenterY(begin) + 1] != Tileset.NOTHING) {
                    return false;
                }
                return true;
            }
        } else if (pathLengthX == 0 && pathLengthY != 0) {
            for (int y = getCenterY(end) + end.getHeight() / 2 + 1;
                 y < getCenterY(begin) - begin.getHeight() / 2; y++) {
                if (autograderBuddyWorld[pathLengthX - 1][y] != Tileset.NOTHING
                        || autograderBuddyWorld[pathLengthX + 1][y] != Tileset.NOTHING
                        || autograderBuddyWorld[pathLengthX][y] != Tileset.NOTHING) {
                    return false;
                }
            }
            return true;
        } else {
            for (int x = getCenterX(begin) + begin.getWidth() / 2 + 1;
                 x < getCenterX(end) - end.getWidth() / 2; x++) {
                if (autograderBuddyWorld[x][getCenterY(end)] != Tileset.NOTHING
                        || autograderBuddyWorld[x][getCenterY(end) - 1] != Tileset.NOTHING
                        || autograderBuddyWorld[x][getCenterY(end) + 1] != Tileset.NOTHING) {
                    return false;
                }
            }
            return true;
        }
    }

    private ArrayList<Room> findBegin(Room r1, Room r2) {
        ArrayList<Room> outputRooms = new ArrayList<>();
        Room begin;
        Room end;
        if (getCenterX(r1) < getCenterX(r2)) {
            begin = r1;
            end = r2;
        } else if (getCenterX(r1) > getCenterX(r2)) {
            begin = r2;
            end = r1;
        } else {
            if (getCenterY(r1) < getCenterY(r2)) {
                begin = r1;
                end = r2;
            } else {
                begin = r2;
                end = r1;
            }
        }
        outputRooms.add(begin);
        outputRooms.add(end);
        return outputRooms;
    }

    private void connectViaHallways(Room r1, Room r2) {
        Coordinates r1Center = new Coordinates(getCenterX(r1), getCenterY(r1));
        Coordinates r2Center = new Coordinates(getCenterX(r2), getCenterY(r2));
        int pathLengthX = Math.abs(r1Center.getxPos() - r2Center.getxPos());
        int pathLengthY = Math.abs(r1Center.getyPos() - r2Center.getyPos());
        Room begin = findBegin(r1, r2).get(0);
        Room end = findBegin(r1, r2).get(1);
        if (pathLengthX != 0 && pathLengthY != 0) {
            if (getCenterY(end) > getCenterY(begin)) {
                markTileForAutograderBuddy(begin, end);
                markSecondTileForAutograderBuddy(begin, end);

                autograderBuddyWorld[getCenterX(end) - 1][getCenterY(begin)] = Tileset.FLOOR;
                if (autograderBuddyWorld[getCenterX(end) + 1][getCenterY(begin) - 1] != Tileset.FLOOR) {
                    autograderBuddyWorld[getCenterX(end) + 1][getCenterY(begin) - 1] = Tileset.WALL;
                }
                if (autograderBuddyWorld[getCenterX(end)][getCenterY(begin) - 1] != Tileset.FLOOR) {
                    autograderBuddyWorld[getCenterX(end)][getCenterY(begin) - 1] = Tileset.WALL;
                }
            } else {
                for (int x = getCenterX(begin) + begin.getWidth() / 2; x < getCenterX(end); x++) {
                    autograderBuddyWorld[x][getCenterY(begin)] = Tileset.FLOOR;
                    if (autograderBuddyWorld[x][getCenterY(begin) - 1] != Tileset.FLOOR) {
                        autograderBuddyWorld[x][getCenterY(begin) - 1] = Tileset.WALL;
                    }
                    if (autograderBuddyWorld[x][getCenterY(begin) + 1] != Tileset.FLOOR) {
                        autograderBuddyWorld[x][getCenterY(begin) + 1] = Tileset.WALL;
                    }
                }
                for (int y = getCenterY(end) + end.getHeight() / 2; y <= getCenterY(begin); y++) {
                    autograderBuddyWorld[getCenterX(end)][y] = Tileset.FLOOR;
                    if (autograderBuddyWorld[getCenterX(end) - 1][y] != Tileset.FLOOR) {
                        autograderBuddyWorld[getCenterX(end) - 1][y] = Tileset.WALL;
                    }
                    if (autograderBuddyWorld[getCenterX(end) + 1][y] != Tileset.FLOOR) {
                        autograderBuddyWorld[getCenterX(end) + 1][y] = Tileset.WALL;
                    }
                }
                autograderBuddyWorld[getCenterX(end) - 1][getCenterY(begin)] = Tileset.FLOOR;
                if (autograderBuddyWorld[getCenterX(end) + 1][getCenterY(begin) + 1] != Tileset.FLOOR) {
                    autograderBuddyWorld[getCenterX(end) + 1][getCenterY(begin) + 1] = Tileset.WALL;
                }
                if (autograderBuddyWorld[getCenterX(end)][getCenterY(begin) + 1] != Tileset.FLOOR) {
                    autograderBuddyWorld[getCenterX(end)][getCenterY(begin) + 1] = Tileset.WALL;
                }
            }
        } else if (pathLengthX == 0 && pathLengthY != 0) {
            for (int y = getCenterY(end) + end.getHeight() / 2; y <= getCenterY(begin) - begin.getHeight() / 2; y++) {
                autograderBuddyWorld[getCenterX(r1)][y] = Tileset.FLOOR;
                if (autograderBuddyWorld[getCenterX(r1) - 1][y] != Tileset.FLOOR) {
                    autograderBuddyWorld[getCenterX(r1) - 1][y] = Tileset.WALL;
                }
                if (autograderBuddyWorld[getCenterX(r1) + 1][y] != Tileset.FLOOR) {
                    autograderBuddyWorld[getCenterX(r1) + 1][y] = Tileset.WALL;
                }
            }
        } else {
            for (int x = getCenterX(begin) +  begin.getWidth() / 2;
                 x <= getCenterX(end) - end.getWidth() / 2; x++) {
                autograderBuddyWorld[x][getCenterY(r2)] = Tileset.FLOOR;
                if (autograderBuddyWorld[x][getCenterY(r2) - 1] != Tileset.FLOOR) {
                    autograderBuddyWorld[x][getCenterY(r2) - 1] = Tileset.WALL;
                }
                if (autograderBuddyWorld[x][getCenterY(r2) + 1] != Tileset.FLOOR) {
                    autograderBuddyWorld[x][getCenterY(r2) + 1] = Tileset.WALL;
                }
            }
        }
    }

    private void markSecondTileForAutograderBuddy(Room begin, Room end) {
        for (int y = getCenterY(begin); y <= getCenterY(end) - end.getHeight() / 2; y++) {
            autograderBuddyWorld[getCenterX(end)][y] = Tileset.FLOOR;
            if (autograderBuddyWorld[getCenterX(end) - 1][y] != Tileset.FLOOR) {
                autograderBuddyWorld[getCenterX(end) - 1][y] = Tileset.WALL;
            }
            if (autograderBuddyWorld[getCenterX(end) + 1][y] != Tileset.FLOOR) {
                autograderBuddyWorld[getCenterX(end) + 1][y] = Tileset.WALL;
            }
        }
    }

    private void markTileForAutograderBuddy(Room begin, Room end) {
        for (int x = getCenterX(begin) + begin.getWidth() / 2; x < getCenterX(end); x++) {
            autograderBuddyWorld[x][getCenterY(begin)] = Tileset.FLOOR;
            if (autograderBuddyWorld[x][getCenterY(begin) - 1] != Tileset.FLOOR) {
                autograderBuddyWorld[x][getCenterY(begin) - 1] = Tileset.WALL;
            }
            if (autograderBuddyWorld[x][getCenterY(begin) + 1] != Tileset.FLOOR) {
                autograderBuddyWorld[x][getCenterY(begin) + 1] = Tileset.WALL;
            }
        }
    }

    private boolean roomsAreInProximity(Room r1, Room r2) {
        int r1CenterX = getCenterX(r1);
        int r1CenterY = getCenterY(r1);

        int r2CenterX = getCenterX(r2);
        int r2CenterY = getCenterY(r2);

        // @Source CK-12 distance between 2 points formula
        double shortestDistance = Math.sqrt(Math.pow(r2CenterX - r1CenterX, 2) + Math.pow(r2CenterY - r1CenterY, 2));

        return (shortestDistance < (DEFAULT_WIDTH / 6));
    }

    private int getCenterX(Room r) {
        return r.getBottomLeft().getxPos() + (Math.floorDiv(r.getWidth(), 2));
    }

    private int getCenterY(Room r) {
        return r.getBottomLeft().getyPos() + (Math.floorDiv(r.getHeight(), 2));
    }

    private double emptyTilesCount() {
        double emptyTiles = 0;
        double totalTiles = 0;
        for (int i = 0; i < DEFAULT_WIDTH; i++) {
            for (int j = 0; j < DEFAULT_HEIGHT; j++) {
                totalTiles++;
                if (autograderBuddyWorld[i][j] == Tileset.NOTHING) {
                    emptyTiles++;
                }
            }
        }
        return emptyTiles / totalTiles;
    }

    private void clearWorld() {
        for (int i = 0; i < DEFAULT_WIDTH; i++) {
            for (int j = 0; j < DEFAULT_HEIGHT; j++) {
                autograderBuddyWorld[i][j] = Tileset.NOTHING;
            }
        }
    }

    private void spawnAvatar() {
        int x = random.nextInt(DEFAULT_WIDTH - 1);
        countsOfRandom++;
        int y = random.nextInt(DEFAULT_HEIGHT - 1);
        countsOfRandom++;

        while (autograderBuddyWorld[x][y] != Tileset.FLOOR) {
            x = random.nextInt(DEFAULT_WIDTH - 1);
            countsOfRandom++;
            y = random.nextInt(DEFAULT_HEIGHT - 1);
            countsOfRandom++;
        }
        xAvatar = x;
        yAvatar = y;

        autograderBuddyWorld[x][y] = Tileset.AVATAR;
    }

    private void avatarDisplayer(String input, int index) {
        int i = index - 1;
        while (i < input.length() - 1) {
            i++;
            char c = input.charAt(i);
            char capitalizedC = Character.toUpperCase(c);
            if (capitalizedC == 'W') {
                moveForward(xAvatar, yAvatar);
            }
            if (capitalizedC == 'A') {
                moveLeft(xAvatar, yAvatar);
            }
            if (capitalizedC == 'S') {
                moveBack(xAvatar, yAvatar);
            }
            if (capitalizedC == 'D') {
                moveRight(xAvatar, yAvatar);
            }
            if (capitalizedC == ':') {
                i++;
                c = input.charAt(i);
                capitalizedC = Character.toUpperCase(c);
                if (capitalizedC == 'Q') {
                    saveWorld();
                } else {
                    if (capitalizedC == 'W') {
                        moveForward(xAvatar, yAvatar);
                    }
                    if (capitalizedC == 'A') {
                        moveLeft(xAvatar, yAvatar);
                    }
                    if (capitalizedC == 'S') {
                        moveBack(xAvatar, yAvatar);
                    }
                    if (capitalizedC == 'D') {
                        moveRight(xAvatar, yAvatar);
                    }
                }
            }
        }
    }

    private void saveWorld() {
        savedWorld = new File("save.txt");
        try {
            FileWriter fw = new FileWriter(savedWorld);
            BufferedWriter bw = new BufferedWriter(fw);
            // 0 = WALL, 1 = FLOOR, 2 = AVATAR
            bw.write("" + xAvatar);
            bw.write("\n");
            bw.write("" + yAvatar);
            bw.write("\n");
            bw.write(String.valueOf(realSeed));
            bw.write("\n");
            bw.write(String.valueOf(countsOfRandom));
            bw.write("\n");

            for (int y = DEFAULT_HEIGHT - 1; y >= 0; y--) {
                StringBuilder line = getStringBuilder(y);
                bw.write(String.valueOf(line));
                bw.write("\n");
            }
            bw.close();
        } catch (IOException e) {
            System.err.println("Error saving world");
        }
    }

    private StringBuilder getStringBuilder(int y) {
        StringBuilder line = new StringBuilder();
        for (int x = 0; x < DEFAULT_WIDTH; x++) {
            if (autograderBuddyWorld[x][y] == Tileset.WALL) {
                line.append("0");
            } else if (autograderBuddyWorld[x][y] == Tileset.FLOOR) {
                line.append("1");
            } else if (autograderBuddyWorld[x][y] == Tileset.AVATAR) {
                line.append("2");
            } else {
                line.append("3");
            }
        }
        return line;
    }

    private TETile[][] loadWorld() {
        File worldFile = new File("save.txt");
        if (worldFile.exists()) {
            try {
                FileReader fr = new FileReader(worldFile);
                BufferedReader br = new BufferedReader(fr);
                xAvatar = Integer.parseInt(br.readLine());
                yAvatar = Integer.parseInt(br.readLine());
                realSeed = Long.parseLong(br.readLine());
                countsOfRandom = Integer.parseInt(br.readLine());

                for (int j = DEFAULT_HEIGHT - 1; j >= 0; j--) {
                    String line = br.readLine();

                    for (int i = 0; i < line.length(); i++) {
                        if (line.charAt(i) == '0') {
                            autograderBuddyWorld[i][j] = Tileset.WALL;
                        } else if (line.charAt(i) == '1') {
                            autograderBuddyWorld[i][j] = Tileset.FLOOR;
                        } else if (line.charAt(i) == '2') {
                            autograderBuddyWorld[i][j] = Tileset.AVATAR;
                        } else {
                            autograderBuddyWorld[i][j] = Tileset.NOTHING;
                        }
                    }
                }
                random = new Random(realSeed);
                for (int c = 0; c <= countsOfRandom; c++) {
                    random.nextInt();
                }
                return autograderBuddyWorld;
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return new TETile[0][];
    }

    private void moveForward(int x, int y) {
        if (autograderBuddyWorld[x][y + 1] == Tileset.FLOOR) {
            autograderBuddyWorld[x][y] = Tileset.FLOOR;
            autograderBuddyWorld[x][y + 1] = Tileset.AVATAR;
            yAvatar = y + 1;
        }
    }

    private void moveLeft(int x, int y) {
        if (autograderBuddyWorld[x - 1][y] == Tileset.FLOOR) {
            autograderBuddyWorld[x][y] = Tileset.FLOOR;
            autograderBuddyWorld[x - 1][y] = Tileset.AVATAR;
            xAvatar = x - 1;
        }
    }

    private void moveBack(int x, int y) {
        if (autograderBuddyWorld[x][y - 1] == Tileset.FLOOR) {
            autograderBuddyWorld[x][y] = Tileset.FLOOR;
            autograderBuddyWorld[x][y - 1] = Tileset.AVATAR;
            yAvatar = y - 1;
        }
    }

    private void moveRight(int x, int y) {
        if (autograderBuddyWorld[x + 1][y] == Tileset.FLOOR) {
            autograderBuddyWorld[x][y] = Tileset.FLOOR;
            autograderBuddyWorld[x + 1][y] = Tileset.AVATAR;
            xAvatar = x + 1;
        }
    }

    /**
     * Used to tell the autograder which tiles are the floor/ground (including
     * any lights/items resting on the ground). Change this
     * method if you add additional tiles.
     */
    public static boolean isGroundTile(TETile t) {
        return t.character() == Tileset.FLOOR.character()
                || t.character() == Tileset.AVATAR.character()
                || t.character() == Tileset.FLOWER.character();
    }

    /**
     * Used to tell the autograder while tiles are the walls/boundaries. Change
     * this method if you add additional tiles.
     */
    public static boolean isBoundaryTile(TETile t) {
        return t.character() == Tileset.WALL.character()
                || t.character() == Tileset.LOCKED_DOOR.character()
                || t.character() == Tileset.UNLOCKED_DOOR.character();
    }
}