How to randomly assign one of four images to a field - java

So I am doing a project for my JAVA class finals. During the assignment, there is a question ask me to randomly assign one of four images (the flower images I have) to the image field in my Flower constructor. But I did not seem to understand this requirement. Can somebody help me with this? I will greatly appreciate. Here is my code. Also, my teacher has given us a hint that we should use an "if" statement for this.
import java.awt.Point;
import javax.swing.ImageIcon;
public class Flower {
private ImageIcon image;
private Point pos;
public Flower(int x, int y) {
pos = new Point(x,y);
}
}

Generating a random number from 0 to 4 will do the trick for you.
Suppose the 4 images you have is in the form of array of type ImageIcon.
If the name of the array is list_flowers.
your constructor can be-
public Flower(int x, int y) {
Random rand = new Random();
pos = new Point(x,y);
image = list_flowers[rand.nextInt(4)];
}

First things first, you need to change Flower so you can pass it the image to be used.
public class Flower {
private ImageIcon image;
private Point pos;
public Flower(ImageIcon image, int x, int y) {
pos = new Point(x,y);
}
}
Personal thing, but I prefer it this way, as the result of initialising the class can be reasoned about.
One solution would be to make use of the available functionality in the Java API. Because I'm lazy, this would mean making use of Collections.shuffle to "randomise" a list of objects.
It might go something like....
List<ImageIcon> images = new ArrayList<>(4);
images.add(new ImageIcon(...)); // Flower 1
images.add(new ImageIcon(...)); // Flower 2
images.add(new ImageIcon(...)); // Flower 3
images.add(new ImageIcon(...)); // Flower 4
for (int index = 0; index < numberOfFlowersToCreate; index++) {
int xPos = ...; // Calculate x position
int yPos = ...; // Calculate y position
Collections.shuffle(images);
ImageIcon image = images.get(0);
Flower flower = new Flower(image, xPos, yPos);
// Do something with the instance of Flower
}

Related

Brick positions, in Breakout game, using an array in Java

