For a class project we need to be able to draw a triangle in a 2D array of chars. Algorithmically I can't work out how to do it.
My current code is this (but it does not work):
public void fill() {
for (int i = 0; i < h; i++) {
double x=h;
while(x<=0){
drawing.setPoint(i, x, myChar);
x=Math.ceil(x/2);
}
}
}
I want the output to look something like this:
....*....
...***...
..*****..
.*******.
*********
We can't use any pre-existing methods or classes that relate to drawing.
Thanks for your help
Based on your drawing, you need 9 columns for 5 rows. So,
int height = 5;
int width = 2*height - 1;
Even though I'm not sure what drawing.setPoint(i, x, myChar); does, I think this example will get you going. I will build a String based on chars.
char fill = '*';
char blank = '.';
I'll start the rows at 0 but the columns at 1 to make the math a little clearer.
For row = 0, ....*.... you need one star in column = 5.
For row = 1, ...***... you need three stars in column = 4,5,6.
For row = 3, .*******. you need seven stars in column = 2,3,4,5,6,7,8.
Notice that for row i you need a star in column j if the distance between the height = 5 and the column j is less than or equal to i. That is, when | height - column | <= row
for (int row = 0; row < height; row ++) {
StringBuilder line = new StringBuilder(width);
for (int column = 1; column <= width; column ++) {
char out = Math.abs(column - height) <= row ? fill : blank;
line.append(out);
}
System.out.println(line);
}
This yields
....*....
...***...
..*****..
.*******.
*********
I assume you can use Math.abs since your example has Math.ceil. If not, you can convert Math.abs to an if statement.
There are lots of ways to tackle this, and you've already seen one answer which draws the picture row-by-row.
I'm going to assume that you've already got routines to create char[][] and to print the characters in that array of arrays to the screen. It looks as if you already have a setPoint() method too, to poke a point into the structure.
As a beginner, I don't think it helps you to be given a solution. You need to be pointed in the right direction to solve it yourself.
Lots of experienced coders now use Test Driven Design, and you could learn from this: start with a simple case, create a test for that, make that test pass, repeat with more tests until there are no more tests to write.
Eventually you should learn a test framework like jUnit, but for now you can "test" by just running your program. So the first test is, does it work for height == 1?
You can pass this test (for now that means, run the program and see that the output looks right) with:
public void drawTriangle(int height) {
drawing.setPoint(0,5,'*')
}
Job done.
Now to make it work for height==2:
public void drawTriangle(int height) {
drawing.setPoint(0,5,'*');
if(height == 2) {
drawing.setPoint(1,4,'*');
drawing.setPoint(1,5,'*');
drawing.setPoint(1,6,'*');
}
}
This still works for height == 1, but also works for height == 2.
But you can immediately see an opportunity for a loop to replace those three commands for the second row. So:
public void drawTriangle(int height) {
drawing.setPoint(0,5,'*');
if(height == 2) {
for(int 4; i<7; i++) {
drawing.setPoint(1,i,'*');
}
}
}
... and you can pull that out into a method:
public void drawTriangle(int height) {
drawing.setPoint(0,5,'*');
if(height == 2) {
drawRow2();
}
}
private void drawRow2() {
for(int 4; i<7; i++) {
drawing.setPoint(1,i,'*');
}
}
This is called refactoring -- writing something that works, but isn't written the best way, testing it to ensure it works, then changing the way it's written one step at a time, so it still works, but in a tidier way.
Hopefully you can see where this is going. You can modify drawRow2() to be more general -- drawRow(int rowNumber), and gradually replace the literal numbers in there with variables derived from rowNumber. Then you can use drawRow(0) to draw the first row, and drawRow(1) to draw the second. Then you can draw a three row triangle by adding drawRow(2), and then you can improve that by using a loop instead.
Related
I need to solve a crossword given the initial grid and the words (words can be used more than once or not at all).
The initial grid looks like that:
++_+++
+____+
___+__
+_++_+
+____+
++_+++
Here is an example word list:
pain
nice
pal
id
The task is to fill the placeholders (horizontal or vertical having length > 1) like that:
++p+++
+pain+
pal+id
+i++c+
+nice+
++d+++
Any correct solution is acceptable, and it's guaranteed that there's a solution.
In order to start to solve the problem, I store the grid in 2-dim. char array and I store the words by their length in the list of sets: List<Set<String>> words, so that e.g. the words of length 4 could be accessed by words.get(4)
Then I extract the location of all placeholders from the grid and add them to the list (stack) of placeholders:
class Placeholder {
int x, y; //coordinates
int l; // the length
boolean h; //horizontal or not
public Placeholder(int x, int y, int l, boolean h) {
this.x = x;
this.y = y;
this.l = l;
this.h = h;
}
}
The main part of the algorithm is the solve() method:
char[][] solve (char[][] c, Stack<Placeholder> placeholders) {
if (placeholders.isEmpty())
return c;
Placeholder pl = placeholders.pop();
for (String word : words.get(pl.l)) {
char[][] possibleC = fill(c, word, pl); // description below
if (possibleC != null) {
char[][] ret = solve(possibleC, placeholders);
if (ret != null)
return ret;
}
}
return null;
}
Function fill(c, word, pl) just returns a new crossword with the current word written on the current placeholder pl. If word is incompatible with pl, then function returns null.
char[][] fill (char[][] c, String word, Placeholder pl) {
if (pl.h) {
for (int i = pl.x; i < pl.x + pl.l; i++)
if (c[pl.y][i] != '_' && c[pl.y][i] != word.charAt(i - pl.x))
return null;
for (int i = pl.x; i < pl.x + pl.l; i++)
c[pl.y][i] = word.charAt(i - pl.x);
return c;
} else {
for (int i = pl.y; i < pl.y + pl.l; i++)
if (c[i][pl.x] != '_' && c[i][pl.x] != word.charAt(i - pl.y))
return null;
for (int i = pl.y; i < pl.y + pl.l; i++)
c[i][pl.x] = word.charAt(i - pl.y);
return c;
}
}
Here is the full code on Rextester.
The problem is that my backtracking algorithm doesn't work well. Let's say this is my initial grid:
++++++
+____+
++++_+
++++_+
++++_+
++++++
And this is the list of words:
pain
nice
My algorithm will put the word pain vertically, but then when realizing that it was a wrong choice it will backtrack, but by that time the initial grid will be already changed and the number of placeholders will be reduced. How do you think the algorithm can be fixed?
This can be solved in 2 ways:
Create a deep copy of the matrix at the start of fill, modify and return that (leaving the original intact).
Given that you already pass around the matrix, this wouldn't require any other changes.
This is simple but fairly inefficient as it requires copying the matrix every time you try to fill in a word.
Create an unfill method, which reverts the changes made in fill, to be called at the end of each for loop iteration.
for (String word : words.get(pl.l)) {
if (fill(c, word, pl)) {
...
unfill(c, word, pl);
}
}
Note: I changed fill a bit as per my note below.
Of course just trying to erase all letter may erase letters of other placed words. To fix this, we can keep a count of how many words each letter is a part of.
More specifically, have a int[][] counts (which will also need to be passed around or be otherwise accessible) and whenever you update c[x][y], also increment counts[x][y]. To revert a placement, decrease the count of each letter in that placement by 1 and only remove letters with a count of 0.
This is somewhat more complex, but much more efficient than the above approach.
In terms of code, you might put something like this in fill:
(in the first part, the second is similar)
for (int i = pl.x; i < pl.x + pl.l; i++)
counts[pl.y][i]++;
And unfill would look something like this: (again for just the first part)
for (int i = pl.x; i < pl.x + pl.l; i++)
counts[pl.y][i]--;
for (int i = pl.x; i < pl.x + pl.l; i++)
if (counts[pl.y][i] == 0)
c[pl.y][i] = '_';
// can also just use a single loop with "if (--counts[pl.y][i] == 0)"
Note that, if going for the second approach above, it might make more sense to simply have fill return a boolean (true if successful) and just pass c down to the recursive call of solve. unfill can return void, since it can't fail, unless you have a bug.
There is only a single array that you're passing around in your code, all you're doing is changing its name.
See also Is Java "pass-by-reference" or "pass-by-value"?
You identified it yourself:
it will backtrack, but by that time the initial grid will be already
changed
That grid should be a local matrix, not a global one. That way, when you back up with a return of null, the grid from the parent call is still intact, ready to try the next word in the for loop.
Your termination logic is correct: when you find a solution, immediately pass that grid back up the stack.
I am new in this page, it hope get to some help, basically I am doing a minesweeper game on Java but it have a problem with a function: discover the region with no mines and no numbers like in the game on windows, when you click in one place and all withe cells appear. I tried make recursive but I can't, some help?
Sorry for the code, the original is in spanish but i tried make a pseudocode:
Matriz = multidimensional Array (the minesweeper)
min and max returns the index min and max to iterate (8 sorroud cells)
private void discoverWitheCell(int x, int y) {
if(matriz[x][y].getdiscovered() == false){
matriz[x][y].setDiscovered(true);
}
else{
if(matriz[x][y].getNumberOfMinesArround() == 0){
for(int i=min(x);i<max(x);i++)
for(int j=min(y);j<max(y);j++)
discoverWhiteCell(i,j);
}
}
}
There's not a lot of code here but I feel like you're coming at it backwards.
Sorry, I'm not a Java speaker so I'm guessing at some of the syntax. Note that this can go out of bounds--personally, I would add a layer of empty cells around my map so I never need to concern myself with bounds checking.
private void ClickSquare(int x, int y)
{
// Did the user click an already exposed square? If so, ignore
if (matriz[x][y].getDiscovered()) return;
matriz[x][y].SetDiscovered(true);
if (matriz[x][y].getNumberOfMinesAround != 0) return;
// If empty, click all the neighbors
for (int xloop = x - 1; xloop <= x + 1; xloop++)
for (int yloop = y - 1; yloop <= y + 1; yloop++)
ClickSquare(xloop, yloop);
}
I believe you have the discovered test messed up and your version appears to be able to go into infinite (until the stack overflows) recursion as if the neighbor is also zero it will come back to the original cell. My version stops this recursion by only processing a cell if it hasn't already been processed.
to describe my issue I must first discuss what I am trying to do, http://i.imgur.com/rcHwze5.png here is an image of a letter with a 10*10 grid over it. For every box in the grid if 1/3 of the pixels are colored a 1 is added to the ArrayList, otherwise a 0 is added. Here is my 3 methods that I have created to do this: https://gist.github.com/VincentMc/7ddf3c282e80bbff7835 BoundBM is a bitmap object with the letter drawn onto it.
Here is an image of my desired output http://i.imgur.com/B0QnUW8.png
Here is an image of my actual output http://i.imgur.com/WgRVXLv.png
It seems once a 1 is added on a row it is constantly added until it reaches the next row, but I can't seem to see why??
Any help would be greatly appreciated I have been at this quite a while, Thanks!
do it in two step:
1: sort each string:
public String sortString(String s1){
char[] chars = s1.toCharArray();
Arrays.sort(chars);
String sorted = new String(chars);
return sorted;
}
2: put each of your string in an array and use:
Arrays.sort(stringArray);
Out of the Code-Segmet you offered, i cant see an obvious mistake. But your design is inviting mistakes. To avoid these you may try:
Don't use count as a classwide variable, thou its not relevant for the hole class but only for the method. So make it an return statement, that you dont loose control over it, that it may be set anywhere or is only changed locally in a method.
totalp should not be calculated in every countPixel() method call, because it is a fixed value for your BoundBM. Initialize it in your constructor maybe, or with loading the bitmap.
At last, you know how large your output array is supposed to be, it doesnt make much sense for me, to keep it a list and to add it. Create an 2D array, and write it directly.
Hope it will help
reineke
EDIT: found the mistake!
in code line 27 you set x to 0 and not to the initial value of the input x, so you continue at the wrong position!!
Here is what i would do:
final int GRID=10;
totalp = boundBM.getWidth()/GRID * boundBM.getHeight()/GRID;
//this method now does not need to read boundBM, so it is more opject-oriented
public int countPixels(int x, int y, int h, int w){
count = 0;
for (i=x; i<x+w; i++){
for(k =y; k<y+h; k++){
if(c != boundBM.getPixel(i, k)) count++;
}
}
//funny thing
return (count>totalp/3) ? 1 : 0;
}
public void createNeuralInput(){
int h = boundBM.getHeight()/GRID;
int w = boundBM.getWidth()/GRID;
int[][] array= new int[GRID][GRID];
for(int i = 0; i < GRID; i++) {
for(int j = 0; j < GRID ; j++) {
n1.add(countPixels(i*h, j*w, h, w));
//i would prefer:
//array[i][j]=countPixels(i*h, j*w);
}
}
}
I am trying to implement a chess game with alpha beta pruning. The following is almost working, but it returns wrong moves.
For example, the following can occur.
White (user) to move, white king position - a1 / Black (computer), black king position - h1
White moves its king from a1 - a2, then black return the move g2 - g1???
It appears that the computer returns a move for the wrong node (board representation), as if the best evaluation of a given board position is not being propagated all the way back up the tree. So in one of the simulated positions explored, the computer "imagines" its king moving to g2 and then returns the move to be made from this position, not realising that this position is a simulated position and not the representation of the actual board (the root node?).
How can I correct the code to make the computer return a move for the actual board representation and not one of the simulations by mistake?
Thank you.
Initial call alphaBeta(3, ChessEngine.invertBoard(ChessEngine.board), -10000, 10000, true);
private static int alphaBetaEvaluate = 0;
private static int alphaBetaSelectedSquare = 0;
private static int alphaBetaMoveToSquare = 0;
public static int alphaBeta(int depth, char[] board, int alpha, int beta, boolean maxPlayer) {
//create a copy of the board
char[] boardCopy = board.clone();
//if terminal state has not been met, keep searching
if (maxPlayer == true && depth > 0) {
//for all of the moves that max can make
for (int i = 0; i < board.length; i++) {
for (int move : ChessEngine.getValidMoves(i, boardCopy)) {
//make the move
boardCopy[move] = boardCopy[i];
boardCopy[i] = '.';
alphaBetaEvaluate = rating(board, boardCopy, i, move);
//store the best move to make
int temp = alphaBeta(--depth, ChessEngine.invertBoard(boardCopy), -10000, 10000, false);
if (temp > alpha) {
alphaBetaSelectedSquare = i;
alphaBetaMoveToSquare = move;
alpha = temp;
}
//reset the board for the next simulated move
boardCopy = board.clone();
if (beta <= alpha) {
break;
}
}
}
return alpha;
} else if (maxPlayer == false && depth > 0) {
//for all of the moves that min can make
for (int i = 0; i < board.length; i++) {
for (int move : ChessEngine.getValidMoves(i, boardCopy)) {
//make the move
boardCopy[move] = boardCopy[i];
boardCopy[i] = '.';
beta = Math.min(beta, alphaBeta(--depth, ChessEngine.invertBoard(boardCopy), -10000, 10000, true));
//reset the board for the next simulated move
boardCopy = board.clone();
if (beta <= alpha) {
break;
}
}
}
return beta;
}
return alphaBetaEvaluate;
}
I dont get your implementation after all. First of all what you want to do is create a tree. A decision tree and propagates the decision up. You want to maximize your evaluation and also expect that the enemy will select the move that minimizes your evaluation in return.
So inverting the board does not sound so reasonable for me unless you know that the evaluation you do uppon the situation is correctly adjusting.
Another serious problem for me is that you always call the min/max for the next move with -10k and 10k as the bounderies for alpha and beta. This way your algorithm does not 'learn' from previous moves.
What you need is to check the algorithm again (wikipedia for instance, which I used) and see that they use alpha and beta being modified by former evaluation. This way the calculation in higher depth can firstly stop and secondly evaluate the best move better.
I am no expert in this. its decades ago when I wrote my implementation and I used something different.
Another idea is not to use min and max within the same method but use the min and max methods instead. It makes it more likely you spot other defects.
Also do not use two kings for evaluation. There is no goal in that. Two kings are random, cant win. One thing might be two knights or four queens and alike. It is not so random and you can see the queens dancing around without being able to catch each other. Or use three knights versus a single queen.
And try to create yourself some unit tests around your other parts. Just to insure that the parts are working correctly independently. And why are you using characters? Why not using enums or objects. You can reuse the objets for each field (its more like kinds of figures).
But anyhow this is style and not algorithm correctness.
I am not familiar with coordinate systems or much of the math dealing with these things at all. What I am trying to do is take a Point (x,y), and find its position in a 1 dimensional array such that it follows this:
(0,2)->0 (1,2)->1 (2,2)->2
(0,1)->4 (1,1)->5 (2,1)->6
(0,0)->8 (1,0)->9 (2,0)->10
where the arrows are showing what value the coordinates should map to. Notice that an index is skipped after each row. I'm think it'll end up being a fairly trivial solution, but I can't find any questions similar to this and I haven't had any luck coming up with ideas myself. I do know the width and height of the 2 dimensional array. Thank you for any help!
My question is perhaps ambiguous or using the wrong terminology, my apologies.
I know that the coordinate (0,0) will be the bottom left position. I also know that the top left coordinate should be placed at index 0. Each new row skips an index by 1. The size of the coordinate system varies, but I know the number of rows and number of columns.
First step, flip the values upside down, keep points in tact:
(0,2)->8 (1,2)->9 (2,2)->10
(0,1)->4 (1,1)->5 (2,1)->6
(0,0)->0 (1,0)->1 (2,0)->2
You'll notice that y affects the output by a factor of 4 and x by a factor of 1.
Thus we get a very simple 4y + x.
Now to get back to the original, you'll notice the transformation is (x,y) <- (x,2-y) (that is, if we transform each point above with this transformation, we get the original required mapping).
So, substituting it into the equation, we get (2-y)*4 + x.
Now this is specific to 3x3, but I'm sure you'll be able to generalize it by replacing 2 and 4 by variables.
If you want to reduce the dimension and avoid overlapping you need a space-filling-curve, for example a morton curve. Your example looks like a peano curve because it's a 3x3 matrix. These curves is difficult to calculate but have some nice things. But if you just look for self-avoiding curves you can create your own? Read here: http://www.fractalcurves.com/Root4Square.html.
I was beaten to the formula, here is the bruteforce using a Map.
public class MapPointToIndex {
private Map<Point, Integer> map;
private int index, rowcount;
public MapPointToIndex(int rows, int columns) {
map = new HashMap<Point, Integer>();
for (int i = rows - 1; i >= 0; i--) {
index += rowcount;
for (int j = 0; j < columns; j++) {
Point p = new Point(j, i);
map.put(p, index);
index++;
}
rowcount = 1;
}
}
public int getIndex(Point point){
return map.get(point);
}
public static void main(String[] args) {
MapPointToIndex one = new MapPointToIndex(3, 3);
System.out.println(one.map);
}
}
Out:
{java.awt.Point[x=0,y=0]=8, java.awt.Point[x=2,y=2]=2, java.awt.Point[x=1,y=2]=1, java.awt.Point[x=2,y=1]=6, java.awt.Point[x=1,y=1]=5, java.awt.Point[x=2,y=0]=10, java.awt.Point[x=0,y=2]=0, java.awt.Point[x=1,y=0]=9, java.awt.Point[x=0,y=1]=4}