From e98ad869e8246358fde239c9a1fb3f625e068712 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Sat, 3 Feb 2024 14:21:37 -0500 Subject: [PATCH] Added functionality to allow for a board to be generated and check if the board is solvable. --- src/Assignments/A1/Driver.java | 22 +++++ .../A1/managers/BoardGenerator.java | 90 +++++++++++++++++++ src/Assignments/A1/models/Board.java | 30 +++++-- src/Assignments/A1/models/EightPuzzle.java | 5 ++ src/Assignments/A1/models/Piece.java | 26 ++++++ 5 files changed, 168 insertions(+), 5 deletions(-) diff --git a/src/Assignments/A1/Driver.java b/src/Assignments/A1/Driver.java index d22674b..fd23890 100644 --- a/src/Assignments/A1/Driver.java +++ b/src/Assignments/A1/Driver.java @@ -3,6 +3,10 @@ package Assignments.A1; // Potentially will be changed to an UI Implementation with JavaFX if time permits. +import Assignments.A1.managers.BoardGenerator; +import Assignments.A1.models.Board; +import Assignments.A1.models.Piece; + /** * Board will be used to save locations in a 2D array. * @@ -16,6 +20,24 @@ package Assignments.A1; */ public class Driver { + public static void main(String[] args) { + Board board = BoardGenerator.generateBoard(); + System.out.println(board); + System.out.println(BoardGenerator.isSolvable(board)); + Piece[] pieces = new Piece[9]; + pieces[0] = new Piece(0,7); + pieces[1] = null; + pieces[2] = new Piece(2,5); + pieces[3] = new Piece(3,1); + pieces[4] = new Piece(4,2); + pieces[5] = new Piece(5,4); + pieces[6] = new Piece(6,6); + pieces[7] = new Piece(7,3); + pieces[8] = new Piece(8,8); + + board = new Board(pieces); + System.out.println(BoardGenerator.isSolvable(board)); + } } diff --git a/src/Assignments/A1/managers/BoardGenerator.java b/src/Assignments/A1/managers/BoardGenerator.java index 8d9c8d7..e201a75 100644 --- a/src/Assignments/A1/managers/BoardGenerator.java +++ b/src/Assignments/A1/managers/BoardGenerator.java @@ -1,5 +1,95 @@ package Assignments.A1.managers; +import Assignments.A1.models.Board; +import Assignments.A1.models.Piece; + +import java.util.*; + +/** + * This class is used to create and check boards. + * + * @author Jonathan Turner + * @version Spring 2024 + */ public class BoardGenerator { + /** + * Generates a random 8-Puzzle that is always solvable. + * + * @precondition none + * @postcondition none + * + * @return a board that is solvable. + */ + public static Board generateBoard() { + + Integer[] values = {1, 2, 3, 4, 5, 6, 7, 8}; + List random = new ArrayList<>(Arrays.asList(values)); + Collections.shuffle(random); + + Random gen = new Random(); + int spaceLoc = gen.nextInt(9); + Piece[] pieces = new Piece[9]; + for (int curr = 0; curr < values.length; curr++) { + if (curr < spaceLoc) { + pieces[curr] = new Piece(curr,random.get(curr)); + } else { + pieces[curr+1] = new Piece(curr+1,random.get(curr)); + } + } + + // Checks if the board is solveable. + Board generated = new Board(pieces); + if (isSolvable(generated)) { + return generated; + } else { // If not it swaps the last two values (ignoring the space) + if (spaceLoc == 8) { + pieces[7].setLocation(6); + pieces[6].setLocation(7); + } else if (spaceLoc == 7) { + pieces[8].setLocation(6); + pieces[6].setLocation(8); + } else { + pieces[7].setLocation(6); + pieces[6].setLocation(7); + } + generated = new Board(pieces); + } + + // Puzzle is now solvable. + return generated; + } + + /** + * Checks if the board is solvable by checking the number of inversions. + * If the number of inversions is even, it is solvable, if not it is not solvable. + * + * @precondition board != null + * @postcondition none + * + * @param board the board being checked + * @return if the board has even inversion, True + * if not, False + */ + public static boolean isSolvable(Board board) { + if (board == null) { + return false; + } + + // Holds the number of inversions + int inversions = 0; + Piece[] ordered = board.getPiecesInOrder(); + + // Counts the number of inversions + for (int index = 0; index < 8; index++) { + for (int invers = index+1; invers < 8; invers++) { + if (ordered[index].getValue() > ordered[invers].getValue()) { + inversions++; + } + } + } + return (inversions % 2 == 0); + } + + } diff --git a/src/Assignments/A1/models/Board.java b/src/Assignments/A1/models/Board.java index 416c3ce..45902d2 100644 --- a/src/Assignments/A1/models/Board.java +++ b/src/Assignments/A1/models/Board.java @@ -1,6 +1,7 @@ package Assignments.A1.models; import java.util.Arrays; +import java.util.Random; /** * This class keeps track of the current state (whether in permutation or not) of the board. @@ -45,6 +46,21 @@ public class Board { } } + /** + * Constructor used to create a board with a pre-provided piece list. + * + * @precondition pieces == 9 + * @postcondition a board is created with given locations + * + * @param pieces the provided state. + */ + public Board(Piece[] pieces) { + if (pieces.length != 9) { + throw new IllegalArgumentException("The pieces list must be size 9."); + } + this.pieces = pieces; + } + /** * Checks the status of a place on the board. If the location is taken or not. @@ -195,10 +211,10 @@ public class Board { if (this.getClass() != o.getClass()) { return false; } - Board other = (Board) o; - for (int i = 0; i < 9; i++) { - if (this.pieces[i].getValue() != other.pieces[i].getValue() - || this.pieces[i].getLoc() != other.pieces[i].getLoc()) { + Piece[] other = ((Board) o).getPiecesInOrder(); + Piece[] ordered = this.getPiecesInOrder(); + for (int curr = 0; curr < ordered.length; curr++) { + if (ordered[curr] != other[curr]) { return false; } } @@ -213,7 +229,11 @@ public class Board { public String toString() { String result = ""; for (int i = 0; i < 9; i++) { - result += i + " "; + if (pieces[i] == null) { + result += 0 + " "; + } else { + result += pieces[i] + " "; + } if ((i+1) % 3 == 0) { result += "\n"; } diff --git a/src/Assignments/A1/models/EightPuzzle.java b/src/Assignments/A1/models/EightPuzzle.java index fb0b27a..c455ecf 100644 --- a/src/Assignments/A1/models/EightPuzzle.java +++ b/src/Assignments/A1/models/EightPuzzle.java @@ -1,11 +1,16 @@ package Assignments.A1.models; +import java.util.ArrayList; +import java.util.List; + /** * @author Jonathan Turner * @version Spring 2024 */ public class EightPuzzle { + private List boards = new ArrayList<>(); + } diff --git a/src/Assignments/A1/models/Piece.java b/src/Assignments/A1/models/Piece.java index 36df2af..fa7caa8 100644 --- a/src/Assignments/A1/models/Piece.java +++ b/src/Assignments/A1/models/Piece.java @@ -60,6 +60,21 @@ public class Piece { this.setLoc(newLoc); } + /** + * Should only be used when creating the board to set its location. + * + * @precondition location is valid + * @postcondition new location set + * + * @param newLoc the new location + */ + public void setLocation(int newLoc) { + if (invalidLocation(newLoc)) { + throw new IllegalArgumentException("The location should be valid."); + } + this.loc = newLoc; + } + /** * Gets the location of the piece. * @@ -110,6 +125,17 @@ public class Piece { return board.isTaken(desiredLoc); } + /** + * Turns any string call of the class to just its value. + * @precondition none + * @postcondition none + * @return the value of the piece. + */ + @Override + public String toString() { + return String.valueOf(this.value); + } + /* Private Methods Below. End of Java Docs. */ /* Sets the location for both Moving and Initialization. */