In my program you can place pictures on the applet if you have the required minerals
you start with 400 and each one is 100 minerals so you place 3 and then on the 4th it will delete all the others
public int Minerals
//Pylons
int xCoord[];
int yCoord[];
int numSquare;
boolean firstPaint;
public void init()
{
Minerals = 400;
pylon = getImage(getDocumentBase(),"image/pylon.png");
//pylons
xCoord = new int[100];
yCoord = new int[100];
numSquare = 0;
firstPaint = true;
}
public void paint(Grapics g)
{
pylons(g);
}
public void pylons(Graphics g)
{
//Building the pylons
if(Minerals >= 100)
{
for (int k = 0; k < numSquare; k++)
{
g.drawImage(pylon,xCoord[k],yCoord[k],85,85,this);
//Makes cursor normal.
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
}
//Checks if buildPylon is 1 if so it will draw the infoScreen and then set the cursor to pylon
if(buildPylon == 1)
{
g.drawImage(pylon,510,820,100,100,this);
//Use the custom cursor
setCursor(cursor);
}
}
private void handlePylonPlacement()
{
//This takes away 100 minerals and will add 9 population and make buildPylon 0 again
if(decrementMinerals(100))
addPopMax(9);
buildPylon = 0;
}
private boolean decrementMinerals(int amount)
{
//This Is where it takes away the minerals
if(Minerals - amount >= 0) // prevent situation where you go into negative minerals
{
Minerals -= amount;
return true;
}
else
return false;
}
private void addPopMax(int amount)
{
//Add the population (9)
if(popMax + amount <= 72) // restrict addition to pop-max to a sane upper bound
popMax += amount;
}
public boolean mouseDown(Event e, int x, int y) {
//Makes the ints xCoord2 to equal x and same for the other
xCoord2 = x;
yCoord2 = y;
repaint();
if (numClicks == 10) {//Title screen
numClicks++;
repaint();
}
//Checks to see if buildPylon == 1 then builds the pylon if its in the correct place.
if(buildPylon == 1)
{
if(x > 1 && x < 1275 && y > 711 && y < 948) // Checks to see if the person clicked in this area
{}
else if(x > 378 && x < 876 && y < 568 && y < 705) // Checks to see if the person clicked in this area
{}else if (Minerals >= 100)
{
xCoord[numSquare] = x;
yCoord[numSquare] = y;
numSquare++;
handlePylonPlacement(); // call your new handler
repaint();
}
}
return true;
}
Instead of it deleting them i want the pylons to stay painted on the screen... any help?
In handlePylonPlacement(), did you mean
private void handlePylonPlacement()
{
//This takes away 100 minerals and will add 9 population and make buildPylon 0 again
if (decrementMinerals(100)) {
addPopMax(9);
buildPylon = 0;
}
}
?
Related
I am a beginner in Java as well as OOP.
I am creating a simulator of "a box with particles". Here's what required in the program:
A box with fixed WIDTH & HEIGHT with the pattern of "-" and " | "
Particles with x, y position (0 <= x <= WIDTH; 0 <= y <= HEIGHT). Symbol: *
Enum Direction of 8 directions
move() all particles in random direction and create a new particle if any of them collide (same position)
What I've been strugging to find the answer is that how can I create random number of particles with a loop and can still work on them outside the loop? Because I want each created particle remain after an iteration for further move() execution. Is there any syntax for this kind of access?
Here's what I've tried as this sometimes output 2, 3 particles, sometimes none:
public Box() {
particle = new Particle();
for (int i = 0; i <= HEIGHT + 1; i++) {
for (int j = 0; j <= WIDTH + 1; j++) {
if (i == 0 || i == HEIGHT + 1 && i != particle.getY()){
System.out.print("-");
} else {
if (j == particle.getX() && i == particle.getY()) {
System.out.print("*");
} else if (j == 0 || j == WIDTH + 1 && j != particle.getX()) {
System.out.print("|");
} else if (i != 0 && i != HEIGHT + 1) {
System.out.print(" ");
}
}
}
System.out.println("");
}
}
Coding is easier if you break the large task into smaller tasks.
I separated the creation of the particles from the display of the particles. That way, I could focus on one part of the task at a time.
Here's the output I generated.
|------------------|
| * |
| |
| * * * * |
| * * |
| * * |
| * * * * |
| * |
| * * |
|------------------|
All I did was generate the initial condition. I'm leaving it up to you to move the particles and check for collisions. I'm assuming that once a particular particle moves south, as an example, it continues south until it hits another particle or the wall. Hitting the wall would change the direction to north.
My Eclipse generated the hashCode and equals methods of the Particle class. These methods are essential for the Set contains method to work. I used a Set so there would be no duplicate particles. Because the particles are generated randomly, there might not be all maximum particles in the simulation.
In the generateParticles method, I get a random w between 1 and WIDTH - 1, inclusive, and a random h between 1 and HEIGHT -1, inclusive. This ensures that all particles created are inside the "box".
Here's the complete runnable example code.
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
public class ParticleSimulator {
public static void main(String[] args) {
ParticleSimulator ps = new ParticleSimulator();
ps.displaySimulation();
}
private static int WIDTH = 20;
private static int HEIGHT = 10;
private Random random;
private Set<Particle> particles;
public ParticleSimulator() {
this.random = new Random();
this.particles = generateParticles(20);
}
private Set<Particle> generateParticles(int maximum) {
Set<Particle> particles = new HashSet<>();
for (int i = 0; i < maximum; i++) {
int x = random.nextInt(WIDTH - 1) + 1;
int y = random.nextInt(HEIGHT - 1) + 1;
Particle particle = createParticle(x, y);
particles.add(particle);
}
return particles;
}
public void displaySimulation() {
for (int h = 0; h < HEIGHT; h++) {
for (int w = 0; w < WIDTH; w++) {
if (w == 0 || w == (WIDTH - 1)) {
System.out.print('|');
continue;
}
if (h == 0 || h == (HEIGHT - 1)) {
System.out.print('-');
continue;
}
Particle particle = createParticle(w, h);
if (particles.contains(particle)) {
System.out.print('*');
} else {
System.out.print(' ');
}
}
System.out.println();
}
}
private Particle createParticle(int x, int y) {
Particle particle = new Particle();
particle.setX(x);
particle.setY(y);
return particle;
}
public class Particle {
private int x;
private int y;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result +
getEnclosingInstance().hashCode();
result = prime * result + x;
result = prime * result + y;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Particle other = (Particle) obj;
if (!getEnclosingInstance().equals(
other.getEnclosingInstance()))
return false;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
private ParticleSimulator getEnclosingInstance() {
return ParticleSimulator.this;
}
}
}
i have 2 classes , inputHandlerMenu and GameWorld , and i want to get an integer from inputHanlerMenu and use it in GameWorld ! it tried a lot but i didnt work . can any one help me ?
i declared : public GameWorld seter;
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
screenX = scaleX(screenX);
screenY = scaleY(screenY);
if (menuButtons.get(0).isTouchUp(screenX, screenY)) {
world.getMenuObject().getPad().end();
seter.setModes(1);
for (int i = 0; i < menuButtons.size(); i++) {
menuButtons.get(i).end();
}
world.getMenuObject().getVolumeButton().end();
menuButtons.get(0).tranToGameScreen();
}if (menuButtons.get(1).isTouchUp(screenX, screenY)) {
world.getMenuObject().getPad().end();
seter.setModes(2);
for (int i = 0; i < menuButtons.size(); i++) {
menuButtons.get(i).end();
}
world.getMenuObject().getVolumeButton().end();
menuButtons.get(1).tranToGameScreen();
}if (menuButtons.get(2).isTouchUp(screenX, screenY)) {
world.getMenuObject().getPad().end();
seter.setModes(3);
for (int i = 0; i < menuButtons.size(); i++) ....
i declared mode as public int mode;
public void setModes (int mode){
this.mode = mode;
}
private void collisions() {
{
if (!ball.hasCollided()) {
for (int i = 0; i < pad.getcolCircles().size(); i++)
if (Intersector.overlaps(pad.getcolCircles().get(i), ball.getColCircle())) {
ball.collide();
ball.setCollided(true);
//Gdx.app.log("Angle", ball.getVelocity().toString());
//double perp = 2.0 * ball.getVelocity().cpy().dot(pad.returnNormal(i));
//Vector2 reflectDir = ball.getVelocity().cpy().sub((pad.returnNormal(i).scl((float) perp))).scl(1);
float newAngle = getAngle2Vecs(ball.getVelocity(), pad.returnNormal(i));
//Gdx.app.log("Angle", newAngle + "");
ball.setVelocity(new Vector2(gameWidth / 2 - ball.getColCircle().x, gameHeight / 2 - ball.getColCircle().y));
int rand = (int) Math.random() * 90 + 5;
if (pad.getAngularVelocity() < 0) {
ball.setVelocity(ball.getVelocity().cpy().rotate((float) (rand + Math.random() * 50)));
} else if (pad.getAngularVelocity() > 0) {
ball.setVelocity(ball.getVelocity().cpy().rotate((float) (-rand - Math.random() * 50)));
} else {
ball.setVelocity(ball.getVelocity().cpy().rotate(Math.random() < 0.5 ? -rand : rand));
System.out.println(mode);
if (mode == 1) {
if (score <= 5) {
ball.setVelocity(ball.getVelocity().cpy().scl(Configuration.E_VELOCITY_OVER_0));
} else if (score >= 5 && score < 50) {
ball.setVelocity(ball.getVelocity().cpy().scl(Configuration.E_VELOCITY_OVER_5));
} else if (score >= 10 && score < 50) {
ball.setVelocity(ball.getVelocity().cpy().scl(Configuration.E_VELOCITY_OVER_10));
} else if (score >= 20 && score < 50) {
ball.setVelocity(ball.getVelocity().cpy().scl(Configuration.E_VELOCITY_OVER_20));
} else if (score >= 35 && score < 50) {
ball.setVelocity(ball.getVelocity().cpy().scl(Configuration.E_VELOCITY_OVER_35));
} else if (score >= 50 && score < 75) {
ball.setVelocity(ball.getVelocity().cpy().scl(Configuration.E_VELOCITY_OVER_50));
} else if (score >= 65 && score < 75) {
ball.setVelocity(ball.getVelocity().cpy().scl(Configuration.E_VELOCITY_OVER_65));
} else if (score >= 75 && score < 100) {
ball.setVelocity(ball.getVelocity().cpy().scl(Configuration.E_VELOCITY_OVER_75));
} else if (score >= 100 ) {
ball.setVelocity(ball.getVelocity().cpy().scl(Configuration.E_VELOCITY_OVER_100));
} ....
i use for every button her mode , like if he pressed button 0 , velocity will change , button 1 => velocity change ...
here the int stay at 0 . it doesnt change !
any one know how to do it ! ?
You can use shared preferences and store the integer value in Input Handler Menu and then you can get the value in GameWorld as shown below.
In Input Handler:
SharedPreferences sharedPreferences = getSharedPreferences("MyData" , Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putInt("Key" , your_int_value);
editor.commit();
In GameWorld:
SharedPreferences sharedPreferences = getSharedPreferences("MyData", Context.MODE_PRIVATE);
int position = sharedPreferences.getInt("key", Default_Value);
The integer value stored will be assigned to position, you can use that where ever you want.
Hope this might help you.
Add this method to your GameWorld class and make sure mode is public int
public int mode;
public int getModes(){
return mode
}
Now in your other class whenever you need the integer simply call
int getthatint = seter.getModes();
trying to create a Conways Game of life, but apparently the shapes are not like they have to be. Perhaps someone can help me find the issue.
For example the glider :
- X - - - -
- - X X - -
- X X - - -
- - - - - -
becomes this
- - X X - -
- X - - - -
X X X - - -
- X X X - -
but should be like this :
- - X - - -
- - - X - -
- X X X - -
- - - - - -
And my code looks like this
public Frame(int x, int y) {
setWidth(x);
setHeight(y);
if (x<1)
frame = null;
else if (y<1)
frame = null;
else {
frame = new String [x][y];
for (int i=0; i<frame.length; i++) {
for (int j=0; j<frame[i].length; j++) {
frame [i][j] = DEAD;
}
}
} // else
} // construktor
public Integer getNeighbourCount(int x, int y) {
Frame cell = new Frame(getHeight(), getWidth());
int counter = 0;
if(frame[x][y].equals(ALIVE))
{
counter = counter - 1;
}
for(int i=x-1; i<=x+1;i++){
if(i<frame.length && i>0){
for(int j=y-1; j<=y+1;j++){
if(j<frame[i].length && j>0){
if (frame[i][j]==ALIVE) {
counter++;
}
}
}
}
}
return counter;
}
public Frame nextFrame() {
// Returns next frame
Frame cell = new Frame(getWidth(), getHeight());
//cell.frame = new String[getWidth()][getHeight()];
for(int i = 0; i < frame.length; i++){
for(int j =0; j <frame[i].length;j++){
int n = getNeighbourCount(i,j);
if(cell.frame[i][j]==null) {
cell.frame[i][j] = DEAD;
}
if (isAlive(i, j) && n < 2 || n > 3) {
cell.frame[i][j] = DEAD;
}
if (isAlive(i, j) && n == 3 || n == 2){
cell.frame[i][j] = ALIVE;
}
if(!isAlive(i, j) && n == 3) {
cell.frame[i][j] = ALIVE;
}
if(isAlive(i, j) && n > 3){
cell.frame[i][j] = DEAD;
}
frame[i][j] = cell.frame[i][j];
}
}
cell.toString();
return cell;
}
`
Full code http://pastebin.com/LMwz724H
Here's a solution that works - using an enum for each cell and getting the i/j and x/y stuff right (I think). It certainly generates the correct first iteration:
static class GameOfLife {
final int w;
final int h;
State[][] frame;
enum State {
Dead, Alive;
}
public GameOfLife(int w, int h) {
this.w = w;
this.h = h;
frame = new State[h][w];
}
public void alive(int x, int y) {
frame[y][x] = State.Alive;
}
public void tick() {
frame = nextGeneration();
}
private int surroundingPopulation(int x, int y) {
int pop = 0;
for (int i = y - 1; i <= y + 1; i++) {
for (int j = x - 1; j <= x + 1; j++) {
// On frame - vertically.
if ((i >= 0 && i < h)
// On frame horizontally.
&& (j >= 0 && j < w)
// Alive
&& (frame[i][j] == State.Alive)
// Not the center.
&& (i != y || j != x)) {
pop += 1;
}
}
}
return pop;
}
private State[][] nextGeneration() {
State[][] next = new State[h][w];
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
int pop = surroundingPopulation(x, y);
// Any live cell
if (frame[y][x] == State.Alive) {
if (pop < 2) {
// ... with fewer than two live neighbours dies, as if caused by under-population.
next[y][x] = State.Dead;
} else if (pop > 3) {
// ... with more than three live neighbours dies, as if by overcrowding.
next[y][x] = State.Dead;
} else {
// ... with two or three live neighbours lives on to the next generation.
next[y][x] = State.Alive;
}
} else {
// Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
if (pop == 3) {
next[y][x] = State.Alive;
}
}
}
}
return next;
}
#Override
public String toString() {
StringBuilder s = new StringBuilder();
for (State[] row : frame) {
for (State c : row) {
s.append(c == State.Alive ? "X" : " ");
}
s.append("\r\n");
}
return s.toString();
}
}
public void test() {
GameOfLife g = new GameOfLife(6, 6);
g.alive(1, 0);
g.alive(2, 1);
g.alive(3, 1);
g.alive(1, 2);
g.alive(2, 2);
System.out.println("Before:\r\n" + g);
g.tick();
System.out.println("After:\r\n" + g);
}
I believe the problem is that you are copying the new value as you iterate through the loop. This means neighbours are using the value from the next tick rather than the current one.
You can fix this by waiting until you calculated all new values in your new frame: cell.frame and then iterate through the frame again and copy from cell.frame to frame.
An alternative (better in my view) is to have away of cloning a frame during construction. Then you could change your nextFrame method to create a clone of frame and use the clone to set the new values in frame.
You are changing the DEAD and ALIVE frames while you iterate through the grid. You need to store the coordinates which should die or become alive and perform that afterwards.
Store the coordinates in two ArrayLists (dead, alive). The first and second position is the x and y axis, and change those coordinates according to whether they should become alive or not.
Here's a snippet from a simple test I wrote a while back. As others have mentioned, don't change values on an active board while still reading them. Instead, clone the board and make changes to the copy while reading the current board.
Another problem I bumped into a few times was iterating over y, then x for each y, but referring to x,y when accessing a point. It feels back to front :)
// Rules:
// 1) Any live cell with fewer than two live neighbours dies, as if caused by under-population.
// 2) Any live cell with two or three live neighbours lives on to the next generation.
// 3) Any live cell with more than three live neighbours dies, as if by overcrowding.
// 4) Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
void mutateGrid() {
// Copy existing grid into the next generation's grid
boolean[][] mutatedGrid = new boolean[gridXWidth][gridYHeight];
for (int i = 0; i < gridXWidth; i++) {
System.arraycopy(grid[i], 0, mutatedGrid[i], 0, gridYHeight);
}
// Start mutation rules
for (int y = 0; y < gridYHeight; y++) {
for (int x = 0; x < gridXWidth; x++) {
int liveNeighbours = countLiveNeighbours(x,y);
if (liveNeighbours < 2 || liveNeighbours > 3) {
mutatedGrid[x][y] = false;
}
else if (liveNeighbours == 3) {
mutatedGrid[x][y] = true;
}
}
}
grid = mutatedGrid;
}
int countLiveNeighbours(int x, int y) {
int count = 0;
for (int j = y-1; j <= y+1; j++) {
for (int i = x-1; i <= x+1; i++) {
if (i < 0 || j < 0 || i >= gridXWidth || j >= gridYHeight){
continue;
}
if (grid[i][j]) {
count++;
}
}
}
count -= grid[x][y]?1:0; // remove self from count
return count;
}
I'm trying to move a ball across a frame. I have the up, down, left, and right motion going fine. But when I try to move diagonally, it doesn't seem to work. Here is my code.
First I declare some sets; pressed is the keys pressed, and the others are combinations of keys to move the ball up and left so on so forth;
public Set<Integer> pressed = new HashSet<>();
public Set<Integer> upLeft, upRight, downLeft, downRight;
Next, in my init method I start to add the integer values to the sets and add key listeners to my frame:
private void myInit(){
... // cut down code from above
int[] a = new int[2];
a[0] = 38; a[1] = 37;
upLeft = new HashSet(Arrays.asList(a));
a[1] = 39;
upRight = new HashSet(Arrays.asList(a));
a[0] = 40; a[1] = 37;
downLeft = new HashSet(Arrays.asList(a));
a[1] = 39;
downRight = new HashSet(Arrays.asList(a));
addKeyListener(new java.awt.event.KeyAdapter() {
public void keyPressed(java.awt.event.KeyEvent evt) {
formKeyPressed(evt);
}
});
addKeyListener(new java.awt.event.KeyAdapter() {
public void keyReleased(java.awt.event.KeyEvent evt) {
formKeyReleased(evt);
}
});
}
Now here are my methods to handle the key pressed and released:
public synchronized void formKeyPressed(java.awt.event.KeyEvent evt) {
pressed.add(evt.getKeyCode());
System.out.println("Added:"+evt.getKeyCode());
if(pressed.size() == 1) {
System.out.println("Size is 1");
if(evt.getKeyCode() == evt.VK_UP) {
if(y <= 25) {
y = 25;
}
else {
y = y - yUpSpeed;
}
}
if(evt.getKeyCode() == evt.VK_DOWN) {
if(y >= (500-25)) {
y = (500-25);
}
else {
y = y + yDownSpeed;
}
}
if(evt.getKeyCode() == evt.VK_LEFT) {
if(x <= 0) {
x = 0;
}
else {
x = x - xLeftSpeed;
}
}
if(evt.getKeyCode() == evt.VK_RIGHT) {
if(x >= (500-25)) {
x = (500-25);
}
else {
x = x + xRightSpeed;
}
}
}
else if(pressed.size() == 2) {
System.out.println("Size is 2");
if(pressed.containsAll(upLeft)) {
if(y <= 25) {
y = 25;
}
else {
y = y - yUpSpeed;
}
if(x <= 0) {
x = 0;
}
else {
x = x - xLeftSpeed;
}
}
if(pressed.containsAll(upRight)) {
if(y <= 25) {
y = 25;
}
else {
y = y - yUpSpeed;
}
if(x >= (500-25)) {
x = (500-25);
}
else {
x = x + xRightSpeed;
}
}
if(pressed.containsAll(downLeft)) {
if(y >= (500-25)) {
y = (500-25);
}
else {
y = y + yDownSpeed;
}
if(x <= 0) {
x = 0;
}
else {
x = x - xLeftSpeed;
}
}
if(pressed.containsAll(downRight)) {
if(y >= (500-25)) {
y = (500-25);
}
else {
y = y + yDownSpeed;
}
if(x >= (500-25)) {
x = (500-25);
}
else {
x = x + xRightSpeed;
}
}
}
else {
System.out.println("Size is more than 2");
}
public synchronized void formKeyReleased(java.awt.event.KeyEvent evt) {
System.out.println("Removed:"+evt.getKeyCode());
pressed.remove(evt.getKeyCode());
}
The problem is that, from the debug system.out messages, the size of the set pressed is never larger than one. What am I doing wrong?
Check out the KeyBoardAnimation example from Motion Using the Keyboard. It keeps a Map of the keys that are currently pressed and then move the object based on all the keys in the Map.
This approach uses Key Bindings, which is preferred over a KeyListener for the reasons given in the blog.
I'm working on a tictactoe board for practice making classes and i have ran into a problem with my algorithm. it seems to be returning the best move offensive, but it doesn't play defense. i dont know where i have messed up and cant seem to find it. i have looked over a lot of things on here about it and ive compared it to simular projects, but still can't seem to get it. here is my code.
package TicTacToe;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
public class Solution {
private static GameBoard currentBoard;
private static Player botPlayer;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String player;
System.out.println("ENTER bot: ");
player = in.next();
if(player.equalsIgnoreCase("X")) {
botPlayer = Player.X;}
else {botPlayer = Player.O;}
String board[] = new String[3];
for(int i = 0; i < 3; i++) {
System.out.println("ENTER board: ");
board[i] = in.next();
}
currentBoard = new GameBoard(3,3, board);
List<Space> OpenSpaces = getOpenSquares(currentBoard);
MakeMove(OpenSpaces);
System.exit(-1);
}
public static List<Space> getOpenSquares(GameBoard GB) {
List<Space> OpenSpaces = new ArrayList<Space>();
for(int r = 0; r < 3; r++) {
for(int c = 0; c < 3; c++) {
if(GB.squares[r][c] == Player.Open) {
OpenSpaces.add(new Space(r,c));
}
}
}
return OpenSpaces;
}
private static Space bestMove;
private static Space currentMove;
private static Space previousMove;
private static void MakeMove(List<Space> OpenSpaces) {
if(OpenSpaces.size() == currentBoard.Size) {
Random random = new Random();
bestMove = new Space(random.nextInt(2),2);
} else {
for(Space child: OpenSpaces) {
currentMove = GetBestMove(currentBoard,botPlayer);
if (currentMove != null){
}else{
continue;}
if(previousMove != null && previousMove.Rank < currentMove.Rank ||
previousMove == null && currentMove != null) {
bestMove = currentMove;
}
previousMove = currentMove;
}
}
if (bestMove != null) {
currentBoard.squares[bestMove.X][bestMove.Y] = botPlayer;
System.out.println("the best move is: " + currentMove.X + " " + currentMove.Y);
}
}
private static Space GetBestMove(GameBoard gb, Player p) {
Space bestSpace = null;
List<Space> cloneOpenSpaces = getOpenSquares(gb);
GameBoard cloneBoard = null;
cloneBoard = gb.Clone();
for(Space Open: cloneOpenSpaces) {
cloneBoard = gb.Clone();
Space newSpace = Open;
cloneBoard.squares[newSpace.X][newSpace.Y] = p;
if(cloneBoard.Winner == Player.Open && cloneOpenSpaces.size() > 0) {
Player InP;
if(p == Player.X) {
InP = Player.O;
}else {
InP = Player.X;
}
Space tempMove = GetBestMove(cloneBoard, InP);
if(tempMove != null){
newSpace.Rank = tempMove.Rank;
}
} else {
if(cloneBoard.Winner == Player.Open) {
newSpace.Rank = 0;
}else if(cloneBoard.Winner == Player.O) {
newSpace.Rank = -1;
}else if(cloneBoard.Winner == Player.X) {
newSpace.Rank = 1;
}
}
System.out.println(newSpace.Rank);
if(bestSpace == null ||
(p == Player.X && newSpace.Rank < ((Space)bestSpace).Rank)||
(p == Player.O && newSpace.Rank > ((Space)bestSpace).Rank)) {
bestSpace = newSpace;
}
}
return (Space)bestSpace;
}
public static enum Player {
X (1),
O (-1),
Open (0);
private final double value;
Player(double value){
this.value = value;
}
}
public static class Space {
public int X;
public int Y;
public double Rank;
public Space(int x, int y) {
this.X = x;
this.Y = y;
Rank = 0;
}
public Space() {
}
}
public static class GameBoard {
public int Rows;
public int getRows() {
return this.Rows;
}
public void setRows(int rows) {
Rows = rows;
}
public int Columns;
public int getColumns() {
return this.Columns;
}
public void setColumns(int columns) {
Columns = columns;
}
public Player[][] squares;
//public Player[x][y]
public Player getPlayer(int x, int y) {
return this.squares[x][y];
}
public void setPlayer(int x, int y, Player player) {
squares[x][y] = player;
}
public boolean Full;
public boolean isFull() {
for(int r = 0; r < 2; r++) {
for(int c = 0; c < 2; c++) {
if (squares[r][c] != Player.Open) {return false;}
}
}
return true;
}
public int Size;
public int getSize() {
return this.Size;
}
public void setSize(int size) {
Size = size;
}
public List<Space> OpenSquares;
public List<Space> getOpenSquares() {
List<Space> OpenSquares = new ArrayList<Space>();
for(int r = 0; r < Rows; r++) {
for(int c = 0; c < Columns; c++) {
if(squares[r][c] == Player.Open) {
OpenSquares.add(new Space(r,c));
}
}
}
return this.OpenSquares;
}
public Player Winner;
public Player getWinner() {
int count = 0;
//columns
for (int x = 0; x < Rows; x++)
{
count = 0;
for (int y = 0; y < Columns; y++) {
count += squares[x][y].value;
}
if (count == 3) {
return Player.X;
}else if (count == -3) {
return Player.O;
}
}
//rows
for (int x = 0; x < Rows; x++) {
count = 0;
for (int y = 0; y < Columns; y++) {
count += squares[y][x].value;
}
if (count == 3) {
return Player.X;
}else if (count == -3) {
return Player.O;
}
}
// Diagonals right to left
count = 0;
count += squares[0][0].value;
count += squares[1][1].value;
count += squares[2][2].value;
if (count == 3) {
return Player.X;
}else if (count == -3) {
return Player.O;
}
// Diagonals left to right
count = 0;
count += squares[0][2].value;
count += squares[1][1].value;
count += squares[2][0].value;
if (count == 3) {
return Player.X;
}else if (count == -3) {
return Player.O;
}
return Player.Open;
}
public GameBoard Clone() {
GameBoard b = new GameBoard(Rows,Columns);
b.squares = (Player[][])this.squares.clone();
b.Winner = getWinner();
return b;
}
// Class initializer
public GameBoard(int boardRows, int boardColumns, String[] board) {
// Set the dimensions
Rows = boardRows;
Columns = boardColumns;
// Create game spaces
squares = new Player[Rows][Columns];
for(int r = 0; r < Rows; r++) {
for(int c = 0; c < Columns; c++) {
//squares[i][n] = Player.Open;
if(board[r].charAt(c) == 'X') {
squares[r][c] = Player.X;
}
if(board[r].charAt(c) == 'O') {
squares[r][c] = Player.O;
}
if(board[r].charAt(c) == '_') {
squares[r][c] = Player.Open;
}
}
}
this.Winner = getWinner();
this.OpenSquares = getOpenSquares();
//Size of the board
this.Size = Rows * Columns;
}
// clone Class initializer
public GameBoard(int boardRows, int boardColumns) {
// Set the dimensions
Rows = boardRows;
Columns = boardColumns;
// Create game spaces
squares = new Player[Rows][Columns];
for(int r = 0; r < Rows; r++) {
for(int c = 0; c < Columns; c++) {
squares[r][c] = Player.Open;
}
}
this.Winner = getWinner();
this.OpenSquares = getOpenSquares();
//Size of the board
Size = Rows * Columns;
}
}
}
all of the classes are at the bottom. Thanks in advance for any help and corrections. :)
i made it recursive in the following code, although i still cant figure out the scoring.. if the value is either 1, 0, or -1 then if there are multipule moves with the same value it will just take the 1st one which may not be the best move "blocking.
private static Space GetBestMove(GameBoard gb, Player p) {
Space bestSpace = null;
List<Space> cloneOpenSpaces = getOpenSquares(gb);
GameBoard cloneBoard = null;
cloneBoard = gb.Clone();
for(Space Open: cloneOpenSpaces) {
cloneBoard = gb.Clone();
Space newSpace = Open;
cloneBoard.squares[newSpace.X][newSpace.Y] = p;
if(cloneBoard.Winner == Player.Open && cloneOpenSpaces.size() > 0) {
Player InP;
if(p == Player.X) {
InP = Player.O;
}else {
InP = Player.X;
}
***Space tempMove = GetBestMove(cloneBoard, InP);***
if(tempMove != null){
newSpace.Rank = tempMove.Rank;
}
the results of the test are as follows
test 1
ENTER bot:
O
ENTER board:
[ ][O][ ]
ENTER board:
[ ][ ][ ]
ENTER board:
[ ][X][X]
-1.0
-1.0
-1.0
-1.0
-1.0
-1.0
-1.0
-1.0
-1.0
the best move is: 0 2
test 2
ENTER bot:
O
ENTER board:
[ ][X][X]
ENTER board:
[ ][ ][ ]
ENTER board:
[ ][O][ ]
1.0
1.0
1.0
1.0
1.0
-1.0
1.0
-1.0
-1.0
1.0
-1.0
1.0
1.0
-1.0
-1.0
the best move is: 1 1
I haven't ran your code, but I think I may know why you are having issues. The minimax algorithm is recursive in nature. You look at each open space, and determine some sort of score for each one. I see this in your code. However, what I don't see is the recursion that equates to the logic "if I move here, then what options will my opponent have during his next turn". Notice that you can keep calling the same scoring function, but scoring both players' options. This is where the computation can get intensive, and where stuff like pruning comes into play. Say I want to look 3 moves ahead. Say there are initially 5 open spaces. For each of the 5 open spaces, I examine my options and give a score to each one. Then I pretend to move there, and send the new board through the scoring function, and assume my opponent will take the highest scoring move of the remaining 4 possible moves. Then I pretend he moves there, and I again run the board through the scoring function, now with 2 hypothetical moves on it. You continue this for a set "depth", or number of potential moves, and pick the move that results in the highest value, assuming the opponent will do what you calculated they would.
I realize this was long-winded, but I hope there was a little bit of value buried in there somewhere. Take a look at your code, figure out where you are scoring moves (if you see a win, take it; if you can block a win, take it; etc.). Then continue calling this function where you keep adding fake/potential moves (those with the highest value from your scoring function), and once you reach the depth, you can simply pick the move that is likely to give you the most valuable outcome.
Basically, in your code, you should call GetBestMove(...) once from MakeMove(...). However, GetBestMove(...) should repeatedly call itself, with a modified board each time; and each time, it will return the best move given a hypothetical (or real) board. What I don't see in your code is that recursive call to GetBestMove(...), and the necessary upkeep that goes along with it. This explains why you only get aggressive behavior; it only looks to see what the best immediate move is, without any regard to what your opponent might be able to do if you make that move!
If my assumptions are wrong, provide a test case where you expect some behavior, but are getting something different.