I have been working on a Java project for Uni, the classic arcade game Breakout, and so far have managed to create the bat and ball objects and they work as intended. I'd like to implement the brick wall using an array as making each brick its own object will result in inefficient code, but my experience with Java doesn't extend to Arrays and I understand, unlike Python, they are tricky to get working.
I'd like the bricks to be given different positions based on x and y parameters already established.
Here is the Model class where I'd like to add the array;
public class Model
{
// First, a collection of useful values for calculating sizes and layouts etc.
public int B = 6; // Border round the edge of the panel
public int M = 40; // Height of menu bar space at the top
public int BALL_SIZE = 30; // Ball side
public int BRICK_WIDTH = 50; // Brick size
public int BRICK_HEIGHT = 30;
public int BAT_MOVE = 5; // Distance to move bat on each keypress
public int BALL_MOVE = 3; // Units to move the ball on each step
public int HIT_BRICK = 50; // Score for hitting a brick
public int HIT_BOTTOM = -200; // Score (penalty) for hitting the bottom of the screen
View view;
Controller controller;
public GameObj ball; // The ball
public ArrayList<GameObj> bricks; // The bricks
public GameObj bat; // The bat
public int score = 0; // The score
// variables that control the game
public boolean gameRunning = true; // Set false to stop the game
public boolean fast = false; // Set true to make the ball go faster
// initialisation parameters for the model
public int width; // Width of game
public int height; // Height of game
// CONSTRUCTOR - needs to know how big the window will be
public Model( int w, int h )
{
Debug.trace("Model::<constructor>");
width = w;
height = h;
}
// Initialise the game - reset the score and create the game objects
public void initialiseGame()
{
score = 0;
ball = new GameObj(width/2, height/2, BALL_SIZE, BALL_SIZE, Color.RED );
bat = new GameObj(width/2, height - BRICK_HEIGHT*3/2, BRICK_WIDTH*3,
BRICK_HEIGHT/4, Color.GRAY);
bricks = new ArrayList<>();
// ***HERE***
}
And here is the corresponding code I'd like added to View class to draw the bricks in the GUI;
public void drawPicture()
{
// the ball movement is runnng 'i the background' so we have
// add the following line to make sure
synchronized( Model.class ) // Make thread safe (because the bal
{
GraphicsContext gc = canvas.getGraphicsContext2D();
// clear the canvas to redraw
gc.setFill( Color.WHITE );
gc.fillRect( 0, 0, width, height );
// update score
infoText.setText("BreakOut: Score = " + score);
// draw the bat and ball
displayGameObj( gc, ball ); // Display the Ball
displayGameObj( gc, bat ); // Display the Bat
// ***HERE***
}
}
The .jar project file in its current state can be viewed here.
On a side note, there is a slight bug with the bat, it does not stop when it hits either side, not sure what's the best way to go about making it stay within the parameters of the window.
Thanks in advance!!
You already have your ArrayList of bricks. Create a function to convert a row/column co-ordinate into an index for your array. Say you have a grid 3x4 (3 rows, 4 columns):
0 |_|_|B|_|
1 |_|_|_|_|
2 |_|_|_|_|
0 1 2 3
Your ArrayList would be of size 12 (3x4).
private int translateCoordToIndex(int row, int col) {
return row * TOTAL_COLS + col
}
So for the brick at row=0,col=2 in the diagram its position comes out as (0*4)+2 = 2 which means index 2 in your ArrayList bricks.get(2)
You can even just change the ArrayList into a general array of GameObj GameObj[]
Alternatively you can use a 2d array of GameObj to represent a grid of bricks.
GameObj[][] bricks = new GameObj[rows][cols] This way you can access the exact brick using its row and column position - e.g. bricks[0][0] for the first brick.
Both approaches are pretty much the same.

tile disappearing from rubiks cube with rotation

I'm working on a 2x2 rubik cube, and was having trouble getting one side rotate with my program. The cube is a 2d array of squares. I'm just triying to do a 90 degree counter clockwise turn.
This is what happens
https://imgur.com/a/tlskNKY
I changed the colour so I could see the specific squares and how they changed. I tried changing the order, moving specific pieces at a time to see if the problem was just overlapping pieces (no such luck).
//square class
public class square implements Comparable {
int c;
private Rectangle r;
int xpos, ypos, width, height;
public square(int a, int x, int y) {
c = a;
xpos = x;
ypos = y;
r = new Rectangle(xpos, ypos, 50, 50);
}
//some unused methods
}
//inside the cube class
public class cube{
square[] temp = new square[4]
square[][] sq= new square[6][4]
//two for loops make squares and fills the sq 2d array
//the result is in the imgur link
public void turnVc(){
temp= sq[2];
sq[2][0]=temp[1];
sq[2][1]=temp[3];
sq[2][2]=temp[2];
sq[2][3]=temp[0];
}
}
I expect the output to be the original image turned counter clockwise.
tmp is a pointer that points to the same object that sq[2] pointers. That's why when you change sq[2] content, you change tmp's as well.
i think instead of assign "temp= sq[2];" you should do the following:
temp = new square[4];
for (int i = 0; i < 4; i++) {
temp[i] = sq[2][i];
}
Edit:
i think a little improvement you could do is that you don;t need to save all the sq[2] array, you could only save the fist item. i would do like this (tmp is now a square, not an array):
tmp = sq[2][0];
sq[2][0] = sq[2][1];
sq[2][1] = sq[2][3];
sq[2][3] = sq[2][2];
sq[2][2] = tmp;
If your square class implements Cloneable, you should use clone() method possible, it is also similar to answer of #Nguyen Tan Bao, but shorter
I guess you 're C++ dev, reference in Java is like pointer in C++, you can research more Have fun !

How can I get the different results as I put the number?

I wanna get the different results as the inputted number.
For example, when I put 4 I get the results of the rectangle and when I put 3 I get the triangle.
import java.util.Scanner;
public class Source9_1 {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int x, y; // 클래스 Parameter(내부 변수)
Point[] v = new Point[n]
for(int i=0; i <= v.length; i++) {
v[i] = new Point();
v[i].
}
}
class Point {
int x, y; // 클래스 Parameter (내부 변수)
public void setPoint(int x, int y) { // Point 세팅
this.x = x;
this.y = y;
}
public void printPoint() { // Point 출력
System.out.println("x = " + x + ", y = " + y);
}
}
class Rectangle extends Point {
Point[] p = new Point[4];
Rectangle(Point[] p) {
this.p = p;
}
}
class Triangle extends Point {
Point[] p = new Point[3]; // 3개의 Point인스턴스를 담을 배열 생성
Triangle(Point[] p) {
this.p = p;
}
}
class Shape extends Point { // Point 배열 및 상속을 받아 세팅 후 출력가능한 클래스
Point coord[10];
static int s = 0; // 불릴 때마다 값 증가 ???
public void printShapePoint() { // 배열에 담은 Point 출력
}
public void setShapePoint() { // 배열에 담기 위해 Point 증가
}
}
So far, I coded like this but I don't know what to do now.
How can I get the different result as I put the number?
This is the result what I want
First of all, about your Rectangle and Triangle classes. I feel like you have missed your point there (pun not intended), because you've put both extending the Point class. That doesn't make much sense, since you have the Shape class, which would do a much better job as the superclass for them.
So:
class Rectangle extends Shape {
...
}
class Triangle extends Shape {
...
}
With that out of the way, what you have so far:
You are capturing the number of points from the input;
You are creating an array of that size;
You are instantiating and setting an Point object for each of the array positions.
What you need to do next:
Capture the points coordinates from the input
Set said coordinates to the Point objects
Instantiate an Triangle or Rectangle object, depending on how many points you have.
So, inside your for statement you will want to do:
for (int i=0; i <= v.length; i++) {
v[i] = new Point();
x = sc.nextInt(); // Save 'x' value into the variable
y = sc.nextInt(); // Save 'y' value into the variable
v[i].setPoint(x, y); // Set both values using the method from Point
}
Then, since both Rectangle and Triangle have Shape as a common superclass, you are allowed to put objects of either one of these class in a Shape variable. So right after the for statement you will want to do:
Shape s; // Create the empty variable here, so it will exist outside the if-else scope
if (n == 3)
s = new Triangle(v);
else
s = new Rectangle(v);
Finally, just print your points:
for (int i = 0; i < v.length; i++)
v[i].printPoint();
And that's pretty much it.
The answer from Pedro is great. I have an additional suggestion to make. Using a switch or conditional to create the different types of shapes is a bit of a code smell. I suggest using an abstract factory for this. I put up a little example of how you could do this here.
Deducing the shape from the number of points might be insufficient. For instance, a rectangle is defined by two points (not four) and so would a line, even though you are not currently modeling lines.
I think it would be more clear to select the shape by name and use a factory to instantiate it from the entered points.
Note that he shapes object hierarchy is used a lot to explain object orientation. There are several pitfalls with designing class structures like this. See for example this article. Keep in mind also the Liskov Substitution principle which is easily violated, see this article.

Fill ArrayList with objects fills with same values

I am trying to fill my empty ArrayList "circles" with objects Circle with random sizes and random locations, which I will later on paint. for loop fills array normally, but for some reason when I copy it with circ.addAll(circles) it doesn't work. I also tried to use .clone(), circ = circles,... but it ended up with either nullpoint exception error or all circles having same values. This is my code.
public class board {
public static int size = 400;
public static ArrayList<Circle> circles;
public static void fillArray(ArrayList<Circle> circ){
Random r = new Random();
int rand = r.nextInt(10)+5;
circles = new ArrayList<Circle>(rand);
System.out.println("random ="+ rand);
for(int i = 0; i< rand; i++){
circles.add(new Circle(Circle.x, Circle.y,Circle.size));
System.out.println(i+". "+ circles.get(i).x +" "+ circles.get(i).y +" size je "+ circles.get(i).size);
//fills normaly
}
circ.addAll(circles);
System.out.println("aaaaa"+circ.get(0).x);
//why same values?
System.out.println("fillArray circles= " +circ.get(0).x+circ.get(0).y+ " "+circ.get(1).x);
}
public static void main(String[] args) {
fillArray(circles);
}
my Circle class looks like this:
public class Circle {
public static int x,y;
public static int size;
public Circle(int x, int y, int size) {
this.x = randomLoc();
this.y = randomLoc();
this.size = randomSize();
}
public static int randomSize (){
int min = 15;
int max = 30;
Random r = new Random();
int rand = r.nextInt(max)+min;
return rand;
}
public static int randomLoc(){
int min = 12;
int max = board.size;
Random r = new Random();
int rand = r.nextInt(max)+min;
return rand;
}}
I am trying to fill my empty ArrayList "circles" with objects Circle with random sizes and random locations
But you're not doing that. The line
circles.add(new Circle(Circle.x, Circle.y,Circle.size));
adds a Circle with static field values. Presumably, your Circle class has something like this:
public class Circle {
public static int x, y, size; // perhaps with some initialized values
public Circle(int x, int y, int size) { /* ... */ }
}
So you add the same values to all the circles in the list. To randomize the size and location you would need to use the Random instance you created. Something like:
circles.add(new Circle(r.nextInt(10)+5, r.nextInt(10)+5, r.nextInt(10)+5));
For loop fills array normally, but for some reason when I copy it with circ.addAll(circles) it doesn't work.
You are confusing the 2 lists you created - circ and circles. You are passing the reference ArrayList<Circle> circles to the method, which is named circ inside the method scope. This is redundant since you can access the static circles from within the method without passing it as an argument. I suggest you solve your design issues before anything else.
What you probably want to do it initialize circ:
circ = new ArrayList<Circle>();
and note that the argument passed to the constructor is the initial capacity, which is a performance parameter, and almost certainly shouldn't be random.
Once you do that, the line circ.addAll(circles); is meaningless and should be removed. Just print circ to see the values (#Override Circle's toString).
Note: It's recommended to use the interface and not the implementation to hold the reference: List<Circle> list = new ArrayList<>();. You shouldn't care about the implementation details when all you do are list operations.
circ.addAll(circles) may not be working properly because it is only making a shallow copy and adding it to the arraylist. A shallow copy is a only a copy of the pointers of the original data, not the data itself. There may be errors happening behind the scenes because of this. Try adding the circle objects by creating a deep copy with the actual data.

Substitute rectangle objects on screen when 10 rectangles are reached?

I need to create a class that displays 10 rectangles on the canvas, each with a random color and position. When it reaches 11, the first rectangle is replaced with a new random color and position. 12th rect replaces the 2nd box, and so on. I am using the acm.jar for this, http://jtf.acm.org/javadoc/student/index.html.
import acm.graphics.*;
import acm.program.*;
import java.awt.Color;
import java.util.Random;
public class Rect extends GraphicsProgram
{
public void run()
{
final int width = 800;
final int height = 600;
final int boxWidth = 50;
final int maxBoxes = 10;
this.setSize(width, height);
Random random = new Random();
for(;;) {
int x = random.nextInt(width-boxWidth);
int y = random.nextInt(height-boxWidth);
Color c = new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255));
GRect r = new GRect(x, y, boxWidth, boxWidth);
r.setFilled(true);
r.setLocation(x, y);
r.setFillColor(c);
this.add(r);
this.pause(100);
}
}
}
I already figured out how to make the colors random, I cant figure out how I will substitute the boxes with the old ones.
EDIT:::--------------------------------------------------------------------------------
I did manage to get it working with the help of the guys below. Here is what the new for loop looks like:
for(;;) {
int x = random.nextInt(width-boxWidth);
int y = random.nextInt(height-boxWidth);
Color c = new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256));
GRect r = new GRect(boxWidth, boxWidth);
r.setFilled(true);
r.setLocation(x, y);
r.setFillColor(c);
add(r, x, y);
int n = getElementCount();
if (n>maxBoxes)
{
remove(getElement(0));
}
this.pause(100);
}
One thing I dont understand is why the remove(getElement(0)) works,, how does the element change its index once one is removed? If I have 10 elements 0-9, and I remove element(0) why does the other elements change its index?
This really looks like homework , so I won't do it for you but give some clues.
You can use the getElementCount() method to know the current number of rectangles in your frame.
Create a list of GObjects, and populate it with your rectangles as you create them.
Once you reach ten, the process becomes
remove rectangle from screen using remove(GObject gobj)
remove first element, add to end of list.
And here you are :)
You need to store the list of rectangles drawn so far. Every time you add a new rectangle, if the list is already 10 rectangles long, remove the first rectangle and add a new one. Then you need to redraw ALL rectangles every time you refresh the display, using double buffering to prevent screen flickering.

Categories