i have some trouble with deep copying.
I have this java project, chess, and I need to use the clone() method, because I need to try new configurations without changing the board.
Board scacchiera = new Board();
Initialization(scacchiera);
Board clone = scacchiera.clone();
System.out.println(scacchiera.toString());
System.out.println(clone.toString());
I create an object, scacchiera, then I clone it. I think I have done correctly a deep copy, but when I change something in scacchiera, clone changes too.
In object Board:
public class Board implements Cloneable{
//TODO
//rivedere se check e checkmate public o private;
//se private, costruire get e set;
public Pedine[][] board;
public boolean check;
public boolean checkmate;
//creating 2 lists for all the pieces; Neri=black, Bianchi=White
public ArrayList<Pedine> Neri;
public ArrayList<Pedine> Bianchi;
public Board(){
this.board = new Pedine [8][8];
this.check = false;
this.checkmate = false;
this.Neri = new ArrayList<Pedine>();
this.Bianchi = new ArrayList<Pedine>();
}
...
#Override
public Board clone() throws CloneNotSupportedException{
Board cloned = (Board) super.clone();
cloned.board = (Pedine[][]) board.clone();
return cloned;
}
I have this double array of Pedine, and I have to clone it too, so I do:
public class Pedine implements Cloneable{
private int x;
private int y;
private Piece pezzo;
private Colour colore;
...
#Override
public Pedine clone() throws CloneNotSupportedException{
return (Pedine) super.clone();
}
Why it doesn't work?
I tried this code too, but it doesn't work.
#Override
public Board clone() throws CloneNotSupportedException{
Board cloned = (Board) super.clone();
cloned.board = (Pedine[][]) board.clone();
for (int i=0; i<8; i++)
for(int j=0; j<8; j++){
cloned.board[i][j] = board[i][j].clone();
}
return cloned;
}
(Pedine extends Object)
The problem, as sharonbn indicates, is in the double-array. While you can clone it manually with a double-loop, your chess engine is going to suffer a performance penalty: you will be cloning a lot of boards, and you can benefit from making them a lot easier to copy around.
One option is to use a flat array and some clever addressing to speed things up:
private Piece[] board; // 64 Pieces in there
public Piece at(col, row) {
if (row < 0 || row >= 8 || col < 0 || col >= 8) return null;
return board[col + row*8];
}
Now, instead of accessing board[row][col] you use at(col, row). And copying and creating boards is a lot easier:
board = other.board.clone();
... should now work as expected.
I also strongly recommend having immutable pieces, with no state information whatsoever. Your current pieces have an x and y field, for example. What do they need those for? You should tell them their actual positions only while moving them; that way, you don't need to clone pieces at all -- because all pawns are exactly alike, and you can actually use the same "black pawn" for everything black-pawn related.
deep cloning of multi dimension arrays should be custom coded, as is explained here
Related
I know everyone gets skeptical whenever people put homework on here but I've run out of options and could really use some direction. I have a project where I have to create a deck of cards and allow the user to pick the size of the hand and then fill that hand with random cards and display that to the user. I've found plenty of answers using ArrayLists but mine requires an array and I've tried everything I know and my code is either completely wrong or throws a bunch of errors.
So here are the problems I have:
1) The addCard method in the Hand class can be used to add one Card object at a time to the hand array until it is full. It should increment the cardsInHand counter each time a Card object is added to the Hand as long as there is room for the Card to fit into the Hand.
Here is the code for the Hand class:
public class Hand
{
private int handSize; //Holds the size of the hand
private int cardsInHand; //Holds the number of cards allowed in the hand
private Card[] hand; //Array of card objects
public Hand()
{
this.handSize = 5;
this.cardsInHand = 0;
this.hand = new Card[52];
}//end Default Constructor
public Hand(int handSize)
{
this.handSize = handSize;
}//end Parameterized Constructor
public Hand(Hand handIn)
{
this.handSize = handIn.handSize;
this.cardsInHand = handIn.cardsInHand;
this.hand = handIn.hand;
}//end Copy Constructor
public void addCard(Card card)
{
hand[card]; //--> throws a type mismatch exception (change card param to an int)
}//end addCard()
public int getHandSize()
{
return handSize;
}
public void setHandSize(int handSize)
{
this.handSize = handSize;
}
public int getCardsInHand()
{
return cardsInHand;
}
public void setCardsInHand(int cardsInHand)
{
this.cardsInHand = cardsInHand;
}
public Card[] getHand()
{
return hand;
}
public void setHand(Card[] hand)
{
this.hand = hand;
}
public String toString()
{
String msg = "";
return msg;
}//end toString()
}//end class
My addCard method is just all janky and I could really use some help trying to fill it so my program works. Any help or even a pointing in the right direction would be appreciated!
My addCard method is just all janky and I could really use some help trying to fill it so my program works. Any help or even a pointing in the right direction would be appreciated
Sometimes the best thing to do is stop, turn the screen off, get a pen and piece of paper and just nut it out without any code. Try to understand the problem and get the logic straight in your head.
Basically, you have a series of buckets into which you can put a Card. Before you can put a Card in a bucket, you need to know if you have any free buckets available.
If there are, you need to add the Card to the next available bucket (which should be pointed to by cardsInHand) and increment cardsInHand
Your error is because you're trying reference a "bucket" using a Card, but you can only reference a "bucket" by an index (number) so...
hand[card];
should be more like...
hand[cardsInHand] = card;
but only after you've determined if there is a free "bucket" available, and you should increment cardsInHand AFTER this statement
I'd also be worried about your constructors
public Hand(int handSize)
{
this.handSize = handSize;
}//end Parameterized Constructor
isn't initialising hand, so that's going to be null. A better solution might be to use existing constructors where possible to build a common "initialisation" path
public Hand() {
this(5);
}//end Default Constructor
public Hand(int handSize) {
this.handSize = handSize;
this.cardsInHand = cardsInHand;
this.hand = new Card[handSize];
}//end Parameterized Constructor
Also
public Hand(Hand handIn)
{
this.handSize = handIn.handSize;
this.cardsInHand = handIn.cardsInHand;
this.hand = handIn.hand;
}//end Copy Constructor
is worrying, as it's possible for some external class to make a change to handIn's hand and that change will be reflected by this instance as well (as they are pointing to the same array).
A "copy" constructor should be making a "copy" of the data. Realistically, this should probably be a "deep" copy, so any changes to Card don't mess with the Hand as well, but I'll start with a simple "shallow" copy to get you started
public Hand(Hand handIn) {
this.handSize = handIn.handSize;
this.cardsInHand = 0;
this.hand = new Card[this.handSize];
// Yes, I know there is a better way to do this, but
// I want the OP to learn something
for (int index = 0; index < handIn.hand.length; index++) {
Card card = handIn.hand[index];
if (card != null) {
hand[cardsInHand] = card;
cardsInHand++;
}
}
}//end Copy Constructor
#MadProgrammer already give better answer, I only want to chime a little. Knowing the OP project assignment using Java I want to comment a little about the Hand class design.
The task clearly said that user can pick hand with custom size, then the user will add card into the hand until the hand is full. Thus, I would propose the Hand class design like below.
public class Hand {
private int size; // Hold the amount of card can be hold by hand.
private int counter; // Count how many card added.
private Card[] cards; // The card on hand.
public Hand(int size) {
this.counter = 0;
this.size = size;
this.cards = new Card[size];
}
public void addCard(Card card) {
if (this.counter > this.size) {
throw new IllegalStateArgument("The hand is full of card!");
}
this.cards[this.counter] = card;
this.counter++;
}
public String show() {
StringBuilder result = new StringBuilder("The card on hand is: \n");
for (int i=0; i<this.size; i++) {
result.append(this.cards[i].toString()).append("\n");
}
return result.toString();
}
}
In my opinion the Hand class more easy to understand and achieve the goals of the Hand purpose from the task. However, just use this as reference and write code that you understand well.
I'm currently working on a Bukkit plugin to claim custom areas, and I'm using rectangles (and .intersect()) to check if regions overlap before creating a claim.
I'm trying to figure a way where I don't need to check every single existing claim (of which there eventually will be tens of thousands) as surely this will take quite some time. I'll also need to check for claim owners when players do things such as break blocks or place blocks.
In my current system (which doesn't allow custom claim sizes, only squares) I only need to check at most about 10 claims because I can detect claims within the vicinity of the claim (at most 64 blocks away which is the max radius of claims in this system) but now the claim sizes can be infinitely large in theory with the new system.
Is checking all the rectangles going to take a massive amount of time? Am I being dumb, is there a way to check for rectangles within the vicinity even while the size is unlimited?
First of all checking thousands of rectangles is not gonna be a big deal for java(or your Plugin). Its simple math and should be done in millisecs. To deal with your owner Problem i would recommend you to create my own rectangle and owner class. So your rectangle can have a defined owner and you can simply check if the player is the owner of the area he is in right now.
public class custom_Area extends Rectangle{
private owner o;
public owner getOwner() {
return o;
}
public void setOwner(owner o) {
this.o = o;
}
}
EDIT:
I just tested it by creating 100.000 random rectangles and checking if one of them intersects with others.
--Custom rectangle class
public class area extends Rectangle{
private owner o;
public area(owner o, int i, int i1, int i2, int i3) {
super(i, i1, i2, i3);
this.o = o;
}
public owner getO() {
return o;
}
public void setO(owner o) {
this.o = o;
}
}
--Custom owner class
public class owner {
String name;
public owner(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
--Main class
public class Rectanglesearch {
public static area a[] = new area[100000];
public static owner o[] = new owner[10];
public static int intersectCounter = 0;
public static int ownerCounter = 0;
public static void main(String[] args) {
for(int y = 0; y<10;y++){
o[y] = new owner("y");
}
for (int i = 0; i < 100000; i++) {
a[i] = new area(o[(int)(Math.random() * 10)],random(),random(),random(),random());
}
checkArea(a[10]);
checkOwner(o[3]);
System.out.println("Area a[10] intersects with "+intersectCounter+" out of "+a.length);
System.out.println("Owner o[3] owns "+ownerCounter+" areas out of "+a.length);
}
public static int random(){
return (int)(Math.random() * 100000) + 1;
}
public static void checkArea(area ab){
for (area a1 : a) {
if (ab.intersects(a1)) {
intersectCounter +=1;
}
}
}
public static void checkOwner(owner ob){
for (area a1 : a){
if(a1.getOwner()==ob){
ownerCounter +=1;
}
}
}
}
method checkArea(area ab) returns you how man areas intersects with area ab
method checkOwner(owner ob) return you how man areas are owned my ob
Consider storing your rectangles in an acceleration structure such as a quadtree. To test a new rectangle against the existing set, you'd navigate down the tree to the node that would contain it, testing against the rectangles in each node along the way, but ignoring the rectangles in all the nodes you don't traverse. This quickly eliminates lots of rectangles that can't possibly intersect the new one, without having to test each one individually.
Other acceleration structures are also possible as alternatives, such as binary space partitioning. Read about spatial indexes for a list of several others that may be relevant.
Adding new rectangles to the set doesn't happen very often, so performance probably isn't a big concern. But I'd imagine that your plugin also needs to check whether a specific coordinate (such as a block) is within one of the claimed regions, and that may happen much more often — potentially every frame — so it really does need to be fast. A quadtree or other acceleration structure will be valuable for that.
So I've been stuck on this issue for quite some time now and I just can't seem to figure out the solution. I'm currently working on a project that simulates a parking garage. The parking garage itself isn't the issue; it's the several types of customers that are supposed to be simulated. To make things a little easier I'll ask for the solution of one and with that I should be able to work out the others myself.
For starters it is a requirement to create a separate class for customers with a parking pass and integrate this in a way that shows which cars are parking pass holders and which aren't.
import java.util.Random;
/* creates a boolean called isPass that is randomly picked to be true or false. */
public interface ParkPass {
public Random rnd = new Random();
public boolean isPass = rnd.nextBoolean();
}
This is the class that allows me to randomly set a parking pass. Since the simulation happens through a different class, all I can do is create the method to set the Pass to true or false; I can't set the Pass itself in this class.
public abstract class Car {
private Location location;
private int minutesLeft;
public boolean isPaying;
public boolean isBlue;
public void setIsPaying(boolean isPaying) {
this.isPaying = isPaying;
}
// added a method to allow us to set the colour of the car to blue for when they have a parking pass.
public void setIsBlue(boolean isBlue) {
this.isBlue = isBlue;
}
This is a small snippet of the Car class that shows which booleans belong to it and might show you which direction I'm trying to go with this simulation.
public class AdHocCar extends Car implements ParkPass{
public AdHocCar() {
setIsBlue(isPass);
setIsPaying(!isPass);
}
}
This is the class that is called when simulating a car going in and out of the parking garage. Here you can see I tried implementing the ParkPass class in order to set the Isblue and IsPaying booleans in the Car class so that I can call upon these in the next bit of code which is the simulation view that I'm currently stuck on trying to fix.
import javax.swing.*;
import java.awt.*;
public class SimulatorView extends JFrame {
private CarParkView carParkView;
private int numberOfFloors;
private int numberOfRows;
private int numberOfPlaces;
private Car[][][] cars;
public void updateView() {
/* Create a new car park image if the size has changed.
added 2 colours to show the difference between the three different customer types.*/
if (!size.equals(getSize())) {
size = getSize();
carParkImage = createImage(size.width, size.height);
}
Graphics graphics = carParkImage.getGraphics();
for(int floor = 0; floor < getNumberOfFloors(); floor++) {
for(int row = 0; row < getNumberOfRows(); row++) {
for(int place = 0; place < getNumberOfPlaces(); place++) {
Location location = new Location(floor, row, place);
Car car = getCarAt(location);
Color color = car == null ? Color.white : Car.isBlue ? Color.blue /*: isReservation == true ? Color.green*/ :Color.red ;
drawPlace(graphics, location, color);
}
}
}
repaint();
}
And here we finally get to the problem I have been facing. If you look at it right now you'll probably notice quite a few things wrong. This is because after 10 hours of research and constant changing of the Color attribute I kind of lost track of the exact way I was trying to implement the booleans that were created earlier in order to show the difference between the two types of customer. I'm not extremely experienced with programming so after awhile I just gave in and decided to ask here.
Now for the question, with all these separate classes creating their own booleans how can I make sure that when I use the simulation the cars using a Parking Pass will be blue while the cars that have to pay normally are shown as red?
public interface ParkPass {
public Random rnd = new Random();
public boolean isPass = rnd.nextBoolean();
}
Problem is in the above part. You can not define instance variables in interfaces. These members becoming static final as default.
Move this members to Car class and it will work.
I'm using a arraylist to add states(the board state for the 8 puzzle). My problem is when I get the children of the state it changes the values stored in my array list. I'm assuming this is because ArrayList just stores pointers to the objects and not the values themselves. In order to fix this I create a new object every time before I store it into the ArrayList but I'm still having the same problem.
I will also try to follow naming conventions more often thanks for the tip.
private ArrayList<int[][]>VisitedBoard;
if(RuleNumber ==2){
//Here is my problem. This will change what is stored in VistedBoards
NextState = new State(FireRule.Rule2(WM.get_Board()));//Fire Rule
for(int j=0;j<VisitedBoards.size();j++){
//Meaning this will always be true
if(Arrays.equals(VisitedBoards.get(j), NextState.get_Board())){
Loop =true; //Loop to previous state
}
if(j==VisitedBoards.size()-1 && Loop ==false){ //If the next state is not any previously visited
NotALoop =true;
VisitedBoards.add(NextState.get_Board());
WM.set_Board(NextState.get_Board());
}
}
}
public int[][] Rule2(int [][] Board){//The FireRule Class
Find_BlankLocation(Board);
int temp;
State NewState;
temp = Board[BlankLocation[0]-1][BlankLocation[1]];
Board[BlankLocation[0]-1][BlankLocation[1]] = 0;
Board[BlankLocation[0]][BlankLocation[1]] = temp;
NewState = new State(Board);
return Board;
}
public class State { //State class
private int[][] Board;
private int[][] Goal;
private Boolean GoalFound;
public State(int[][] Start, int[][] goal){
Board = Start;
Goal = goal;
GoalFound=false;
}
public State(int[][] NewState){
Board=NewState;
}
public int[][] get_Goal(){
return Goal;
}
public int[][] get_Board(){
return Board;
}
public void set_Board(int[][] board){
Board = board;
}
public Boolean get_GoalFound(){
return GoalFound;
}
}
Containers like ArrayList work the same in all languages: they are called data structures because they organize storage/retrieval of objects. Obviously they don't store the fields of the objects themselves.
Trying to interpret your problem, maybe you don't want to share the boards between the list of visitedBoards and WM (whatever it means...). Then simply implement get_Board() to return a copy of the array instead of the Board object itself:
public int[][] get_Board(int[][] src) {
int[][] dst = new int[src.length][src[0].length];
for (int i = 0; i < src.length; i++) {
System.arraycopy(src[i], 0, dst[i], 0, src[i].length);
}
return dst;return dst;
}
Beside this, as others already told you, you'd really better to adopt the standard Java naming conventions, use meaningful names, and encapsulate your x, y and int[][] in real application classes.
Presumably, the new State object contains a pointer to the same arrayList as before. You'll want to manually copy the array out to a new one (a "deep clone" or "deep copy" as it is called). You might find this useful: Deep cloning multidimensional arrays in Java...?
Every time you create a new instance of State, you pass it the same array (whatever is returned by WM.get_Board()).
You then add that same array to VisitedBoards when you call VisitedBoards.add().
The fact that you're creating new State objects is irrelevant, because only the return value of NextState.get_Board() gets added to the list.
As a result, the list VisitedBoards always contains several references to the exact same array.
As Raffaele has suggested, you'll be fine if you make sure get_Board() returns a copy of the array in stead of a reference to the original (assuming that doesn't mess up logic that exists elsewhere).
The main thing I learned from this question is how important it is to follow naming conventions.
Your unconventional capitalization has made me dizzy!
Following these rules will make it much easier for others to understand your Java code:
class names should be capitalized (ie PascalCase)
variable names should be lowercase (ie camelCase)
do not use underscores in method names, class names, or variable names (they should only be used for constants)
always use meaningful names when possible
My advice is to create your own container object for their 2D array and implement deep copying.
For example:
package netbeans;
import java.util.Arrays;
public class Container
implements Cloneable
{
private int [] _data;
private int _sx;
private int _sy;
public int get(int x, int y)
{
try { return this._data[y*this._sx+x]; }
catch (Exception e) { throw new ArrayIndexOutOfBoundsException(); }
}
public void set(int x, int y, int value)
{
try { this._data[y*this._sx+x] = value; }
catch (Exception e) { throw new ArrayIndexOutOfBoundsException(); }
}
public Object Clone() { return new Container(this); }
public Container(int sizeX, int sizeY, int [] data)
{
this._sx = sizeX;
this._sy = sizeY;
this._data = data;
}
public Container(Container cont)
{
this._data = Arrays.copyOf(cont._data, cont._data.length);
}
}
I recently came across a very stupid (at least from my point of view) implementation inside Androids Parcel class.
Suppose I have a simple class like this
class Foo implements Parcelable{
private String[] bars;
//other members
public in describeContents(){
return 0;
}
public void writeToParcel(Parcel dest, int flags){
dest.writeStringArray(bars);
//parcel others
}
private Foo(Parcel source){
source.readStringArray(bars);
//unparcel other members
}
public static final Parcelable.Creator<Foo> CREATOR = new Parcelable.Creator<Foo>(){
public Foo createFromParcel(Parcel source){
return new Foo(source);
}
public Foo[] newArray(int size){
return new Foo[size];
}
};
}
Now, if I want to Parcel a Foo Object and bars is null I see no way to recover from this situation (exept of catching Exceptions of course). Here is the implementation of these two methods from Parcel:
public final void writeStringArray(String[] val) {
if (val != null) {
int N = val.length;
writeInt(N);
for (int i=0; i<N; i++) {
writeString(val[i]);
}
} else {
writeInt(-1);
}
}
public final void readStringArray(String[] val) {
int N = readInt();
if (N == val.length) {
for (int i=0; i<N; i++) {
val[i] = readString();
}
} else {
throw new RuntimeException("bad array lengths");
}
}
So writeStringArray is fine if I pass bars which are null. It just writes -1 to the Parcel. But How is the method readStringArray supposed to get used? If I pass bars inside (which of course is null) I will get a NullPointerException from val.length. If I create bars before like say bars = new String[???] I don't get any clue how big it should be. If the size doesn't match what was written inside I recieve a RuntimeException.
Why is readStringArray not aware of a result of -1 which gets written on null objects from writeStringArray and just returns?
The only way I see is to save the size of bars before I call writeStringArray(String[]) which makes this method kind of useless. It will also redundatly save the size of the Array twice (one time for me to remember, the second time from writeStringArray).
Does anyone know how these two methods are supposed to be used, as there is NO java-doc for them on top?
You should use Parcel.createStringArray() in your case.
I can't imagine a proper use-case for Parcel.readStringArray(String[] val) but in order to use it you have to know the exact size of array and manually allocate it.
It's not really clear from the (lack of) documentation but readStringArray() is to be used when the object already knows how to create the string array before calling this function; for example when it's statistically instanciated or it's size is known from another previously read value.
What you need here is to call the function createStringArray() instead.