I'm working on a genetic algorithm which recreates paintings using triangles. At the moment my method used to populate children is changing the values of the parents and I can't figure out why.
public void populate()
{
System.out.println("pre: " + Arrays.toString(triangles[0][0]));
for(int drawNum = 2; drawNum < 12; drawNum ++)
{
for(int triNum = 0; triNum < numTriangles; triNum ++)
{
double pChooser = Math.random();
if(pChooser < .45)
{
triangles[drawNum][triNum] = triangles[0][triNum];
}
else if(pChooser < .9)
{
triangles[drawNum][triNum] = triangles[1][triNum];
}
else
{
triangles[drawNum][triNum] = randomTriangle();
}
}
}
genNum ++;
System.out.println("pst: " + Arrays.toString(triangles[0][0]));
}
private int[] randomTriangle()
{
int[] result = new int[9];
for(int i = 0; i < 9; i++)
{
result[i] = (int) (Math.random() * 256);
}
return result;
}
triangles is a 3 dimensional int array that holds each drawing, each triangle in the drawing, and each value of the endpoints and color of the triangle in the form triangles[drawingNumber][triangleNumber][values]. triangles[0] and triangles[1] are the two parents. The print statements print the values of the first triangle in the first parent before and after the children are formed. However, the pre and post print statements are returning different results, meaning that triangles[0][0] was changed somewhere in the code, but I can't figure out where that is.
Related
I am assigning 3 chars (two 'T's and one 'S') to a 10 x 10 grid. I have that down but I want to know how I could re randomize the char's positions if they end up on the same spot. Basically I am creating a little game where I am a soldier (S) and am on a grid with two Targets (T). Eventually I will have to eliminate the targets but I fist I want to make sure each one ends up in it's own spot. here is my code
import java.lang.Math;
public class PaintBall_Thomas{
public static void fillGrid(char[][] battleField){
for ( int i = 0; i < battleField.length; i++){
for ( int j = 0; j < battleField[i].length; j++){
battleField[i][j] = '-';
}
}
battleField[((int)(Math.random()*10))][((int)(Math.random()*10))] = 'S';//assigns a random number between 1-10 and assigns it to either soldier/target
battleField[((int)(Math.random()*10))][((int)(Math.random()*10))] = 'T';
battleField[((int)(Math.random()*10))][((int)(Math.random()*10))] = 'T';
for ( int i = 0; i < battleField.length; i++){
for ( int j = 0; j < battleField[i].length; j++){
System.out.print(battleField[i][j] + " ");
}
System.out.println();
}
}//end of fillGrid method
public static void main(String[] args) {
int columns = 10;
int rows = 10;
System.out.println("----------GRID----------");
//end of main
char[][] battleField = new char [rows][columns];
fillGrid(battleField);
}
}
this could be a good use for recursion, so like
public void addChar(char type) {
int row = (int)(Math.random() * battleField.length); // choose rand spot
int col = (int)(Math.random() * battleField.length);
if (battleField[row][col] == '-') { // if chosen space is free
battleField[row][col] = type; // add it
} else {
addChar(type) // try again if space was occupied
}
}
so this could have some problems... such as possibilities of getting a stack overflow if the board is already full... but if the method's only intended use is to add the two Ts and one S, it should be fine
so you could just add them like
addChar('T');
addChar('T');
addChar('S');
and none of the chosen spots will be duplicates
I have an 2D array(matrix) and a Integer n.n is full square
for example if n equals 16 fill matrix like this.
1 2 3 4
12 13 14 5
11 16 15 6
10 9 8 7
what can I do?
public static void main(String args[]) {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Enter the dimension of the matrix : ");
int dimension = Integer.parseInt(br.readLine());
System.out.print("Enter the number of elements : ");
int n = Integer.parseInt(br.readLine()); // total number of elements to be filled
n = n/dimension; // Get the number of rows and columns
if(n % dimension != 0){
// Not a Square matrix
}
int circularArray[][] = new int[n][n];
int k = 1, c1 = 0, c2 = n - 1, r1 = 0, r2 = n - 1;
while (k <= n * n) {
for (int i = c1; i <= c2; i++) {
circularArray[r1][i] = k++;
}
for (int j = r1 + 1; j <= r2; j++) {
circularArray[j][c2] = k++;
}
for (int i = c2 - 1; i >= c1; i--) {
circularArray[r2][i] = k++;
}
for (int j = r2 - 1; j >= r1 + 1; j--) {
circularArray[j][c1] = k++;
}
c1++;
c2--;
r1++;
r2--;
}
/* Printing the Circular matrix */
System.out.println("The Circular Matrix is:");
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
System.out.print(circularArray[i][j] + "\t");
}
System.out.println();
}
}
Here is a tiny example how this could look like.
What is actually happening is written as comments.
public class TestArray {
// A simple enum for each direction
public enum Mode {
right, down, left, up;
}
public static void main(String[] args) {
final int size = 4; // We set a fixed size for the square
int[][] arr = new int[size][size]; // create the array from the size
// Running vallues
// i and j to refer to the array.
// val holds the current value to be inserted
// circle holds how often we are going up. Each time we go up it´s increased by one
// In the end this should reduce the amount of steps we do to not override
// already assigned values.
int i = 0,j = 0, val = 1, circle = 0;
Mode runningMode = Mode.right; // We start by going to the right.
while(size*size >= val) { // loop until we reached the last value
arr[j][i] = val++; // Assign the value and increase the value by one afterwards.
// We go right.
if(runningMode == Mode.right) {
// we reached the last assignable item.
// subtract one to not get an index out of bound,
// subract the variable trips that is used to get the last item for the inner circle
if(i==arr.length-1-circle) {
// We are going down now and increase j
runningMode = Mode.down;
++j;
} else {
// go on going right.
++i;
}
} else if(runningMode == Mode.down){
// we reached the last assignable item.
// subtract one to not get an index out of bound,
// subract the variable trips that is used to get the last item for the inner circle
if(j==arr.length-1-circle) {
// We are going left now and decrease i
runningMode = Mode.left;
--i;
} else {
// go on going down.
++j;
}
} else if(runningMode == Mode.left){
// we reached the last assignable item.
// add the variable trips that is used to get the last item for the inner circle
if(i==0+circle) {
// We are going up now and decrease j
// Simultaniosly we are about to end our next circle, so we increase circle
runningMode = Mode.up;
++circle;
--j;
} else {
// go on going left.
--i;
}
} else if(runningMode == Mode.up){
// we reached the last assignable item.
// add the variable trips that is used to get the last item for the inner circle
if(j==0+circle) {
// We are going right now and increase i
runningMode = Mode.right;
++i;
} else {
// go on going up.
--j;
}
}
}
// Print the result
for(int[] a : arr) {
for(int b : a) {
System.out.print(b + "\t" );
}
System.out.println();
}
}
}
(Disclaimer: There are maybe 20 different versions of this question on SO, but a reading through most of them still hasn't solved my issue)
Hello all, (relatively) beginner programmer here. So I've been trying to build a Sudoku backtracker that will fill in an incomplete puzzle. It seems to works perfectly well even when 1-3 rows are completely empty (i.e. filled in with 0's), but when more boxes start emptying (specifically around the 7-8 column in the fourth row, where I stopped writing in numbers) I get a Stack Overflow Error. Here's the code:
import java.util.ArrayList;
import java.util.HashSet;
public class Sudoku
{
public static int[][] puzzle = new int[9][9];
public static int filledIn = 0;
public static ArrayList<Integer> blankBoxes = new ArrayList<Integer>();
public static int currentIndex = 0;
public static int runs = 0;
/**
* Main method.
*/
public static void main(String args[])
{
//Manual input of the numbers
int[] completedNumbers = {0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,3,4,
8,9,1,2,3,4,5,6,7,
3,4,5,6,7,8,9,1,2,
6,7,8,9,1,2,3,4,5,
9,1,2,3,4,5,6,7,8};
//Adds the numbers manually to the puzzle array
ArrayList<Integer> completeArray = new ArrayList<>();
for(Integer number : completedNumbers) {
completeArray.add(number);
}
int counter = 0;
for(int i = 0; i < 9; i++) {
for(int j = 0; j < 9; j++) {
puzzle[i][j] = completeArray.get(counter);
counter++;
}
}
//Adds all the blank boxes to an ArrayList.
//The index is stored as 10*i + j, which can be retrieved
// via modulo and integer division.
boolean containsEmpty = false;
for(int i = 0; i < 9; i++) {
for(int j = 0; j < 9; j++) {
if(puzzle[i][j] == 0) {
blankBoxes.add(10*i + j);
containsEmpty = true;
}
}
}
filler(blankBoxes.get(currentIndex));
}
/**
* A general method for testing whether an array contains a
* duplicate, via a (relatively inefficient) sort.
* #param testArray The int[] that is being tested for duplicates
* #return True if there are NO duplicate, false if there
* are ANY duplicates.
*/
public static boolean checkDupl(int[] testArray) {
for(int i = 0; i < 8; i++) {
int num = testArray[i];
for(int j = i + 1; j < 9; j++) {
if(num == testArray[j] && num != 0) {
return false;
}
}
}
return true;
}
/**
* If the puzzle is not full, the filler will be run. The filler is my attempt at a backtracker.
* It stores every (i,j) for which puzzle[i][j] == 0. It then adds 1 to it's value. If the value
* is already somewhere else, it adds another 1. If it is 9, and that's already there, it loops to
* 0, and the index beforehand is rechecked.
*/
public static void filler(int indexOfBlank) {
//If the current index is equal to the size of blankBoxes, meaning that we
//went through every index of blankBoxes, meaning the puzzle is full and correct.
runs++;
if(currentIndex == blankBoxes.size()) {
System.out.println("The puzzle is full!" + "\n");
for(int i = 0; i < 9; i++) {
System.out.println();
for(int j = 0; j < 9; j++) {
System.out.print(puzzle[i][j]);
}
}
System.out.println("\n" + "The filler method was run " + runs + " times");
return;
}
//Assuming the puzzle isn't full, find the row/column of the blankBoxes index.
int row = blankBoxes.get(currentIndex) / 10;
int column = blankBoxes.get(currentIndex) % 10;
//Adds one to the value of that box.
puzzle[row][column] = (puzzle[row][column] + 1);
//Just used as a breakpoint for a debugger.
if(row == 4 && column == 4){
int x = 0;
}
//If the value is 10, meaning it went through all the possible values:
if(puzzle[row][column] == 10) {
//Do filler() on the previous box
puzzle[row][column] = 0;
currentIndex--;
filler(currentIndex);
}
//If the number is 1-9, but there are duplicates:
else if(!(checkSingleRow(row) && checkSingleColumn(column) && checkSingleBox(row, column))) {
//Do filler() on the same box.
filler(currentIndex);
}
//If the number is 1-9, and there is no duplicate:
else {
currentIndex++;
filler(currentIndex);
}
}
/**
* Used to check if a single row has any duplicates or not. This is called by the
* filler method.
* #param row
* #return
*/
public static boolean checkSingleRow(int row) {
return checkDupl(puzzle[row]);
}
/**
* Used to check if a single column has any duplicates or not.
* filler method, as well as the checkColumns of the checker.
* #param column
* #return
*/
public static boolean checkSingleColumn(int column) {
int[] singleColumn = new int[9];
for(int i = 0; i < 9; i++) {
singleColumn[i] = puzzle[i][column];
}
return checkDupl(singleColumn);
}
public static boolean checkSingleBox(int row, int column) {
//Makes row and column be the first row and the first column of the box in which
//this specific cell appears. So, for example, the box at puzzle[3][7] will iterate
//through a box from rows 3-6 and columns 6-9 (exclusive).
row = (row / 3) * 3;
column = (column / 3) * 3;
//Iterates through the box
int[] newBox = new int[9];
int counter = 0;
for(int i = row; i < row + 3; i++) {
for(int j = row; j < row + 3; j++) {
newBox[counter] = puzzle[i][j];
counter++;
}
}
return checkDupl(newBox);
}
}
Why am I calling it a weird error? A few reasons:
The box that the error occurs on changes randomly (give or take a box).
The actual line of code that the error occurs on changes randomly (it seems to usually happen in the filler method, but that's probably just because that's the biggest one.
Different compilers have different errors in different boxes (probably related to 1)
What I assume is that I just wrote inefficient code, so though it's not an actual infinite recursion, it's bad enough to call a Stack Overflow Error. But if anyone that sees a glaring issue, I'd love to hear it. Thanks!
Your code is not backtracking. Backtracking implies return back on failure:
if(puzzle[row][column] == 10) {
puzzle[row][column] = 0;
currentIndex--;
filler(currentIndex);// but every fail you go deeper
}
There are must be something like:
public boolean backtrack(int currentIndex) {
if (NoBlankBoxes())
return true;
for (int i = 1; i <= 9; ++i) {
if (NoDuplicates()) {
puzzle[row][column] = i;
++currentIndex;
if (backtrack(currentIndex) == true) {
return true;
}
puzzle[row][column] = 0;
}
}
return false;
}
So this problem is a little bit complicated to understand what I'm trying to do.
Basically, I am trying to randomly generate 3 vectors, all of size 11.
The first vector must have a 1 at position 0 with the next 5 positions being 0 (e.g. 100000) while the next five digits can be either 0 1 or 2, however there can only be one zero used in the last 5 digits, hence 10000012101 would be valid but 10000012001 wouldn't.
The same is applicable to the second and third vector however the first 1 will move a place for the second and the third (010000xxxxx for the second, and 001000xxxxx for the third).
There are more conditions that have to be satisfied. Each vector must differ from each other in at least 5 positions (10000011210 would differ from 01000022100 in 5 positions which would work).
However, there is also a final constraint which states that if you add the vectors modulo 3, then the result of adding these two must have at least 5 NON zero values in the vector.
I have went about this by using arraylists. As I know the first 6 elements of each arraylist for each vector I manually put these in, and for the next 5 elements I randomly assign these, if there is more than one 0 in the last five digits, i call the method again recursively.
The problem I have with this program is that when I try to run my code it comes up with a
Exception in thread "main" java.lang.StackOverflowError
at java.util.ArrayList.get(Unknown Source)
I think it's because it's continuously trying to loop and therefore crashing but I'm not sure. See below for the code.
import java.util.ArrayList;
/**
* The purpose of this class is to be able to capture different ways
* of generating six vectors that will produce a collection of 729
* vectors that guarantee 9 out of 11 correct.
*/
public class GenerateVectors {
static ArrayList<Integer> firstVector = new ArrayList<Integer>();
static ArrayList<Integer> secondVector = new ArrayList<Integer>();
static ArrayList<Integer> thirdVector = new ArrayList<Integer>();
static ArrayList<Integer> sumOfXandY = new ArrayList<Integer>();
//Creates the first vectors to ensure it starts with "1,0,0,0,0,0"
//and has at most one more zero in the last 5 digits
public void createFirstVector(){
int[] fir stVector1 = {1,0,0,0,0,0};
for (int i=0; i<firstVector1.length; i++) {
firstVector.add(firstVector1[i]);
}
for(int i = 0; i < 5; i++){
int x = (int) (Math.random()*3);
firstVector.add(x);
}
int j = 0;
for(int i = 6; i<firstVector.size(); i++){
if(firstVector.get(i).equals(0)){
j++;
}
}
if(j>1){
OneZeroInLastFive(firstVector);
}
int[] sum = {0,0,0,0,0,0,0,0,0,0,0};
for (int i=0; i<sum.length; i++) {
sumOfXandY.add(sum[i]);
}
}
//Edits the vector if there is more than 0 in the last five digits
public void OneZeroInLastFive(ArrayList<Integer> x){
int j = 0;
for(int i = 6; i<x.size(); i++){
if(x.get(i).equals(0)){
j++;
}
}
if(j>1){
x.set(6, (int) (Math.random()*3));
x.set(7, (int) (Math.random()*3));
x.set(8, (int) (Math.random()*3));
x.set(9, (int) (Math.random()*3));
x.set(10, (int) (Math.random()*3));
j = 0;
OneZeroInLastFive(x);
}
}
//Creates the second vector with the last 5 digits random
public void createSecondVector(){
int[] secondVector1 = {0,1,0,0,0,0};
for (int i=0; i<secondVector1.length; i++) {
secondVector.add(secondVector1[i]);
}
for(int i = 0; i < 5; i++){
int x = (int) (Math.random()*3);
secondVector.add(x);
}
}
//Creates the third vector with the last 5 digits random
public void createThirdVector(){
int[] thirdVector1 = {0,0,1,0,0,0};
for (int i=0; i<thirdVector1.length; i++) {
thirdVector.add(thirdVector1[i]);
}
for(int i = 0; i < 5; i++){
int x = (int) (Math.random()*3);
thirdVector.add(x);
}
}
/**
* Will edit the second vector to ensure the following conditions are satisfied
* - The sum of x and y modulo 3 has at least 5 NON zeros
* - x and y must DIFFER in at least 5 places
* - There is only one zero within the last 5 digits
*
*/
public void checkVectors(ArrayList<Integer> x, ArrayList<Integer> y){
int k = 0;
int m = 0;
for(int j = 0; j < x.size(); j++){
if(x.get(j).equals(y.get(j))){
;
}
else{
k++;
}
}
for(int i = 6; i<y.size(); i++){
if(y.get(i).equals(0)){
m++;
}
}
if((k>4 && m<1)&& checkNonZeros(x,y)){
System.out.println("Conditions met");
}
else{
y.set(6, (int) (Math.random()*3));
y.set(7, (int) (Math.random()*3));
y.set(8, (int) (Math.random()*3));
y.set(9, (int) (Math.random()*3));
y.set(10, (int) (Math.random()*3));
k = 0;
m = 0;
checkVectors(x,y);
}
}
public ArrayList<Integer> addTwoVectors(ArrayList<Integer> x, ArrayList<Integer> y, ArrayList<Integer> z){
for(int i = 0; i<x.size(); i++){
int j = x.get(i);
int k = y.get(i);
z.set(i, ((j+k)%3));
}
return z;
}
public boolean checkNonZeros(ArrayList<Integer> x, ArrayList<Integer> y){
addTwoVectors(x,y, sumOfXandY);
int j = 0;
for(int i = 0; i<firstVector.size(); i++){
if(sumOfXandY.get(i).equals(0)){
;
}
else{
j++;
}
}
if(j<5){
return false;
}
else {
return true;
}
}
public static void main(String[] args){
GenerateVectors g = new GenerateVectors();
g.createFirstVector();
g.createSecondVector();
g.createThirdVector();
g.checkVectors(firstVector,secondVector);
g.checkVectors(secondVector,thirdVector);
System.out.println(firstVector);
System.out.println(secondVector);
System.out.println(thirdVector + "\n");
System.out.println(g.checkNonZeros(firstVector, secondVector));
System.out.println(g.checkNonZeros(secondVector,thirdVector));
System.out.println(sumOfXandY);
}
}
Any help would be much appreciated!!!
The problem is that you have methods that recursively call themselves in order to 'redo', which may happen many times before you get a success. This is fine in languages like scheme or ml which do proper tail recursion, but java does not, so you get stack overflows.
In order to fix this you need to manually convert the recursive code into a loop. Code that looks like:
method(arg1, arg2) {
Code_block_1;
if (test) {
Code_block_2;
} else {
Code_block_3;
method(newarg1, newarg2);
}
}
needs to become something like:
method(arg1, arg2) {
Code_block_1;
while(!test) {
Code_block_3;
arg1 = newarg1;
arg2 = newarg2;
Code_block_1;
}
Code_block_2;
}
You can then refactor stuff to get rid of/merge the duplicated code if you wish.
Hey all, back again. Working on a dungeon generator and I'm actually surprising myself with the progress. Yet I still have a straggling room every now and then. I was wondering if there was a way to loop through an array and see if all the '1s' (the floor tiles) are connected, and if not, how to connect them.
Thanks!
EDIT: The array is randomly filled with rooms and corridors; here's the code:
import java.util.Random;
public class Level
{
Random random = new Random();
int[][] A = new int[100][100];
int minimum = 3;
int maximum = 7;
int xFeature = 0;
int yFeature = 0;
private void feature()
{
int i = 0;
while(i>=0)
{
xFeature = random.nextInt(100-1) + 1;
yFeature = random.nextInt(100-1) + 1;
if(A[xFeature][yFeature]==1)//||A[xFeature++][yFeature]==1||A[xFeature][yFeature--]==1||A[xFeature][yFeature++]==1)
break;
i++;
}
}
private void room()
{
int safeFall = 0;
int xCoPLUS = minimum + (int)(Math.random()*minimum);
int yCoPLUS = minimum + (int)(Math.random()*minimum);
if(yCoPLUS >= xCoPLUS)
{
for(int across = xFeature; across < xFeature+xCoPLUS+2; across++)
{
for(int vert = yFeature; vert < yFeature+yCoPLUS+1; vert++)
{
if(A[vert][across] == 0)
safeFall++;
else
break;
}
}
}
if(yCoPLUS < xCoPLUS)
{
for(int across = xFeature; across < xFeature+xCoPLUS+1; across++)
{
for(int vert = yFeature; vert < yFeature+yCoPLUS+2; vert++)
{
if(A[vert][across] == 0)
safeFall++;
else
break;
}
}
}
if((safeFall== (xCoPLUS+1) * (yCoPLUS+2)) || ((safeFall== (xCoPLUS+2) * (yCoPLUS+1))))
{
for(int across = xFeature; across < xFeature+xCoPLUS; across++)
{
for(int vert = yFeature; vert < yFeature+yCoPLUS; vert++)
{
A[vert][across] = 1;
}
}
}
}
private void corridor()
{
int xCoONE = xFeature;
int yCoONE = yFeature;
int xCoTWO = random.nextInt(10)+10;
int yCoTWO = random.nextInt(10)+10;
while(xCoONE > xCoTWO)
{
A[xCoONE][yCoONE] = 1;
xCoONE--;
}
while(xCoONE < xCoTWO)
{
A[xCoONE][yCoONE] = 1;
xCoONE++;
}
while(yCoONE > yCoTWO)
{
A[xCoONE][yCoONE] = 1;
yCoONE--;
}
while(yCoONE < yCoTWO)
{
A[xCoONE][yCoONE] = 1;
yCoONE++;
}
}
public Level()
{
firstroom();
for(int i = 0; i < 500; i++)
{
int x = random.nextInt(50);
feature();
if(x > 1)
room();
else
corridor();
}
troubleShoot();
}
So basically what happens when I create an object of this class is that a 100x100 array is filled with corridors and rooms determined by a random number. (well, a couple of them) But with how I have my room non-overlapping failsafe (safeFall in room()), I get stuck with a room that is one title out of reach every now and then.
The article Maze Generation Algorithm discusses several approaches to generating a maze. It includes links to Java examples.