I have this problem: build a tower formed with n colored cubes with given side. There can't be a cube with a small side on a cube with a bigger side and neither can't be two neighbor cubes with the same color. I'm trying to solve it using Ant Colony Optimization. The trouble that I have with it is that I don't know how to choose the next cube to move the ant on and leave pheromone on it.
Example: For the following cubes:
C1 - side = 5, Color = Red
C2 - side = 2, Color = Green
C3 - side = 10, Color = Blue
C4 - side = 1, Color = Red
the solution would be: C3, C1, C2, C4
This is what I've done so far:
Ant class:
public class Ant {
private int[] visited;
private int size;
public Ant(int size) {
this.size = size;
this.visited = new int[size];
}
public void clearVisited(){
for(int i=0; i < size; i++){
visited[i] = -1;
}
}
public void visit(int index, int cube) {
visited[index] = cube;
}
public int visited(int index){
return visited[index];
}
public boolean contains(int cube){
for(int i=0; i < size; i++){
if(visited[i] == cube){
return true;
}
}
return false;
}
}
Cube class:
public class Cube {
private int length;
private String color;
public Cube(int length, String color){
this.length = length;
this.color = color;
}
public Cube(String color){
this.length = (int)Math.round(Math.random() * 200);
this.color = color;
}
public int getLength(){
return this.length;
}
public String getColor(){
return this.color;
}
public void setLength(int length){
this.length = length;
}
public void setColor(String color){
this.color = color;
}
public String toString(){
String str = "";
str += "Cub: l = " + length + ", " + "c = " + color;
return str;
}
public boolean equals(Object o){
if(o == null){
return false;
}
if(!(o instanceof Cube)){
return false;
}
Cube c = (Cube)o;
if((c.getColor().equals(this.getColor())) && (c.getLength() == this.getLength())){
return true;
}
return false;
}
}
Cube Repository class: here I store the cubes
public class CubeRepository {
private static ArrayList<Cube> availableCubes = new ArrayList<Cube>();
public static void addCube(Cube cube){
if(!availableCubes.contains(cube)){
availableCubes.add(cube);
}
}
public static Cube getCube(int index){
return availableCubes.get(index);
}
public static int getSize(){
return availableCubes.size();
}
}
The ACO algorithm:
public class ACO {
private int nrAnts;
private int nrCubes;
private Ant[] ants;
private int currentIndex;
private double[] pheromoneTrail;
private double ph = 1; //pheromon trace on every cube at start
private int alpha = 1;
private int beta = 5;
private int Q = 500;
private double q0 = 0.01;
public ACO(int nrAnts, int nrCubes){
this.nrAnts = nrAnts;
this.nrCubes = nrCubes;
ants = new Ant[nrAnts];
pheromoneTrail = new double[nrCubes];
}
public void createAnts(){//creeaza toate furnicile
currentIndex = 0;
for(int i=0; i < nrAnts; i++){
ants[i] = new Ant(nrCubes);
}
}
public Ant getAnt(int index){//return an ant
return ants[index];
}
public void setupPheromoneTrail(){ //sets pheromone trail for every cube at start
for(int i=0; i < nrCubes; i++){
pheromoneTrail[i] = ph;
}
}
public void placeAnts(){ //place every ant on a cube
for(int i=0; i < nrAnts; i++){
ants[i].visit(currentIndex, (int)(Math.random() * nrCubes));
}
currentIndex++;
}
public int selectNextCube(Ant ant){
if(Math.random() < q0){
int cube = (int)(Math.random() * nrCubes); //pick a random cube
while(!ant.contains(cube)){
if(CubeRepository.getCube(ant.visited(currentIndex-1)).getColor().equals(CubeRepository.getCube(cube).getColor())){
cube = (int)(Math.random() * nrCubes);
}
}
return cube;
}
return 1; //I didn't return a proper value
}
public void MoveAnts(){ //move every ant on another cube
while(currentIndex < nrCubes){
for(int i=0; i < nrAnts; i++){
ants[i].visit(currentIndex, selectNextCube(ants[i]));
}
currentIndex++;
}
}
}
Without having understood the whole program (it's far too much to quickly read it and find an answer): You may select a random cube that has a different color than the previous one with a pseudocode like this
private static final Random random = new Random(0);
public int selectNextCube(Ant ant)
{
Cube previousCube = CubeRepository.getCube(ant.visited(currentIndex-1));
List<Cube> allCubes = obtainAllCubesFromCubeRepository();
List<Cube> sameColor = obtainAllCubesWithSameColorAs(previousCube);
allCubes.removeAll(sameColor);
// EDIT>>>: You might also need this:
allCubes.remove(computeAllCubesAlreadyVisitedBy(ant));
// <<<EDIT: You might also need this:
int index = random.nextInt(allCubes.size());
Cube nextCube = allCubes.get(index);
return indexFor(nextCube);
}
BTW: I'd strongly recomment to not use Math.random(). It returns an unpredictable random value. Debugging a program that involves Math.random() is horrible. Instead, you should use an instance of java.lang.Random, as shown in the above snippet. You may call random.nextDouble() in order to obtain double values like with Math.random(). Additionally, you may call random.nextInt(n) to obtain int values in the range [0,n). The most important thing is: When you create this instance as new Random(0) then it will always return the same sequence of random numbers. This makes the program predictable and makes it possible to really debug the program. (If you want an "unpredictable" random number sequence, you can instantiate it as new Random(), without a random seed).
Related
I am new to coding and trying to call a method (RandomArray) which I wrote and defined in a separate class, but in my driver code I am getting following error message:
Couldn't find symbol- RandomArray().
the code SHOULD create an array (size of which is chosen by the user) and then populate it with random numbers and output the Highest, Lowest, and Average of the numbers in said array.
All spellings match up, and the call itself works and displays no errors, but when using it in the for-loop I get the error message.
This is the class where I created the method:
import java.util.Random;
public class RandomArray
{
//things declared at class level
public int minimun,maximun,adverage, mn, mx, avg;
public String range;
//constucotr for inital numbers
public RandomArray()
{
minimun = 0;
maximun = 1000 + 1;
}
static int RandomArray()
{
Random ran = new Random();
return (ran.nextInt(1000) + 1);
}
//define types
public RandomArray (int mn, int mx, String r, int a)
{
minimun = mn;
maximun = mx;
range = r;
adverage = a;
}
//set minimun
public void setMinimun (int m)
{
minimun = mn;
}
//get minimun
public int getMinimun()
{
return minimun;
}
//set maximun
public void setMaximun(int x)
{
maximun = mx;
}
//get maximun
public int getMaximun()
{
return maximun;
}
//compute adverage
public int adverage(int...array)
{
int adverage = 0;
if (array.length > 0)
{
int sum = 0;
for(int num : array)
sum = sum + num; //add numbers in array
adverage = (int)sum / array.length; //divide numbers in array by the array lenth
}
return adverage;
}
//return values as a string
public String toString()
{
return String.valueOf(getMinimun() + getMaximun() + adverage());
}
}
And this is the driver program that should be populating the array (of users choice) with random numbers and printing the highest, lowest and average:
import java.util.Random;
import java.util.Scanner;
import java.util.Arrays;
public class DemoRandomArray
{
// variable go here
final int minimun = 0;
public static void main(String[] args)
{
final int max = 100;
RandomArray ra = new RandomArray();
int[] anArray = new int[1000];
for(int i=1; i < max; i++)
{
System.out.println(RandomArray());
}
}
}
The method is inside another class, so you need to use the class name.
RandomArray.RandomArray() instead of just RandomArray()
I attempted to follow this pseudocode on wikipedia https://en.wikipedia.org/wiki/Maze_generation_algorithmRandomized_Prim's_algorithm
but my code just generates a full grid. I seem to be missing something in my understanding of what the algorithm does. Can someone help explain what I'm doing wrong?
I've looked at a few sources but I can't wrap my head around it
public class MazeGen {
private int dimension, nodeCounter;
private Node[][] nodes;
private List<Edge> walls;
public static void main(String[] args) {
MazeGen g = new MazeGen(20);
g.generate();
g.printMaze();
}
private void generate() {
pickCell();
generateMaze();
}
private void generateMaze() {
while (!walls.isEmpty()) {
int v;
Edge wall = walls.get(ThreadLocalRandom.current().nextInt(walls.size()));
if ((!wall.nodes[0].visited && wall.nodes[1].visited)
|| (wall.nodes[0].visited && !wall.nodes[1].visited)) {
if (!wall.nodes[0].visited)
v = 0;
else
v = 1;
includeNode(wall.nodes[v]);
wall.nodes[Math.abs(v - 1)].visited = true;
}
walls.remove(wall);
}
}
private void pickCell() {
int i = ThreadLocalRandom.current().nextInt(dimension);
int j = ThreadLocalRandom.current().nextInt(dimension);
includeNode(nodes[i][j]);
}
private void includeNode(Node node) {
node.visited = true;
node.partOfMaze = true;
walls.addAll(node.edges);
}
public void printMaze() {
for (int i = 0; i < dimension; i++) {
System.out.println();
for (int j = 0; j < dimension; j++) {
if (nodes[i][j].partOfMaze) {
System.out.print(".");
} else
System.out.print("p");
}
}
}
public MazeGen(int n) {
nodes = new Node[n][n];
walls = new ArrayList<Edge>();
dimension = n;
createNodes();
connectAdjacents();
}
private void connectAdjacents() {
for (int i = 0; i < dimension; i++) {
for (int j = 0; j < dimension; j++) {
verifyConnection(i, j, i, j + 1);
verifyConnection(i, j, i + 1, j);
}
}
}
private void verifyConnection(int i, int j, int arg1, int arg2) {
if (arg1 < dimension && arg2 < dimension)
connect(i, j, arg1, arg2);
}
private void createNodes() {
for (int i = 0; i < dimension; i++) {
for (int j = 0; j < dimension; j++) {
nodes[i][j] = new Node();
}
}
}
private void connect(int row, int col, int row2, int col2) {
nodes[row][col].edges.add(new Edge(nodes[row][col], nodes[row2][col2]));
nodes[row2][col2].edges.add(new Edge(nodes[row][col], nodes[row2][col2]));
}
private class Node {
boolean visited, partOfMaze;
int number;
List<Edge> edges;
Node() {
number = nodeCounter++;
edges = new ArrayList<Edge>();
}
#Override
public String toString() {
return String.valueOf(number);
}
}
private class Edge {
Node[] nodes;
Edge(Node n, Node n2) {
nodes = new Node[2];
nodes[0] = n;
nodes[1] = n2;
}
#Override
public String toString() {
return nodes[0] + "-" + nodes[1];
}
}
I think that your algorithm is correct but you don't keep the correct output.
All the nodes should be part of the maze. The walls that should be part of the maze are the walls that connect two visited nodes when you proccess them.
make another array of output walls, and set the values in the generateMaze method.
private void generateMaze() {
while (!walls.isEmpty()) {
int v;
Edge wall = walls.get(ThreadLocalRandom.current().nextInt(walls.size()));
if ((!wall.nodes[0].visited && wall.nodes[1].visited)
|| (wall.nodes[0].visited && !wall.nodes[1].visited)) {
if (!wall.nodes[0].visited)
v = 0;
else
v = 1;
includeNode(wall.nodes[v]);
wall.nodes[Math.abs(v - 1)].visited = true;
/////////////////////////////////////
// remove this wall from the output walls
/////////////////////////////////////
} else {
////////////////////////////////
// add this wall to the output walls
////////////////////////////////
}
walls.remove(wall);
}
}
Forget Wikipedia, they censor free speech and manipulate information, especially in political and social areas. For that reason I also deleted all my additions to the Wikipedia page on "maze generation" (see page history).
The idea of "Prim's" MST algorithm is to maintain a "cut" (a set of edges) between disconnected subgraphs and always select the cheapest edge to connect these subgraphs. Visited vertices are marked to avoid generating cycles.
This can be used for maze generation by using edge random weights in a full grid graph or by starting with an empty grid graph and adding randomly weighted edges on the fly.
See my GitHub repository on maze generation for details:
https://github.com/armin-reichert/mazes
https://github.com/armin-reichert/mazes/blob/master/mazes-algorithms/src/main/java/de/amr/maze/alg/mst/PrimMST.java
public void createMaze(int x, int y) {
cut = new PriorityQueue<>();
expand(grid.cell(x, y));
while (!cut.isEmpty()) {
WeightedEdge<Integer> minEdge = cut.poll();
int u = minEdge.either(), v = minEdge.other();
if (isCellUnvisited(u) || isCellUnvisited(v)) {
grid.addEdge(u, v);
expand(isCellUnvisited(u) ? u : v);
}
}
}
private void expand(int cell) {
grid.set(cell, COMPLETED);
grid.neighbors(cell).filter(this::isCellUnvisited).forEach(neighbor -> {
cut.add(new WeightedEdge<>(cell, neighbor, rnd.nextInt()));
});
}
I was attempting to implement Fruchterman and Reingold algorithm in Java, but for some reasons, the coordinate of output vertices sometimes occupy the same coordinates, which is not something this algorithm would want. Where did I go wrong?
Coordinate object (vector)
public class Coordinates {
private float x;
private float y;
public Coordinates(float xx, float yy){
x = xx; y = yy;
}
public float getX() {
return x;
}
public void setX(float x) {
this.x = x;
}
public float getY() {
return y;
}
public void setY(float y) {
this.y = y;
}
public String toString(){
return x+" "+y;
}
public Coordinates subtract(Coordinates c){
return new Coordinates(x-c.x, y - c.y);
}
public Coordinates add(Coordinates c){
return new Coordinates(x + c.x, y + c.y);
}
public Coordinates unit(){
if(length() == 0)
return new Coordinates(0.000001f,0.0000001f);
else
return new Coordinates(x/(float)Math.sqrt(x*x + y*y),y/(float)Math.sqrt(y*y + x*x));
}
public float length(){
return (float)Math.sqrt(x*x + y*y);
}
public float distance(Coordinates c){
return (float) Math.sqrt((x-c.x)*(x-c.x) + (y-c.y)*(y-c.y));
}
public Coordinates scale(float k){
return new Coordinates(k*x,k*y);
}
}
Node object
import java.util.LinkedList;
public class Node {
private LinkedList<Node> incidentList; //has 30 elements for 30 vertices. 1 if incident, 0 if not
private int color;
private Coordinates coord;
private Coordinates disp;
public Coordinates getDisp() {
return disp;
}
public void setDisp(float x, float y) {
disp.setX(x);
disp.setY(y);
}
public void setDisp(Coordinates d) {
disp = d;
}
private int id;
public Node(){
incidentList = new LinkedList<Node>();
color = 0;
coord = new Coordinates(0,0);
disp = new Coordinates(0,0);
id = -1;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public LinkedList<Node> getIncidentList() {
return incidentList;
}
public void addEdge(Node n) {
incidentList.add(n);
}
public void removeEdge(Node n){
incidentList.remove(n);
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
public Coordinates getCoord() {
return coord;
}
public void setCoord(float x, float y) {
coord.setX(x);
coord.setY(y);
}
public int getDegree(){
return incidentList.size();
}
public boolean isAdjacent(Node n){
return incidentList.contains(n);
}
}
Graph object (with layout algorithm function frlayout)
import java.util.ArrayList;
import java.util.Random;
public class MyGraph{
private final int DISRESPECT = -1;
private final int MORECOLOR = -3;
private final float EPSILON = 0.003f;
private ArrayList<Node> graphNodes; //maximum of 30 vertices
private int nVertices = 0;
private int score = 50;
int maxColor = 0;
int[] colorPopulation = new int[15];
double boundx, boundy, C;
public double getBoundx() {
return boundx;
}
public void setBoundx(double boundx) {
this.boundx = boundx;
}
public double getBoundy() {
return boundy;
}
public void setBoundy(double boundy) {
this.boundy = boundy;
}
public double getC() {
return C;
}
public void setC(double c) {
C = c;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public int getnVertices() {
return nVertices;
}
public MyGraph(){
graphNodes = new ArrayList<Node>();
}
public ArrayList<Node> getGraphNodes() {
return graphNodes;
}
//add a new node into the graph
//also set the id of that node
public void addNode(Node n){
graphNodes.add(n);
n.setId(nVertices++);
}
public void addEdge(Node n1, Node n2){
n1.addEdge(n2);
n2.addEdge(n1);
}
//randomly generate a graph with parsity
public void randomGenerating(double parse){ //parse is between 0 and 1
Random gen = new Random(System.currentTimeMillis());
int tempNVertices = 6; //CHANGE HERE TO BECOME A RANDOM NUMBER
for(int i = 0; i< tempNVertices; i++){
Node n = new Node();
float x = 0,y = 0;
while(true){
boolean flag = true;
x = gen.nextFloat();
y = gen.nextFloat();
for(int j = 0; j < i; j++){
if(x*boundx == graphNodes.get(j).getCoord().getX() && y*boundx == graphNodes.get(j).getCoord().getY())
flag = false; break;
}
if (flag)
break;
}
n.setCoord((float)(x*boundx),(float)(y*boundy));
addNode(n);
}
for(int i = 0; i < tempNVertices; i++){
for(int j = i + 1; j < tempNVertices; j++){
if(gen.nextDouble() < parse){
addEdge(graphNodes.get(i),graphNodes.get(j));
}
}
}
}
public void frLayout(){
double w = boundx, h = boundy;
double area = w*h;
double k = C*Math.sqrt(area/nVertices);
double temperature = 1000;
for(int i = 0; i < nVertices; i++)
System.out.println(graphNodes.get(i).getCoord().getX()+" "+graphNodes.get(i).getCoord().getY());
System.out.println("------------------------------");
for(int m = 0; m< 900; m++){
for(int i = 0; i < nVertices; i++){
Node v = graphNodes.get(i);
v.setDisp(0,0);
for(int j = 0; j< nVertices; j++){
Node u = graphNodes.get(j);
if(i!= j){
Coordinates delta = v.getCoord().subtract(u.getCoord());
double myFr = fr(u,v,k);
v.setDisp(v.getDisp().add(delta.unit().scale((float)myFr)));
if(Double.isNaN(v.getDisp().getX())){
System.out.println("PANIC: "+u.getCoord().getX()+" "+u.getCoord().getY()+" "+delta.getX()+" "+v.getCoord().getX());
return;
}
}
}
}
for(int i = 0; i < nVertices; i++){
Node v = graphNodes.get(i);
for(int j = i+1; j< nVertices; j++){
Node u = graphNodes.get(j);
if(v.isAdjacent(u)){
Coordinates delta = v.getCoord().subtract(u.getCoord());
double myFa = fa(u,v,k);
v.setDisp(v.getDisp().subtract(delta.unit().scale((float)myFa)));
u.setDisp(u.getDisp().add(delta.unit().scale((float)myFa)));
}
}
}
for(int i = 0; i< nVertices; i++){
//actually adjusting the nodes
Node v = graphNodes.get(i);
if(i == 0){
System.out.println(v.getCoord().getX()+" "+v.getCoord().getY());
Coordinates disp = v.getDisp().unit().scale((float)Math.min(v.getDisp().length(), temperature));
System.out.println(">>"+disp.getX()+" "+disp.getY());
}
Coordinates newCoord = (v.getCoord().add(v.getDisp().unit().scale((float)Math.min(v.getDisp().length(), temperature))));
v.setCoord(newCoord.getX(), newCoord.getY());
// //prevent from going outside of bound
// float x = (float)Math.min(w, Math.max(0,v.getCoord().getX()));
// float y = (float)Math.min(h, Math.max(0, v.getCoord().getY()));
//
// v.setCoord(x,y);
if(i == 0){
System.out.println(v.getCoord().getX()+" "+v.getCoord().getY());
}
}
temperature *= 0.9;
System.out.println("TEMPERATURE = "+temperature);
}
for(int i = 0; i< nVertices; i++){
Node v = graphNodes.get(i);
System.out.println(v.getCoord().getX()+" "+v.getCoord().getY());;
}
}
private double fa(Node ni, Node nj, double k){
double distance = ni.getCoord().distance(nj.getCoord());
return distance*distance/k;
}
private double fr(Node ni, Node nj, double k){
double distance = ni.getCoord().distance(nj.getCoord());
return k*k/(distance+0.000001);
}
public static void main(String[] args){
MyGraph grph = new MyGraph();
grph.setBoundx(480);
grph.setBoundy(480);
grph.setC(1);
grph.randomGenerating(1);
grph.frLayout();
}
}
Apologies for the overly long question. I tried tutorials on net, but couldn't get anywhere closer to figuring out what's going wrong. Note that when finding unit vector, if a vector is zero (0,0), I make it a very small, non-zero vector so that when two vertices are close to one another, they will repel violently just as the author of the algorithm hoped.
Any instructions would be appreciated.
I found my bug. I was taking square root of the distance twice while computing the attraction and repulsion forces as well as a few other smaller bugs. I posted the corrected code in my question. Hopefully anyone out there attempting this algorithm will find it useful. Note that by removing the boundary, we let the graph free to evolve, it could produce better shape. Once obtaining the resulting graph, we could always translate/scale it so that it fit into whatever dimension required.
I want to find out whether a number passed through a method is part of a randomly generated object (created from a tree map). I've been looking online to find an attribute to the class that can help me find it but have come up short, I've tried HashCodes, Equals(), and this the like... At the moment I have it set up like this and what I'm asking, I guess, is whether I'm using what I read right or wrong?
Here's the code:
public class a {
private final TreeMap<Integer,TreeMap<Integer,Double>> rectangle;
private final int height;
private final int width;
public a(int h, int w) {
this.rectangle = new TreeMap<>();
this.height = h;
this.width = w;
}
public double get(int i, int j) {
if ( i > j ) {
largest = i; // defined earlier
}
for(int a = 0; a < largest; a++) {
if (this.height.equals(a) == i && this.width.equals(a) == j){
int[] position = new int[1];
position[0] = i;
position[1] = j;``
}
else {
return 0.0;
}
}
}
Hi can anyone tell me what im doing wrong here?
i want to check each subgrid for repeated values in a 9by 9 square.
my method works first by creating each subgrid a one dimensional array which can then check each row for each subgrid. and for it to go to each subgrid i provide its coordinates myself.
it checks the first grid 0,0 but does not check other subgrids for repeated values.
can anyone tell me what im doing wrong?
public class SudokuPlayer
{
private int [][] game;
public enum CellState { EMPTY, FIXED, PLAYED };
private CellState[][] gamestate;
private int [][] copy;
private static final int GRID_SIZE=9;
private boolean whichGameToReset;
private int len;
private int stateSize;
private int row;
private int col;
private boolean coordinates(int startX, int startY)
{
row=startX;
col=startY;
if(isBoxValid()==false)
{
return false;
}
return true;
}
public boolean check()
{
if(coordinates(0,0)==false)
{
return false;
}
if(coordinates(0,3)==false)
{
return false;
}
if(coordinates(0,6)==false)
{
return false;
}
if(coordinates(1,0)==false)
{
return false;
}
if( coordinates(1,3)==false)
{
return false;
}
if( coordinates(1,6)==false)
{
return false;
}
if(coordinates(2,0)==false)
{
return false;
}
if(coordinates(2,3)==false)
{
return false;
}
if(coordinates(2,6)==false)
{
return false;
}
return true;
}
private boolean isBoxValid()
{
int[] arrayCopy = new int[game.length];
int currentRow = (row/3)*3;
int currentCol = (col/3)*3;
int i = 0;
for ( int r =currentRow; r < 3; r++)
{
for( int c =currentCol; c < 3; c++)
{
arrayCopy[i] = game[r][c];
i++;
}
}
for ( int p =0; p < arrayCopy.length; p++)
{
for ( int j = p+1; j < arrayCopy.length; j++)
{
if ( arrayCopy[p] == arrayCopy[j] && arrayCopy[j]!=0)
{
return false;
}
}
}
return true;
}
}
The problem is in your isBoxValid() method. You are initializing r and c to be currentRow and currentCol, respectively, but you run the loop up to a hard coded value of 3, not 3+currentRow or 3+currentCol. When currentRow and currentCol are 0, it works fine, but for other numbers, not so much.
Oh, another thing that's nice about writing concise code: it's easier to see where your errors are. Take another look at the numbers you've hard-coded into check(): you're incrementing the columns by 3 and the rows by 1. That would be much easier to spot if you compressed it into a pair of for loops.