Hello. I'm trying to implement a program that generates the game tree
for this game,
http://www.everything2.org/index.pl?node_id=1314953&lastnode_id=1140332
.
I think I'm having difficulties understanding what constructors do when
called from within an instance of the class being constructed. In
particular, I would expect this:
GameState[] generateChildren(){
int count=0;
GameState[] children = new GameState[hands*hands+1];//the number of
children = hands^2+1 for splits
for(int i=0;i<hands;i++){
for(int j=0;j<hands;j++){
children[count]=new GameState(i,j,this); //this should make a new
GameState with hand
//this.state[0][i]for p1 added to hand j for p2 or
//vice versa if
//turn==false
}
}
...
to make a new array of GameStates without changing the GameState in
which this method is being called. But when I run it, I find that it is
changing the GameState itself.
Below is the entire GameState class. I know I don't have good style,
and that this is probably some silly issue that I should understand,
but I am stumped. Thanks in advance for your help.
package fingernumbers;
import java.util.HashSet;
public class GameState {
int hands; //this is the number of hands
int fingers;//this is the number of fingers on each hand
int[][] state;//this holds the number of fingers up on each hand
boolean turn;//this holds whose turn it is. true = 1st
player(state[0][]), false = 2nd (state[1][])
boolean victory=false;
volatile HashSet<GameState> linkTo; //this holds any GameStates with
this as a child.
GameState[] children; //this holds all the GameStates that can be made
from this one.
//this constructor is just for creating the initial state
GameState(int hands, int fingers){
this.hands = hands;
this.fingers= fingers;
turn=true;
state = new int[2][hands];
for(int i=0;i<hands;i++){
state[0][i]=1;
state[1][i]=1;
}}
//this constructor combines hands of the parent gamestate to make a
new child
GameState(int p1,int p2,GameState parent){
state=parent.state;
hands=parent.hands;
fingers=parent.fingers;
turn=!parent.turn;
if(turn){ //turn==true means it is p1's
turn
state[1][p2]=state[1][p2]+state[0][p1];
if(state[1][p2]>=parent.fingers)
state[1][p2]=fingers;
}
else{ //turn==false means p2's turn
state[0][p1]=state[0][p1]+state[1][p2];
if(state[0][p1]>=parent.fingers)
state[0][p1]=fingers;
}
//sorting the hands to ascending order of fingers up
int sortWhich=0;
if(turn)
sortWhich=1;
int tempHolder=0;
for(int i=0;i<hands;i++){
for(int j=i+1;j<hands;j++){
if(state[sortWhich][i]>state[sortWhich][j]){
tempHolder=state[sortWhich][i];
state[sortWhich][i]=state[sortWhich][j];
state[sortWhich][j]=tempHolder;
}
}
}
}//end constructor
//this constructor splits the remaining hand of the player whose turn
it is
GameState(GameState parent,int indexSplit){
state=parent.state;
hands=parent.hands;
fingers=parent.fingers;
turn=!parent.turn;
int newFingers=state[0][indexSplit]/hands;
if(turn){
for(int i = 0;i<hands;i++){
state[0][i]=newFingers;
}
}
else
{ for(int i = 0;i<hands;i++){
state[1][i]=newFingers;
}}
}
//this returns the GameStates for the children of the current game
GameState[] generateChildren(){
int count=0;
GameState[] children = new GameState[hands*hands+1];//the number of
children = hands^2+1 for splits
for(int i=0;i<hands;i++){
for(int j=0;j<hands;j++){
children[count]=new GameState(i,j,this); //this combines the hands of
each player
}
//this part checks for a split
count=0;
int indexSplit=0;
int turnIndex=0;
if(turn)
turnIndex=1;
for(int i=0;i<hands;i++){
if(state[turnIndex][i]==0)
count++;
else
indexSplit=i;
}
if(count==hands-1){
if(state[turnIndex][indexSplit]/hands==(double)state[turnIndex][indexSplit]/hands)
children[children.length-1]=new GameState(this,indexSplit);
}
//this removes equal GameStates from children
count=children.length;
int[] indexRemoved = new int[children.length];
for(int i=0;i<hands;i++){
for(int j=i+1;j<hands;j++){
if(children[i]==children[j]){
indexRemoved[j]=1;
count--;
}
}
}
GameState[] finishedChildren = new GameState[count];
count=0;
for(int i=0;i<hands;i++)
if(indexRemoved[i]==0){
finishedChildren[count]=children[i];
count++;
}
this.children=finishedChildren;
return finishedChildren;//return the simplified children
}
public boolean victory(){
int turnIndex=0;
if(turn)
turnIndex=1;
int count=0;
for(int i=0;i<hands;i++)
if(state[turnIndex][i]==fingers)
count++;
if(count==hands)
return true;
else
return false;
}
public boolean equals(Object obj){
if(this==obj)
return true;
if((obj==null)||obj.getClass()!=this.getClass())
return false;
//object must be GameState here
GameState check = (GameState)obj;
return turn==this.turn&&state==this.state;
}
public String toString(){
String returnString="";
for(int j=0;j<2;j++){
returnString=returnString+'\n';
for(int i=0;i<hands;i++){
returnString=returnString+state[j][i]+",";
}
} return returnString;
}
}
public class Main {
public static void main(String[] args) {
GameState game = new GameState(2,5);
GameState[] children=game.generateChildren();
System.out.println(game);
for(int i=0;i<children.length;i++){
System.out.println(children[i]);
}
}
}
Florian Weimer - 09 Jan 2007 12:45 GMT
* jules khan:
> //this constructor combines hands of the parent gamestate to make a
> new child
> GameState(int p1,int p2,GameState parent){
> state=parent.state;
You share the state with the parent. You need to clone the state
object, or otherwise allocate a new object.
jules khan - 10 Jan 2007 05:38 GMT
> * jules khan:
>
[quoted text clipped - 5 lines]
> You share the state with the parent. You need to clone the state
> object, or otherwise allocate a new object.
Thanks
Oliver Wong - 09 Jan 2007 23:22 GMT
> Hello. I'm trying to implement a program that generates the game tree
> for this game,
> http://www.everything2.org/index.pl?node_id=1314953&lastnode_id=1140332
> .
Florian already answered your question, but I just wanted to point out
that either you'll either end up with a tree of infinite depth, or you
should change your tree into a graph with cycles. The reason being that the
game described allows you to re-enter a state you've already been in.
- Oliver
Lew - 09 Jan 2007 23:42 GMT
[snip]
You should format code samples for readability on Usenet. That means generally
following Sun's code conventions and not using TAB characters embedded in your
posts.
- Lew
strangegod@gmail.com - 10 Jan 2007 11:45 GMT
> [snip]
>
[quoted text clipped - 3 lines]
>
> - Lew
Duly noted
jules khan - 10 Jan 2007 05:37 GMT
> > Hello. I'm trying to implement a program that generates the game tree
> > for this game,
[quoted text clipped - 7 lines]
>
> - Oliver
I'm planning on dealing with that by keeping track of each node's
lineage and creating repeated nodes in the lineage as draws, which
don't have children.
I'm definitely butchering the elegant way to hold graph information,
but maybe it will work.
Thanks for your advice,