Skip to content

Instantly share code, notes, and snippets.

@darkyen
Last active October 23, 2017 12:05
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save darkyen/702c01cd758182d6680a76c32b868165 to your computer and use it in GitHub Desktop.
package towerofhanoi;
import java.awt.Color;
import java.util.Random;
import CS2114.Shape;
/**
* A disc representation
*
* @author Anon
* @version 23.10.2017
*
*/
public class Disc extends Shape implements Comparable<Disc> {
private int size = 0;
// ~ Constructor ...........................................................
/**
* Creates a new Disc of a specified width and a random color
*
* @param width
* the disc's width
*/
public Disc(int width) {
super(0, 0, width, GameWindow.DISC_HEIGHT);
this.size = width;
int [] color = this.randomRGB();
Color randomColor = new Color(color[0], color[1], color[2]);
this.setBackgroundColor(randomColor);
}
// ~ Methods ...............................................................
/**
* Compares this disc to another disc
*
* @param otherDisc
* the other disc
* @return a negative number if this disc is smaller, 0 if they are equal,
* and a positive number if this disc is larger
*/
public int compareTo(Disc otherDisc) throws IllegalArgumentException {
if (otherDisc == null) {
throw new IllegalArgumentException("No disc");
}
return this.size - otherDisc.size;
}
/**
* Compares this disc to another object
*
* @param obj
* the object to compare to
* @return true if both are discs of the same size, false otherwise
*/
public boolean equals(Object obj) {
if (!(obj instanceof Disc)) {
return false;
}
return this.compareTo((Disc)obj) == 0;
}
/**
* Returns the width of this disc as a string
*
* @return the width of the disc as a string
*/
public String toString() {
return (new Integer(this.size)).toString();
}
/**
* Returns a random RGB value
*
* @return a random RGB value
*/
private int[] randomRGB() {
Random random = new Random();
int[] randomRGB = new int[3];
for (int i = 0; i < 3; i++) {
randomRGB[i] = random.nextInt(255);
}
return randomRGB;
}
}
package towerofhanoi;
import java.awt.Color;
import java.util.Observable;
import java.util.Observer;
import CS2114.Button;
import CS2114.Shape;
import CS2114.Window;
import CS2114.WindowSide;
public class GameWindow implements Observer {
private HanoiSolver game;
private Shape left, middle, right;
private Window window;
/**
* The size of the gap between individual discs which are on top of each
* other
*/
protected final int DISC_GAP = 5;
/**
* The thickness of a disc
*/
protected static final int DISC_HEIGHT = 18;
public GameWindow(HanoiSolver game) {
this.game = game;
this.window = new Window("Tower of Hanoi");
int padd = window.getHeight() - window.getGraphPanelHeight();
int width = window.getGraphPanelWidth();
int height = window.getGraphPanelHeight();
int xDist = width / 4;
int yDist = height - (200 + padd);
this.left = new Shape(xDist - 0, yDist, 10, 200, Color.RED);
this.middle = new Shape((xDist * 2) - 5, yDist, 10, 200, Color.RED);
this.right = new Shape((xDist * 3) - 10, yDist, 10, 200, Color.RED);
game.addObserver((Observer)this);
for (int i = game.discs(); i > 0; i--) {
Disc tempDisc = new Disc(((int)Math.pow(i, 1.5) * 7) + 20);
game.getTower(Position.LEFT).push(tempDisc);
this.window.addShape(tempDisc);
this.moveDisc(Position.LEFT);
}
System.out.println();
this.window.addShape(this.left);
this.window.addShape(this.right);
this.window.addShape(this.middle);
Button button = new Button("Solve");
button.onClick(this, "clickedSolve");
this.window.addButton(button, WindowSide.NORTH);
}
public void update(Observable o, Object arg) {
if (arg.getClass().equals(Position.class)) {
Position pos = (Position) arg;
this.moveDisc(pos);
}
this.sleep();
}
public Window getWindow() {
return this.window;
}
public void clickedSolve(Button button) {
button.disable();
new Thread() {
public void run() {
game.solve();
}
}.start();
}
private void moveDisc(Position pos) {
Shape currentPole = null;
Tower currentTower = this.game.getTower(pos);
Disc currentDisc = (Disc)currentTower.peek();
switch (pos) {
case OTHER:
case LEFT:
currentPole = left;
break;
case RIGHT:
currentPole = right;
break;
case MIDDLE:
currentPole = middle;
break;
}
int y = currentPole.getY() + 190;
int x = currentPole.getX() - (currentDisc.getWidth() / 2) + (currentPole.getWidth() / 2);
if (currentTower.size() > 0) {
y -= (currentTower.size() * (DISC_HEIGHT + DISC_GAP));
}
currentDisc.moveTo(x, y);
}
private void sleep() {
try {
Thread.sleep(500);
}
catch (Exception e) {
}
}
}
package towerofhanoi;
import java.util.Observable;
/**
*
* @author Anon
* @version 23.10.2017
*
*/
public class HanoiSolver extends Observable {
// ~ Fields ................................................................
private Tower left, middle, right;
private int numDiscs;
public HanoiSolver(int numDiscs) {
this.numDiscs = numDiscs;
this.left = new Tower(Position.LEFT);
this.right = new Tower(Position.RIGHT);
this.middle = new Tower(Position.MIDDLE);
}
public Tower getTower(Position pos) {
switch(pos) {
default:
case OTHER:
case LEFT:
return this.left;
case RIGHT:
return this.right;
case MIDDLE:
return this.middle;
}
}
public int discs() {
return this.numDiscs;
}
public void solve() {
this.solveTowers(this.discs(), this.left, this.middle, this.right);
}
public String toString() {
return this.left.toString() + this.middle.toString() + this.right.toString();
}
private void solveTowers(int currentDiscs,
Tower startPole,
Tower tempPole,
Tower endPole) {
boolean baseCase = (currentDiscs == 1);
if (baseCase) {
this.move(startPole, endPole);
return;
}
this.solveTowers(currentDiscs - 1, startPole, endPole, tempPole);
this.move(startPole, endPole);
this.solveTowers(currentDiscs - 1, tempPole, startPole, endPole);
}
private void move(Tower source, Tower destination) {
Disc discToMove = (Disc) source.pop();
destination.push(discToMove);
System.out.println(this.toString());
this.setChanged();
notifyObservers(destination.position());
}
}
package towerofhanoi;
import java.util.EmptyStackException;
import stack.StackInterface;
/**
* A linked-stack implementation
*
* @author Anon
* @version 23.10.2017
*
* @param <T> A generic type
*
*/
public class LinkedStack<T> implements StackInterface<T> {
// ~ Fields ................................................................
private Node<T> topNode;
private int size;
// ~ Constructor ...........................................................
/**
* Creates a new empty linked stack
*/
public LinkedStack() {
this.topNode = null;
this.size = 0;
}
// ~ Methods ...............................................................
/**
* Pushes the given entry to the stack
*
* @param newEntry the entry to be pushed
*/
public void push(T newEntry) {
Node<T> newNode = new Node<T>(newEntry);
if (!this.isEmpty()) {
newNode.setNextNode(this.topNode);
}
this.topNode = newNode;
size++;
System.out.println("pushed: " + newEntry.toString());
}
/**
* Pops an entry from the stack
*
* @return the popped entry
* @throws EmptyStackException if the stack is empty before the operation
*/
public T pop() throws EmptyStackException {
if (this.isEmpty()) {
throw new EmptyStackException();
}
Node<T> popped = this.topNode;
this.topNode = popped.getNextNode();
popped.setNextNode(null);
size--;
System.out.println("popped: " + popped.getData().toString());
return popped.getData();
}
/**
* Returns the entry at the top of the stack
*
* @return the entry at the top of the stack
* @throws EmptyStackException if the stack is empty before the operation
*/
public T peek() throws EmptyStackException {
if (this.isEmpty()) {
throw new EmptyStackException();
}
return this.topNode.getData();
}
public int size() {
return this.size;
}
/**
* Checks whethert the stack is empty
*
* @return whether the stack is empty
*/
public boolean isEmpty() {
return (this.size == 0);
}
/**
* Clears the stack of all entries
*/
public void clear() {
this.topNode = null;
this.size = 0;
}
/**
* Returns a string representation of this stack. A stack's string
* representation is written as a comma-separated list of its contents (in
* top-to-bottom order) surrounded by square brackets, such as:
*
* "[lastPush, secondPush, firstPush]"
*
* or "[]" for an empty stack
*
* @return a string representation of the stack
*/
public String toString() {
if (this.isEmpty()) {
return "[]";
}
StringBuilder s = new StringBuilder();
s.append("[");
Node<T> cur = this.topNode;
for (int i = 0; i < this.size - 1; i++) {
s.append(cur.getData().toString() + ", ");
cur = cur.getNextNode();
}
s.append(cur.getData().toString() + "]");
return s.toString();
}
// ~ Nested Classes ........................................................
/**
* A Single Linked Node implementation
*
* @author Lila Pustovoyt (lila)
* @version 23.10.2017
*
* @param <T> a generic type
*
*/
class Node<T> {
// ~ Fields ............................................................
private Node<T> next;
private T data;
// ~ Constructors ......................................................
/**
* Creates a new node with the given data
*
* @param datum the data to be stored in the node
*/
public Node(T datum) {
this.data = datum;
this.next = null;
}
/**
* Creates a new node with the given data and next node reference
*
* @param datum the data to be stored in the node
* @param next the next node reference
*/
public Node(T datum, Node<T> next) {
this.data = datum;
this.next = next;
}
// ~ Methods ...........................................................
/**
* Returns this node's next node reference
*
* @return the next node
*/
public Node<T> getNextNode() {
return this.next;
}
/**
* Returns this node's data
*
* @return the node's data
*/
public T getData() {
return this.data;
}
/**
* Sets this node's next node reference
*
* @param next the next node reference
*/
public void setNextNode(Node<T> next) {
this.next = next;
}
}
}
package towerofhanoi;
public enum Position {
LEFT, RIGHT, MIDDLE, OTHER
}
package towerofhanoi;
public class ProjectRunner {
public static void main(String[] args) {
// TODO Auto-generated method stub
int disks = 5;
if (args.length > 0) {
disks = Integer.parseInt(args[0]);
}
HanoiSolver game = new HanoiSolver(disks);
GameWindow gameWindow = new GameWindow(game);
}
}
package towerofhanoi;
/**
* A representation of the towers on which the discs are stored
*
* @author Anon
* @version 23.10.2017
*
*/
public class Tower extends LinkedStack <Disc>{
// ~ Fields ................................................................
private Position position;
// ~ Constructors ..........................................................
/**
* Creates a new tower at the specified position
*
* @param position the tower's position
*/
public Tower(Position position) {
super();
this.position = position;
}
/**
* Returns this tower's position
*
* @return the tower's position
*/
public Position position() {
return this.position;
}
/**
* Places a disc on the towers
*
* @param disc the disc to be placed
*/
@Override
public void push(Disc disc) throws IllegalStateException,
IllegalArgumentException {
if (disc == null){
throw new IllegalArgumentException("Disc cannnot be null");
}
if (this.size() > 0 && this.peek().compareTo(disc) < 0){
throw new IllegalStateException("Cannot add a bigger disk");
}
super.push(disc);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment