I basically checked out a book from the Library and started learning Java. I'm trying to code a little score calculator for my golf league and this site has been a lof of help! So thanks for even being here!
Now to the question:
I have a 9 labels, created with NetBeans GUI, with names like jLabel_Hole1, jLabel_Hole2, ...
If a user selects the radio option to play the front nine those labels have number 1 - 9 and if they change it to the "Back Nine" then they should display 10 - 18. I can manually set each label to the new value on a selection change but I wanted to know if there was a more elegant way and if so if one of you could be kind enough to explain how it works.
Here is the code that I want to try and truncate:
TGL.jLbl_Hole1.setText("10");
TGL.jLbl_Hole2.setText("11");
TGL.jLbl_Hole3.setText("12");
TGL.jLbl_Hole4.setText("13");
TGL.jLbl_Hole5.setText("14");
TGL.jLbl_Hole6.setText("15");
TGL.jLbl_Hole7.setText("16");
TGL.jLbl_Hole8.setText("17");
TGL.jLbl_Hole9.setText("18");
I've read some things about String being immutable and maybe it's just a limitation but I would think there has to be way and I just can't imagine it.
Thanks.
Basically, rather then creating a individual label for each hole, you should create an array of labels, where each element in the array represents a individual hole.
So instead of...
TGL.jLbl_Hole1.setText("10");
TGL.jLbl_Hole2.setText("11");
TGL.jLbl_Hole3.setText("12");
TGL.jLbl_Hole4.setText("13");
TGL.jLbl_Hole5.setText("14");
TGL.jLbl_Hole6.setText("15");
TGL.jLbl_Hole7.setText("16");
TGL.jLbl_Hole8.setText("17");
TGL.jLbl_Hole9.setText("18");
You would have...
for (JLabel label : TGL.holeLables) {
lable.setText(...);
}
A better solution would be to hide the labels from the developer and simply provide a setter...
TGL.setHoleText(hole, text); // hole is int and text is String
Internally to your TGL class, you have two choices...
If you've used the form editor in Netbeans, you're going to have to place the components that Netbeans creates into your own array...
private JLabel[] holes;
//...//
// Some where after initComponents is called...
holes = new JLabel[9];
holes[0] = jLbl_Hole1;
// There other 8 holes...
Then you would simply provide a setter and getter methods that can update or return the value...
public void setHole(int hole, String text) {
if (hole >= 0 && hole < holes.length) {
holes[hole].setText(text);
}
}
public String getHole() {
String text = null;
if (hole >= 0 && hole < holes.length) {
text = holes[hole].getText();
}
return text;
}
Take a closer look at the Arrays tutorial for more details...
I've never found a Java GUI-generator to provide code that's any good. I may be wrong--there may be a good one, but I always prefer to position and name them myself. So,
/**
* The JLabels for the holes on the golf course.
* <p>
* holeLabels[0][i] are for the outward holes, 1-9.
* holeLabels[1][i] are for the inward holes, 10-18.
*/
private JLabel[][] holeLabels;
/**
* The starts of the outward and inward ranges of holes.
*/
private static final int[] holeStart = {1, 10};
// Later
holeLabels = new JLabel[2][9];
for(final int i = 0; i < holeLabels.length; i++) {
for (final int j = 0; j < holeLabels[i].length; j++) {
holeLabel[i][j] = new JLabel();
holeLabel[i][j].setText(Integer.toString(holeStart[i] + j));
}
}
Interestingly, holeLabels.length is 2. holeLabels is an array of 2 arrays of 9 ints. i goes from 0 to 1, and j goes from 0 to 8, so the text computation works. The reason I did things this way is so you can easily place the labels in an appropriate GridLayout later.
Related
I'm making a snake game and the apples shouldn't spawn inside the snake when randomly spawned on the screen. I have tried looking for a new place for the apples, when they get placed inside the snake with:
for (int i = 0; i < snake.size() - 1; i++) {
if (snake.get(i).xPos == plum.get(0).xPos && snake.get(i).yPos == plum.get(0).yPos) {
plum.remove(0);
plum.add(new Coordinate(rollDice(squaresX - 1) * (squareSize + sizeOfSpace) + sizeOfSpace, rollDice(squaresY - 1) * (squareSize + sizeOfSpace) + sizeOfSpace, new Color(199, 7, 255)));
}
}
This is not a good solution so I'm looking for a new one where I can create invalid coordiantes which are the snakes coordinates and valid coordinates that is the rest. So I can randomize the apples new position from just valid coordinates. But I'm not sure how I'm supposed to code this
This is just a general suggestion, but I think it might work for you.
Keep the length of the snake updated all of the time
Now when creating a new apple, create an array of Coordinations of size of the grid size minus snake length. For example: if your grid size is 9x9 and your snake length is 6, create an array of length 75.
Run over the grid and array and add to the array just Coordinations that do not have the snake in them. It should look something like this:
int arrayLocation=0;
for(int i=0; i< grid.length();i++)
{
for(int j=0; j<grid[i].length(); j++)
{
if (!snakeAtLocation(i,j))
{
arr[arrayLocation++] = new Coordinate(i, j);
}
}
}
Then you can randomly pick a number n between 0 to arr.length(), then retrieve the coordination from arr[n] and you should have a coordination without a snake in it. Hope it helps and if you need more detailed example I will provide tommorow as I'm writing this from my phone and I don't have pc right now:)
By the way, this answer if for a simple use case, as it isn't optimized and running with o(n)^2 each time you eat an apple. If you want more optimized solutions, you would have to track the snake location with each move he make. I'll be able to post both answers tommorow if needed:)
I am creating a simple game of 15 puzzle (Please see here: https://en.wikipedia.org/wiki/15_puzzle). I have an array of 4 by 4 buttons and want to know the best way to handle a user clicking on a button and moving around the numbers.
I have started off by creating a JavaFX gridpane to display the buttons as well as a HashMap (suggested by multiple people) to store a mapping between the displayed number (1-15) and the button at that location.
I populate the map with class objects "Btn"
public class Btn {
private int ID;
private int x;
private int y;
public Button button;
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 4; j++) {
Btn btn = new Btn(count, j, i, new Button("" + count));
map.put(count, btn);
btn.button.setMinSize(100, 100);
btn.button.setOnAction(e -> {
if (isMoveLegal(btn) == true) {
move(btn);
}
});
count++;
grid.add(btn.button, j, i);
}
}
So far it has worked quite well. In the isMoveLegal() method I check if the empty field is above, left, right, or below the clicked button. Which gets quite complicated because of the HashMaps nature of not preserving any order. But my real problem lies in the move() method. Since there is no order, I can't just switch 2 map nodes or can I?
if (MoveDir.equals("Right")) {
map.get((btn.getYs()+1)*4 - (4-btn.getXs())).button.setText("" + map.get(btn.getID()).getID());
map.get(btn.getID()).button.setText("" + map.get((btn.getYs()+1)*4 - (4-btn.getXs())).getID());
int tempID = map.get(btn.getID()).getID();
map.get(btn.getID()).setID(16);
map.get((btn.getYs()+1)*4 - (4-btn.getXs())).setID(tempID);
// System.out.println(map.get(btn.getID()).getID());
// System.out.println(map.get((btn.getYs()+1)* 4 - (4-btn.getXs())).getID());
map.get(btn.getID()).setYs(map.get(btn.getID()).getYs()+1);
map.get((btn.getYs()+1)* 4 - (4-btn.getXs())).setYs(map.get((btn.getYs()+1)* 4 - (4-btn.getXs())).getYs()-1);
This is what I have come up with so far, which extremely complicated and tedious. To quickly sum it up, I first switch the labels of the buttons, then I change the ID variables of the 2 buttons, and then I change the cord variables (x & y) to indicate their new location in map/grid.
I'm pretty sure I have gone way too far with this and there is a simpler solution to all of this but I am just unsure what that would be. Should I ditch the HashMap entirely and just use an object array of Btns?
Thanks for the help.
The problem you're facing is that your UI and your data structure are too tightly coupled. You need to separate them, give them their own responsibilities, and use communication (method calls) between them to make things happen.
For example, the UI should only be responsible for displaying the numbers and allowing the user to click a number to perform a move. Using a gridpane of buttons seems reasonable for this. Each button only needs to know it's x,y coordinate.
The data model should be a 2-dimensional array that contains the number at that location. For example:
+-+-+-+
|4|1|8|
+-+-+-+
|2|3|7|
+-+-+-+
| |5|6|
+-+-+-+
(You can figure out how to represent the empty space. Maybe a null, or the number '0' or '-1')
The data model can be wrapped in a data object that handles questions about and manipulations to the data model. For example, one method it might contain is getTheNumberAtLocation(x,y) which the buttons will call, and will return the number at that location. The buttons will use this to determine what number they should show.
Another method it might contain is isThereASpaceNextToLocation(x,y). This would return whether or not a space exists next to the location given by the x,y. The button will call this method to determine whether or not it can be clicked.
Finally, you could have a moveLocationToEmptySpace(x,y) which will manipulate the data to put the number at the current location into the empty space. After that, all the buttons should call getTheNumberAtLocation(x,y) to update the number they are showing.
By arranging your code like this you've nicely separated the concern of the UI (show text, handle button clicks) from the concern of maintaining the game state (checking if a move is valid, performing a move, determining the state of the board). Now when you write code it will be easier to write because each method will be responsible for a small, manageable piece of logic.
To summarise:
Gridpane (4x4)
-> Button
-> label [calls GameData.getTheNumberAtLocation]
-> click [calls GameData.isThereASpaceNextToLocation, moveLocationToEmptySpace]
GameData
-> Array (4x4) (private)
-> Integer (1-15)
-> getTheNumberAtLocation(x,y)
-> isThereASpaceNextToLocation(x,y)
-> moveLocationToEmptySpace(x,y)
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.
OK, so I created a console app that, among other things, takes an array of numbers and prints them out one by one, line by line. Now, I have to take the class that I created for that console app, and pop it into a separate GUI app we're creating. I have all of the other methods working fine, but for the life of me I cannot get the array method to print out correctly. It just gives me the last number I typed into the text field. I'm hoping someone can give me a nudge to help me figure this part out so I can move along, and get to the whole SpringLayout stuff, (the main part of the new assignment) I am limited in what I can show you here because this is a current assignment, so I will have to stick to this stuff as specifically as I can. And please, don't just post the code as an answer, (because then I can't use it), thanks.
Here's what I had for my original project for the array method:
int [] getArray(int x)
{
breakUpNum(x);
return numAry;
}
From there, inside my new class I have this, in an attempt to get it to print:
private class ButtonTest implements ActionListener
{
public void actionPerformed(ActionEvent ae)
{
Lab1 tester = new Lab1();
int[] test4 = tester.getArray(num);
for(int i = 0; i < test4.length; i ++)
{
crossTest.getArrCross.setText("" + test4[i]);
}
}
}
Any help pointing me in the right direction would be greatly appreciated, thanks!
setText does just that, sets the text you pass to as the current text content, it does not append it.
If you were to use JTextArea, you could use it's append method...however, for a JTextField you need to have a different approach.
Now you could use getArrCross.setText(getArrCross.getText() + test4[i])...but to quite frank, that's rather inefficient, as each call to setText is going to stage a paint event...
StringBuilder sb = new StringBuilder(128);
for(int i = 0; i < test4.length; i ++)
{
sb.append(test4[i]);
}
crossTest.getArrCross.setText(sb.toString());
Now, if you want to separate each element, you need to add
if (sb.length() > 0) {
sb.append(", ");
}
Before sb.append(test4[i]);
The last bit of actionPerformed in the for loop isn't working right. setText replaces the current text with its argument, and it doesn't seem like you want to do that. To fix it, replace the line in the for loop with this:
crossTest.getArrCross.setText(crossTest.getArrCross.getText() + test4[i]);
I created two methods for my Bingo Game in Java. One method creates a new board which populates the Bingo Board with integers according to the Bingo rule (1-75). My second method generates random numbers with a range of 1 - 75.
public static int drawNum(){
Random rand = new Random();
int num = rand.nextInt(75)+1;
return num;
}
public static void bingoCard(){
int [][]card=new int [5][5];
ArrayList<Integer> alreadyUsed = new ArrayList<Integer>();
boolean valid = false;
int tmp = 0;
for(int i = 0; i <= 4; i++){
for(int row = 0; row < card.length; row++){
while(!valid){
tmp = (int)(Math.random() * 15) + 1 + 15 * i;
if(!alreadyUsed.contains(tmp)){
valid = true;
alreadyUsed.add(tmp);
}
}
card[row][i] = tmp;
valid = false;
}
}
card[2][2] = 0;
//create array to make title.
String title []={"B","I","N","G","O"};
for(int i=0;i<title.length;i++){
System.out.print(title[i]+ "\t");
}
System.out.println();
for(int row=0;row<card.length;row++){
for(int col=0;col<card[row].length;col++){
System.out.print(card[row][col]+ "\t");
}
System.out.println();
}
}
What I need help with is, how do I check whether or not the drawNum() method corresponds to any values stored inside my bingoCard() array? If so, print out a new array with the integers filled in. If the condition is met for a bingo, then you win.
I hope I don't make it sound like I want you to do it for me, but I am confused as to how to start coding that part. Thank you.
This my recommendation - Learn Object Oriented Programming immediately
I see you are using objects provided in the JDK, so why not learn to make your own?
Make two classes with the following methods (-) and members (+) (PS. This is not a formal way to document code)
BingoCard
+list of numbers on card
-reset() : gets new numbers for this card
-test(BingoDrawer) : Tests to see if this card won on this drawing
-toString() : returns a String representation of this card
BingoDrawer
+list of numbers drawn
-reset() : draws new numbers
-hasNumber(int number) : tests if this number was drawn
-toString() : returns a String representation of this drawing
One more suggestions
Instead of keeping track of what you used, keep track of what you have not used, it will make things much easier because you can just choose stuff from that list randomly. Unlike your current action which is choosing (a logical number) from thin air and hoping (which causes issues) it is not a collision
If you follow my recommendation you can write code like this
public static void main(String[] args) {
BingoCard bc = new BingoCard();
BingoDrawer bd = new BingoDrawer();
while(thePlayerWantsToPlay()) { //function to be defined by you
bc.reset();
bd.reset();
System.out.println(bc);
System.out.println(bd);
System.out.println(bc.test(bd));
}
}
You can take it a step further and make a BingoGame class and do what I did in main there and just create an instance of BingoGame and call some start method on the object.
For checking if you have the number in your board, read through the board in a similar manner as you do for the already_used numbers, except with the number the user just entered.
The conditions for the user to win should be checked after the board has another number guessed.
There are a few ways to do this, a simple one would be to iterate over every possible pattern that could win, checking to see if there are tokens there.
All of this would be in a loop, that goes a little like this:
Set up board via user entering numbers.
Start loop
set either a timer to wait for, or wait for a keypress (so the game doesn't just play really fast)
Get random number
Possibly add to board
Check if winner
if winner, break the loop and do something else.
Print the new board out.
(end of loop)
If they got here, that could mean they won!
Wait to exit
You can just write it out as pseudo-code and fill in the methods after that. It usually helps to work on these things in a top-down fashion. So, for bingo you might have:
board = generateBoard();
while (!bingoFound(board)) {
number = drawNumber();
board = stampNumbers(board, number);
}
If that makes sense, you can go a step deeper and define each method. For example, bingoFound might look like:
public boolean bingoFound(int[][] board) {
boolean wasFound = bingoRowFound(board)
|| bingoColFound(board)
|| bingoDiagonalFound(board);
return wasFound;
}
Again, I've defined everything in (mostly) pseudo-code. If this looks ok, you can move a step deeper. Let's define the bingoRowFound method.
public boolean bingoRowFound(int[][] board) {
for (int row = 0; row < NUM_ROWS; row++) {
boolean rowIsABingo = true;
for (int col = 0; col < NUM_COLS; col++) {
// We have to check that everything up until this point has
// been marked off. I am using -1 to indicate that a spot has
// been marked.
rowIsABingo = rowIsABingo && board[row][col] == -1;
}
if (rowIsABingo) { return rowIsABingo; }
}
return false; // If we didn't find a bingo, return false.
}
Some of the methods (like drawNumber) will be really easy to implement. Others, like looking for a diagonal bingo might be a bit more difficult.
Feb 12 2014 Update:
Retracted code, since this was a college course assignment, and I want to prevent people just copying the code. I almost got in trouble for being accused of sharing code (which is a nono in assignments) when another student lifted my code from my Github repo and sent it in as their own.
There were two classes, one main class and a class to hold my methods and constructors.
BINGOFINAL.java was my main class.
Bingo_Card.java held my constructor and methods.
If you want to run this, make sure you create a new project called BINGOFINAL, and put Bingo_Card.java into that same */src/ extension.