Pass Variables using Blocking Queue - java

At the moment I am trying to make my program pass the variables xPos and yPos from the ChessBoard class to the makeMove() method in HumanPlayer.
But at the moment it just gives null pointer exceptions in HumanPlayer.
Can this be done with BlockingQueues and if so what am I doing wrong?
HumanPlayer
import java.util.*;
import java.util.concurrent.BlockingQueue;
public class HumanPlayer extends Player implements Runnable{
private Scanner in;
protected BlockingQueue<Integer> queue = null;
int x;
int y;
public HumanPlayer(String n, Pieces p, Board b, Player o, BlockingQueue<Integer> queue) {
super(n, p, b, o);
this.queue = queue;
}
#Override
public void run() {
try{
x = queue.take();
y = queue.take();
}
catch (InterruptedException e){
e.printStackTrace();
}
}
public boolean makeMove() {
// declare board and selected piece
Board chess = getBoard();
Piece selected;
//take input of piece player wants to move
// in = new Scanner(System.in);
// System.out.println("Select Piece: ");
// System.out.print("x: ");
// String inputX = in.nextLine().toUpperCase();
// System.out.print("y: ");
// String inputY = in.nextLine();
// System.out.println(inputX+inputY);
// //if one of the inputs is >1 length then return false to stop error
// if (inputY.length()!=1 || inputX.length() !=1)
// return false;
// //change inputs to numbers to use in array
// int x = (int)(inputX.charAt(0)-'A');
// int y = (int)(inputY.charAt(0)-'0')-1;
run();
// if the input is in range of the board array select that piece if not return false
if ( x<=7 && x>=0 && y<=7 && y>=0){
selected = chess.getPiece(x,y);
System.out.println(x+""+y);
}
else
return false;
// check the piece selected is not null and is the players own piece
if ((selected != null)
&& (getPieces().getPiece(0).getColour() == selected.getColour() )) {
}
else
return false;
// get the position the player wants to move the piece to
// System.out.println("Select Move: ");
// System.out.print("x: ");
// String moveX = in.nextLine().toUpperCase();
// System.out.print("y: ");
// String moveY = in.nextLine();
// System.out.println(moveX+moveY);
// check the inputs length are > 1 to stop errors
// if (moveY.length()!=1 || moveX.length() !=1)
// return false;
// //change inputs to ints for array
// int mX = (int)(moveX.charAt(0)-'A');
// int mY = (int)(moveY.charAt(0)-'0')-1;
run();
int mX = x;
int mY = y;
//check the inputs are not > 7 or less than 0
if ( mX>7 || mX<0 || mY>7 || mY<0) {
return false;
}
//declare boolean and move
boolean occupied = getBoard().occupied(mX, mY);
Move requested = new Move(selected,x,y,mX,mY,occupied);
//check if the move is and available move
if ( selected.availableMoves().contains(requested) ){
//delete the opponents piece if its taken
if (occupied){
Piece remove = chess.getPiece(mX,mY);
chess.remove(mX, mY);
getOpponent().getPieces().delete(remove);
}
// move the piece to desired position
selected.setPosition(mX, mY);
chess.setPosition(mX, mY, selected);
chess.remove(x, y);
return true;
}
//return false if not and available move
return false;
}
}
ChessBoard
import java.awt.*;
import java.awt.event.*;
import java.util.concurrent.BlockingQueue;
import javax.swing.*;
#SuppressWarnings("serial")
public class ChessBoard extends JFrame implements ActionListener, Runnable{
JButton[][] squares;
private int xPos;
private int yPos;
protected BlockingQueue<Integer> queue = null;
public ChessBoard(BlockingQueue<Integer> queue){
this.queue = queue;
setSize(800,800);
setTitle("chess");
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container contentPane = getContentPane();
contentPane.setLayout(new GridLayout (8,8));
squares = new JButton[8][8];
Color lightBrown = new Color(222,184,135);
Color Brown = new Color(167,71,20);
for(int y=7; y>=0; y--){
for(int x=0; x<8; x++){
squares[x][y] = new JButton();
squares[x][y].addActionListener(this);
if ((x + y) % 2 == 0) {
squares[x][y].setBackground(Brown);
}
else {
squares[x][y].setBackground(lightBrown);
}
contentPane.add(squares[x][y]);
}
}
setVisible(true);
}
public JButton getButton(int x, int y){
return squares[x][y];
}
#Override
public void actionPerformed(ActionEvent e) {
JButton selected = (JButton) e.getSource();
for(int y=7; y>=0; y--){
for(int x=0; x<8; x++){
if( selected == squares[x][y]){
xPos = x;
yPos = y;
System.out.println(xPos+""+yPos);
}
}
}
}
public int getxPos() {
return xPos;
}
public int getyPos() {
return yPos;
}
#Override
public void run() {
try{
queue.put(xPos);
Thread.sleep(1000);
queue.put(yPos);
}
catch (InterruptedException e){
e.printStackTrace();
}
}
}

Related

Calling function to set array in server and printing array in client

So I'm building the game battleship and I am using a 2d array for the board, but the problem is if I call the function to set the array, I have to call all other functions that use the array to get the same array, otherwise, it will just use a fresh new array. Right now I'm calling the setup function for the array inside the server, and when I call the function to print out the array to the GUI, it prints out a new array, any idea on how to fix this?
Server Class:
public class Server {
private static PrintWriter writerSocket;
private static BufferedReader buffedReader;
public static String player1shipHit;
Controller controller = Controller.returnController();
private static String sharedMessage;
int shipsLeftPlayer1 = 4;
int shipsLeftPlayer2 = 4;
public static String player2hit;
private static InputStreamReader readerSocket;
private final Object lock = new Object();
void waitForLock() {
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
void notifyLock() {
synchronized (lock) {
lock.notify();
}
}
public static void main(String[] args) throws IOException {
new Server().go();
}
void go() throws IOException {
ServerSocket server = new ServerSocket(5000);
Socket connectionOne = server.accept();
controller.player1.setUp(); //Setup
System.out.println("Server>> P1 connected");
writerSocket = new PrintWriter(connectionOne.getOutputStream());
writerSocket.println("Player1> Enter your guess in the format: X,Y");
writerSocket.flush();
new Thread(new JobOne(connectionOne)).start();
Socket connectionTwo = server.accept();
System.out.println("server>> P2 connected");
controller.player2.setUp();
writerSocket = new PrintWriter(connectionTwo.getOutputStream());
writerSocket.flush();
new Thread(new JobTwo(connectionTwo)).start();
}
private class JobOne implements Runnable {
Socket socket;
JobOne(Socket name) {
socket = name;
}
#Override
public void run() {
try {
readerSocket = new InputStreamReader(socket.getInputStream());
buffedReader = new BufferedReader(readerSocket);
} catch (IOException e) {
e.printStackTrace();
}
while (true) {
Controller.state = false;
try {
sharedMessage = buffedReader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
String[] coordinates = sharedMessage.split(",");
int x = Integer.parseInt(coordinates[0]);
int y = Integer.parseInt(coordinates[1]);
if (controller.player2.board.testHit(x, y)) {
controller.player1.board.updateBoard("Hit", x, y);
sharedMessage = "Player 2 has been hit!";
writerSocket.println(sharedMessage);
writerSocket.flush();
if (controller.player2.testShip("C", x, y)) {
sharedMessage = "Player 2's" + player1shipHit + " is Down";
shipsLeftPlayer2--;
if (shipsLeftPlayer2 == 0) {
sharedMessage = "Player 1 has won!";
}
}
} else if (!controller.player2.board.testHit(x, y)) {
sharedMessage = "Player 1 misses!";
}
try {
writerSocket = new PrintWriter(socket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
notifyLock();
writerSocket.println(sharedMessage);
writerSocket.flush();
waitForLock();
}
}
}
private class JobTwo implements Runnable {
Socket socket;
JobTwo(Socket name) {
socket = name;
}
#Override
public void run() {
try {
writerSocket = new PrintWriter((socket.getOutputStream()));
readerSocket = new InputStreamReader(socket.getInputStream());
buffedReader = new BufferedReader(readerSocket);
} catch (IOException e) {
e.printStackTrace();
}
while (true) {
waitForLock();
writerSocket.println(sharedMessage);
writerSocket.flush();
while (true) {
Controller.state1 = false;
writerSocket.println("Player2> Enter the coordinates in the format X,Y:");
writerSocket.flush();
try {
sharedMessage = buffedReader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
String[] coordinates = sharedMessage.split(",");
int x = Integer.parseInt(coordinates[0]);
int y = Integer.parseInt(coordinates[1]);
;
System.out.println("Player 2 X:" + x);
System.out.println("PLayer 2 Y:" + y);
Coordinate coordinate = new Coordinate(x, y);
if (controller.player1.board.testHit(x, y)) {
controller.player2.board.updateBoard("Hit", x, y);
sharedMessage = "Player 2 has a hit";
if (controller.player1.testShip(player2hit, x, y)) {
sharedMessage = "Player1s" + player2hit + "is down!" + 50;
shipsLeftPlayer1--;
if (shipsLeftPlayer1 == 0) {
sharedMessage = "PLayer 2 has won!";
}
}
} else {
controller.player2.board.updateBoard("Miss", x, y);
sharedMessage = "PLayer 2 has a miss.";
}
notifyLock();
}
}
}
}
}
Board class:
public class Board {
public int[][] board1 = null;
public int[][] board2;
public Board() {
board1 = new int[20][20];
board2 = new int[20][20];
}
public void updateBoard(String type, int x, int y) {
if (type.equals("hit")) {
board2[x][y] = 1;
} else if (type.equals("miss")) {
board2[x][y] = '0';
}
}
public boolean testHit(int x, int y) {
if (board1[x][y] == 1) {
board1[x][y] = 5;
System.out.println("Its a hit!");
return true;
} else {
System.out.println("It's a miss");
return false;
}
}
}
Player Class:
public class Player {
Destroyer destroyer;
Battleship battleship;
Submarine submarine;
Board board;
int[][] board1;
Turn turn;
int playerId;
boolean guiState;
Carrier carrier;
ArrayList<String> ships = new ArrayList<String>(4);
public Player(int playerIdSet){
board1 = new int[20][20];
playerId = playerIdSet;
board = new Board();
turn = new Turn();
ships.add("Carrier");
ships.add("Destroyer");
ships.add("Battleship");
ships.add("Submarine");
}
public void setSubmarine(Submarine subSet){
submarine = subSet;
}
public Submarine getSubmarine(){
return submarine;
}
public void setBattleship(Battleship battleshipSet) {
battleship = battleshipSet;
}
public Battleship getBattleship() {
return battleship;
}
public void setDestroyer(Destroyer destroyerSet) {
destroyer = destroyerSet;
}
public void setCarrier(Carrier carrierSet){
carrier = carrierSet;
}
public Carrier getCarrier(){
return carrier;
}
public Destroyer getDestroyer() {
return destroyer;
}
public Board getBoard(){
return board;
}
public void setUp(){
for (String ship : ships) {
int x;
int y;
switch (ship) {
case "Destroyer" -> {
x = (int) (Math.random() * (9) + 0);
y = (int) (Math.random() * (9) + 0);
if (board.board1[x][y] == 0) {
Destroyer destroyer = new Destroyer(x, y);
setDestroyer(destroyer);
getDestroyer().createShip(playerId);
} else {
x = (int) (Math.random() * (9) + 0);
y = (int) (Math.random() * (9) + 0);
}
}
case "Carrier" -> {
x = (int) (Math.random() * (9) + 1);
y = (int) (Math.random() * (9) + 1);
if (board.board1[x][y] == 0) {
Carrier carrier = new Carrier(x, y);
setCarrier(carrier);
getCarrier().createShip(playerId);
} else {
x = (int) (Math.random() * (9) + 0);
y = (int) (Math.random() * (9) + 0);
}
}
case "Battleship" -> {
x = (int) (Math.random() * (9) + 0);
y = (int) (Math.random() * (9) + 0);
if (board.board1[x][y] == 0) {
System.out.println("X:" + x);
System.out.println("Y:" + y);
Battleship battleship = new Battleship(x, y);
setBattleship(battleship);
getBattleship().createShip(playerId);
} else {
x = (int) (Math.random() * (9) + 0);
y = (int) (Math.random() * (9) + 0);
}
}
case "Submarine" -> {
x = (int) (Math.random() * (9) + 0);
y = (int) (Math.random() * (9) + 0);
if (board.board1[x][y] == 0) {
System.out.println("X:" + x);
System.out.println("Y:" + y);
Submarine submarine = new Submarine(x, y);
setSubmarine(submarine);
getSubmarine().createShip(playerId);
} else {
x = (int) (Math.random() * (9) + 0);
y = (int) (Math.random() * (9) + 0);
System.out.println("Error checking...\n");
}
}
}
}
}
public void printBoard(){
System.out.println("Attempting to print");
for(int x = 0; x < board.board1.length; x++) {
for (int y =0; y < board.board1[x].length; y++){
System.out.println(board.board1[x][y]);
}
}
}
public void displayBoard(GUIController guiController) {
StringBuilder grid = new StringBuilder();
StringBuilder grid1 = new StringBuilder();
for(int x = 0; x < board.board1.length; x++) {
grid.append(x);
for (int y =0; y < board.board1[x].length; y++){
grid.append("[").append(board.board1[x][y]).append("]");
grid.append(" ");
}
grid.append("\n");
}
guiController.gui.board1Area.setText(String.valueOf(grid));
for(int i =0; i < board.board2.length; i++){
for(int j =0; j < board.board2.length; j++){
grid1.append("[").append(board.board2[i][j]).append("]");
grid.append(" ");
}
grid1.append("\n");
}
guiController.gui.board2Area.setText(String.valueOf(grid1));
}
public boolean testShip(String ship,int row, int col){
switch (ship){
case "Battleship" -> {
for (int[] ints : battleship.battleShipArray) {
for (int anInt : ints) {
return anInt == battleship.battleShipArray[row][col];
}
}
}
case "Carrier" -> {
for (int[] ints : carrier.carrierArray) {
for (int anInt : ints) {
return anInt == carrier.carrierArray[row][col];
}
}
}
case "Submarine" -> {
for (int[] ints : submarine.submarineArray) {
for (int anInt : ints) {
return anInt == submarine.submarineArray[row][col];
}
}
}
case "Destroyer" -> {
for (int[] ints : destroyer.destroyerArray) {
for (int anInt : ints) {
return anInt == destroyer.destroyerArray[row][col];
}
}
}
}
return false;
}
void markShipHit(int x, int y){
for(String ship : ships){
switch(ship){
/*case "Carrier" -> {
if(carrier.testHit(1,x,y)){
carrier.carrierArray[x][y] = 0;
Server.player1shipHit = "Carrier";
}
}*/
case "Battleship" -> {
if(battleship.testHit(1,x,y)){
battleship.battleShipArray[x][y] = 0;
Server.player1shipHit="Battleship";
}
}
case "Destroyer" ->{
if(destroyer.testHit(1,x,y)){
destroyer.destroyerArray[x][y] = 0;
Server.player1shipHit="Destroyer";
}
}
case "Submarine" ->{
if(submarine.testHit(1,x,y)){
submarine.submarineArray[x][y] = 0;
Server.player1shipHit="Submarine";
}
}
}
}
}
}
Client example:
public class PlayerOne {
Socket socket;
InputStreamReader readerSocket;
PrintWriter writerSocket;
BufferedReader bufferedReader;
public static String input;
GUIController guiController;
boolean state = true;
Controller controller = Controller.returnController();
boolean setupState = false;
public static void main(String[] args){
new PlayerOne().go();
}
private void go(){
guiController = new GUIController();
try {
socket = new Socket("127.0.0.1", 5000);
receiveRead();
while(true) {
if (Controller.state) {
writeSend();
Controller.state = false;
} else {
receiveRead();
Controller.state = true;
}
}
}catch (IOException e){
e.printStackTrace();
}
}
void writeSend()throws IOException {
while (input == null) {
input = guiController.inputLine;
}
writerSocket = new PrintWriter(socket.getOutputStream());
writerSocket.println(input);
writerSocket.flush();
controller.player1.displayBoard(guiController);
}
void receiveRead () throws IOException {
readerSocket = new InputStreamReader(socket.getInputStream());
bufferedReader = new BufferedReader(readerSocket);
String line = bufferedReader.readLine();
guiController.gui.setOutputText(line);
controller.player1.displayBoard(guiController);
}
}

basic planet wars ai issues

I am programming a very basic bot for planet wars in java and I cant seem to find the errors in my code. I am receiving a few different error messages but the main issue for me is the error: class, interface, or enum expected. Ive checked my brackets about a thousand times. Any help would be appreciated. Here's my bot code:
import java.util.List;
import java.util.Random;
import shared.Planet;
import shared.PlanetWars;
public class MyNewBot {
public static void doTurn(PlanetWars pw) {
// (1) If we currently have a fleet in flight, then do nothing until
// it arrives.
if (pw.myFleets().size() >= 10) {
return;
}
// (2) Pick one of my planets based on the number of ships
Planet source = null;
int largestForce = 0;
for (Planet p : pw.myPlanets()){
int force = pw.numShips();
if( force > largestForce){
largestForce = force;
source = p;
}
}
// (3) Pick a target planet at random.
Planet dest = null;
int highestGrowthRate = 0;
int shortestDistance = 9999;
for (Planet p = pw.notMyPlanets()){
int growthRate = pw.growthRate();
if( growthRate > highestGrowthRate){
highestGrowthRate = growthRate;
dest = p;
}else if (growthRate == highestGrowthRate){
int distance = pw.distance(source,p);
if (distance < shortestDistance){
shortestDistance = distance;
dest = p;
}
}
}
// (4) Send half the ships from source to destination.
if (source != null && dest != null) {
int numShips = source.numShips() / 2;
pw.issueOrder(source, dest, numShips);
}
}
// Ignore the main method unless you know what you're doing.
// Refer to the doTurn function to code your bot.
public static void main(String[] args) {
String line = "";
String message = "";
int c;
try {
while ((c = System.in.read()) >= 0) {
switch (c) {
case '\n':
if (line.equals("go")) {
PlanetWars pw = new PlanetWars(message);
doTurn(pw);
pw.finishTurn();
message = "";
} else {
message += line + "\n";
}
line = "";
break;
default:
line += (char) c;
break;
}
}
} catch (Exception e) {
// Owned.
}
}
}
and the supporting class files:
package shared;
public class Planet implements Cloneable {
private int planetID;
private int owner;
private int numShips;
private int growthRate;
private double x, y;
public Planet(int planetID, int owner, int numShips, int growthRate,
double x, double y) {
this.planetID = planetID;
this.owner = owner;
this.numShips = numShips;
this.growthRate = growthRate;
this.x = x;
this.y = y;
}
public int planetID() {
return planetID;
}
public int owner() {
return owner;
}
public int numShips() {
return numShips;
}
public int growthRate() {
return growthRate;
}
public double x() {
return x;
}
public double y() {
return y;
}
public void owner(int newOwner) {
this.owner = newOwner;
}
public void numShips(int newNumShips) {
this.numShips = newNumShips;
}
public void addShips(int amount) {
numShips += amount;
}
public void removeShips(int amount) {
numShips -= amount;
}
private Planet(Planet _p) {
planetID = _p.planetID;
owner = _p.owner;
numShips = _p.numShips;
growthRate = _p.growthRate;
x = _p.x;
y = _p.y;
}
public Object clone() {
return new Planet(this);
}
}
package shared;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
public class PlanetWars {
// Constructs a PlanetWars object instance, given a string containing a
// description of a game state.
public PlanetWars(String gameStateString) {
planets = new ArrayList<Planet>();
fleets = new ArrayList<Fleet>();
parseGameState(gameStateString);
}
// Returns the number of planets. Planets are numbered starting with 0.
public int numPlanets() {
return planets.size();
}
// Returns the planet with the given planet_id. There are NumPlanets()
// planets. They are numbered starting at 0.
public Planet getPlanet(int planetID) {
return planets.get(planetID);
}
// Returns the number of fleets.
public int numFleets() {
return fleets.size();
}
// Returns the fleet with the given fleet_id. Fleets are numbered starting
// with 0. There are NumFleets() fleets. fleet_id's are not consistent from
// one turn to the next.
public Fleet getFleet(int fleetID) {
return fleets.get(fleetID);
}
// Returns a list of all the planets.
public List<Planet> planets() {
return planets;
}
// Return a list of all the planets owned by the current player. By
// convention, the current player is always player number 1.
public List<Planet> myPlanets() {
List<Planet> r = new ArrayList<Planet>();
for (Planet p : planets) {
if (p.owner() == 1) {
r.add(p);
}
}
return r;
}
// Return a list of all neutral planets.
public List<Planet> neutralPlanets() {
List<Planet> r = new ArrayList<Planet>();
for (Planet p : planets) {
if (p.owner() == 0) {
r.add(p);
}
}
return r;
}
// Return a list of all the planets owned by rival players. This excludes
// planets owned by the current player, as well as neutral planets.
public List<Planet> enemyPlanets() {
List<Planet> r = new ArrayList<Planet>();
for (Planet p : planets) {
if (p.owner() >= 2) {
r.add(p);
}
}
return r;
}
// Return a list of all the planets that are not owned by the current
// player. This includes all enemy planets and neutral planets.
public List<Planet> notMyPlanets() {
List<Planet> r = new ArrayList<Planet>();
for (Planet p : planets) {
if (p.owner() != 1) {
r.add(p);
}
}
return r;
}
// Return a list of all the fleets.
public List<Fleet> fleets() {
List<Fleet> r = new ArrayList<Fleet>();
for (Fleet f : fleets) {
r.add(f);
}
return r;
}
// Return a list of all the fleets owned by the current player.
public List<Fleet> myFleets() {
List<Fleet> r = new ArrayList<Fleet>();
for (Fleet f : fleets) {
if (f.owner() == 1) {
r.add(f);
}
}
return r;
}
// Return a list of all the fleets owned by enemy players.
public List<Fleet> enemyFleets() {
List<Fleet> r = new ArrayList<Fleet>();
for (Fleet f : fleets) {
if (f.owner() != 1) {
r.add(f);
}
}
return r;
}
// Returns the distance between two planets, rounded up to the next highest
// integer. This is the number of discrete time steps it takes to get
// between the two planets.
public int distance(int sourcePlanet, int destinationPlanet) {
Planet source = planets.get(sourcePlanet);
Planet destination = planets.get(destinationPlanet);
double dx = source.x() - destination.x();
double dy = source.y() - destination.y();
return (int) Math.ceil(Math.sqrt(dx * dx + dy * dy));
}
// Returns the distance between two planets, rounded up to the next highest
// integer. This is the number of discrete time steps it takes to get
// between the two planets.
public int distance(Planet source, Planet destination) {
double dx = source.x() - destination.x();
double dy = source.y() - destination.y();
return (int) Math.ceil(Math.sqrt(dx * dx + dy * dy));
}
// Sends an order to the game engine. An order is composed of a source
// planet number, a destination planet number, and a number of ships. A
// few things to keep in mind:
// * you can issue many orders per turn if you like.
// * the planets are numbered starting at zero, not one.
// * you must own the source planet. If you break this rule, the game
// engine kicks your bot out of the game instantly.
// * you can't move more ships than are currently on the source planet.
// * the ships will take a few turns to reach their destination. Travel
// is not instant. See the Distance() function for more info.
public void issueOrder(int sourcePlanet, int destinationPlanet, int
numShips) {
System.out.println("" + sourcePlanet + " " + destinationPlanet + " "
+ numShips);
System.out.flush();
}
// Sends an order to the game engine. An order is composed of a source
// planet number, a destination planet number, and a number of ships. A
// few things to keep in mind:
// * you can issue many orders per turn if you like.
// * the planets are numbered starting at zero, not one.
// * you must own the source planet. If you break this rule, the game
// engine kicks your bot out of the game instantly.
// * you can't move more ships than are currently on the source planet.
// * the ships will take a few turns to reach their destination. Travel
// is not instant. See the Distance() function for more info.
public void issueOrder(Planet source, Planet dest, int numShips) {
System.out.println("" + source.planetID() + " " + dest.planetID() + " "
+ numShips);
System.out.flush();
}
// Sends the game engine a message to let it know that we're done sending
// orders. This signifies the end of our turn.
public void finishTurn() {
System.out.println("go");
System.out.flush();
}
// Returns true if the named player owns at least one planet or fleet.
// Otherwise, the player is deemed to be dead and false is returned.
public boolean isAlive(int playerID) {
for (Planet p : planets) {
if (p.owner() == playerID) {
return true;
}
}
for (Fleet f : fleets) {
if (f.owner() == playerID) {
return true;
}
}
return false;
}
// If the game is not yet over (ie: at least two players have planets or
// fleets remaining), returns -1. If the game is over (ie: only one player
// is left) then that player's number is returned. If there are no
// remaining players, then the game is a draw and 0 is returned.
public int winner() {
Set<Integer> remainingPlayers = new TreeSet<Integer>();
for (Planet p : planets) {
remainingPlayers.add(p.owner());
}
for (Fleet f : fleets) {
remainingPlayers.add(f.owner());
}
switch (remainingPlayers.size()) {
case 0:
return 0;
case 1:
return ((Integer) remainingPlayers.toArray()[0]).intValue();
default:
return -1;
}
}
// Returns the number of ships that the current player has, either located
// on planets or in flight.
public int numShips(int playerID) {
int numShips = 0;
for (Planet p : planets) {
if (p.owner() == playerID) {
numShips += p.numShips();
}
}
for (Fleet f : fleets) {
if (f.owner() == playerID) {
numShips += f.numShips();
}
}
return numShips;
}
// Returns the production of the given player.
public int production(int playerID) {
int prod = 0;
for (Planet p : planets) {
if (p.owner() == playerID) {
prod += p.growthRate();
}
}
return prod;
}
// Parses a game state from a string. On success, returns 1. On failure,
// returns 0.
private int parseGameState(String s) {
planets.clear();
fleets.clear();
int planetID = 0;
String[] lines = s.split("\n");
for (int i = 0; i < lines.length; ++i) {
String line = lines[i];
int commentBegin = line.indexOf('#');
if (commentBegin >= 0) {
line = line.substring(0, commentBegin);
}
if (line.trim().length() == 0) {
continue;
}
String[] tokens = line.split(" ");
if (tokens.length == 0) {
continue;
}
if (tokens[0].equals("P")) {
if (tokens.length != 6) {
return 0;
}
double x = Double.parseDouble(tokens[1]);
double y = Double.parseDouble(tokens[2]);
int owner = Integer.parseInt(tokens[3]);
int numShips = Integer.parseInt(tokens[4]);
int growthRate = Integer.parseInt(tokens[5]);
Planet p = new Planet(planetID++, owner, numShips, growthRate,
x, y);
planets.add(p);
} else if (tokens[0].equals("F")) {
if (tokens.length != 7) {
return 0;
}
int owner = Integer.parseInt(tokens[1]);
int numShips = Integer.parseInt(tokens[2]);
int source = Integer.parseInt(tokens[3]);
int destination = Integer.parseInt(tokens[4]);
int totalTripLength = Integer.parseInt(tokens[5]);
int turnsRemaining = Integer.parseInt(tokens[6]);
Fleet f = new Fleet(owner, numShips, source, destination,
totalTripLength, turnsRemaining);
fleets.add(f);
} else {
return 0;
}
}
return 1;
}
// Store all the planets and fleets. OMG we wouldn't wanna lose all the
// planets and fleets, would we!?
private ArrayList<Planet> planets;
private ArrayList<Fleet> fleets;
}
package shared;
public class Fleet implements Comparable<Fleet>, Cloneable {
private int owner;
private int numShips;
private int sourcePlanet;
private int destinationPlanet;
private int totalTripLength;
private int turnsRemaining;
public Fleet(int owner, int numShips, int sourcePlanet,
int destinationPlanet, int totalTripLength, int turnsRemaining) {
this.owner = owner;
this.numShips = numShips;
this.sourcePlanet = sourcePlanet;
this.destinationPlanet = destinationPlanet;
this.totalTripLength = totalTripLength;
this.turnsRemaining = turnsRemaining;
}
public Fleet(int owner, int numShips) {
this.owner = owner;
this.numShips = numShips;
this.sourcePlanet = -1;
this.destinationPlanet = -1;
this.totalTripLength = -1;
this.turnsRemaining = -1;
}
public int owner() {
return owner;
}
public int numShips() {
return numShips;
}
public int sourcePlanet() {
return sourcePlanet;
}
public int destinationPlanet() {
return destinationPlanet;
}
public int totalTripLength() {
return totalTripLength;
}
public int turnsRemaining() {
return turnsRemaining;
}
public void removeShips(int amount) {
numShips -= amount;
}
// Subtracts one turn remaining. Call this function to make the fleet get
// one turn closer to its destination.
public void TimeStep() {
if (turnsRemaining > 0) {
--turnsRemaining;
} else {
turnsRemaining = 0;
}
}
#Override
public int compareTo(Fleet f) {
return this.numShips - f.numShips;
}
private Fleet(Fleet _f) {
owner = _f.owner;
numShips = _f.numShips;
sourcePlanet = _f.sourcePlanet;
destinationPlanet = _f.destinationPlanet;
totalTripLength = _f.totalTripLength;
turnsRemaining = _f.turnsRemaining;
}
public Object clone() {
return new Fleet(this);
}
}
for (Planet p = pw.notMyPlanets()){ should be for (Planet p : pw.notMyPlanets()){.
You've not posted the Fleet class, so as it is the code won't compile for me. However, the above is the only other error I could see.

match and delete elements in arraylists

I am making a robot maze where the robot reaches a target automatically without crashing into walls. I want the robot to do the maze once, learn the correct route and then the second time be able to get there straight away without going to any deadends. I thought I could do this by making three arraylists.
One for all the squares the robot visits.
Two for all the squares that lead to a deadend.
Three for all the directions the robot goes.
If the squares that lead to a dead end are found in the first arraylist then i can delete the same indexes in the third arraylist. That way, the second time, i can just iterate the third Arraylist.
My full code is below:
import java.util.ArrayList;
import java.util.*;
import java.util.Iterator;
import java.util.stream.IntStream;
public class Explorer {
private int pollRun = 0; // Incremented after each pass.
private RobotData robotData; // Data store for junctions.
private ArrayList<Integer> nonWallDirections;
private ArrayList<Integer> passageDirections;
private ArrayList<Integer> beenbeforeDirections;
private Random random = new Random();
int [] directions = {IRobot.AHEAD, IRobot.LEFT, IRobot.RIGHT, IRobot.BEHIND};
private ArrayList<Square> correctSquares;
private ArrayList<Square> wrongSquares;
private ArrayList<Integer> correctDirections;
public void controlRobot (IRobot robot) {
// On the first move of the first run of a new maze.
if ((robot.getRuns() == 0) && (pollRun ==0))
robotData = new RobotData();
pollRun++; /* Increment poll run so that the data is not reset
each time the robot moves. */
int exits = nonwallExits(robot);
int direction;
if ((robot.getRuns() != 0))
direction = grandfinale(robot);
nonWallDirections = new ArrayList<Integer>();
passageDirections = new ArrayList<Integer>();
beenbeforeDirections = new ArrayList<Integer>();
correctSquares = new ArrayList<Square>();
correctDirections = new ArrayList<Integer>();
// Adding each direction to the appropriate state ArrayList.
for(int item : directions) {
if(robot.look(item) != IRobot.WALL) {
nonWallDirections.add(item);
}
}
for(int item : directions) {
if(robot.look(item) == IRobot.PASSAGE) {
passageDirections.add(item);
}
}
for(int item : directions) {
if(robot.look(item) == IRobot.BEENBEFORE) {
beenbeforeDirections.add(item);
}
}
// Calling the appropriate method depending on the number of exits.
if (exits < 2) {
direction = deadEnd(robot);
} else if (exits == 2) {
direction = corridor(robot);
} else {
direction = junction(robot);
robotData.addJunction(robot);
robotData.printJunction(robot);
}
robot.face(direction);
addcorrectSquares(robot);
correctDirections.add(direction);
}
/* The specification advised to have to seperate controls: Explorer and Backtrack
and a variable explorerMode to switch between them.
Instead, whenever needed I shall call this backtrack method.
If at a junction, the robot will head back the junction as to when it first approached it.
When at a deadend or corridor, it will follow the beenbefore squares until it
reaches an unexplored path. */
public int backtrack (IRobot robot) {
if (nonwallExits(robot) > 2) {
addwrongSquares(robot);
return robotData.reverseHeading(robot);
} else {
do {
addwrongSquares(robot);
return nonWallDirections.get(0);
} while (nonwallExits(robot) == 1);
}
}
// Deadend method makes the robot follow the only nonwall exit.
public int deadEnd (IRobot robot) {
return backtrack(robot);
}
/* Corridor method will make the robot follow the one and only passage.
The exception is at the start. Sometimes, the robot will start with
two passages available to it in which case it will choose one randomly.
If there is no passage, it will follow the beenbefore squares
until it reaches an unexplored path.*/
public int corridor (IRobot robot) {
if (passageExits(robot) == 1) {
return passageDirections.get(0);
} else if (passageExits(robot) == 2) {
int randomPassage = random.nextInt(passageDirections.size());
return passageDirections.get(randomPassage);
} else {
return backtrack(robot);
}
}
/* Junction method states if there is more than one passage, it will randomly select one.
This applies to crossroads as well as essentially they are the same.
If there is no passage, it will follow the beenbefore squares until it reaches an unexplored
path. */
public int junction(IRobot robot) {
if (passageExits(robot) == 1) {
return passageDirections.get(0);
} else if (passageExits(robot) > 1) {
int randomPassage = random.nextInt(passageDirections.size());
return passageDirections.get(randomPassage);
} else {
return backtrack(robot);
}
}
// Calculates number of exits.
private int nonwallExits (IRobot robot) {
int nonwallExits = 0;
for(int item : directions) {
if(robot.look(item) != IRobot.WALL) {
nonwallExits++;
}
}
return nonwallExits;
}
// Calculates number of passages.
private int passageExits (IRobot robot) {
int passageExits = 0;
for(int item : directions) {
if(robot.look(item) == IRobot.PASSAGE) {
passageExits++;
}
}
return passageExits;
}
// Calculates number of beenbefores.
private int beenbeforeExits (IRobot robot) {
int beenbeforeExits = 0;
for(int item : directions) {
if(robot.look(item) == IRobot.PASSAGE) {
beenbeforeExits++;
}
}
return beenbeforeExits;
}
// Resets Junction Counter in RobotData class.
public int reset() {
return robotData.resetJunctionCounter();
}
public void addcorrectSquares(IRobot robot) {
Square newSquare = new Square(robot.getLocation().x, robot.getLocation().y);
correctSquares.add(newSquare);
}
public void addwrongSquares(IRobot robot) {
Square badSquare = new Square(robot.getLocation().x, robot.getLocation().y);
wrongSquares.add(badSquare);
}
public int grandfinale (IRobot robot) {
IntStream.range(0, correctSquares.size())
.map(index -> correctSquares.size() - index - 1)
.filter(index -> (((wrongSquares.x).contains(correctSquares.x)) && ((wrongSquares.y).contains(correctSquares.y))).get(index))
.forEach(index -> correctDirections.remove(index));
Iterator<Integer> routeIterator = correctDirections.iterator();
while (routeIterator.hasNext()) {
break;
}
return (routeIterator.next());
}
}
class RobotData {
/* It was advised in the specification to include the variable:
private static int maxJunctions = 10000;
However, as I am not using arrays, but ArrayLists, I do not
need this. */
private static int junctionCounter = 0;
private ArrayList<Junction> junctionList = new ArrayList<Junction>();
// Resets the Junction counter.
public int resetJunctionCounter() {
return junctionCounter = 0;
}
// Adds the current junction to the list of arrays.
public void addJunction(IRobot robot) {
Junction newJunction = new Junction(robot.getLocation().x, robot.getLocation().y, robot.getHeading());
junctionList.add(newJunction);
junctionCounter++;
}
// Gets the junction counter for Junction info method in Junction class.
public int getJunctionCounter (IRobot robot) {
return junctionCounter;
}
// Prints Junction info.
public void printJunction(IRobot robot) {
String course = "";
switch (robot.getHeading()) {
case IRobot.NORTH:
course = "NORTH";
break;
case IRobot.EAST:
course = "EAST";
break;
case IRobot.SOUTH:
course = "SOUTH";
break;
case IRobot.WEST:
course = "WEST";
break;
}
System.out.println("Junction " + junctionCounter + " (x=" + robot.getLocation().x + ", y=" + robot.getLocation().y +") heading " + course);
}
/* Iterates through the junction arrayList to find the
heading of the robot when it first approached the junction.
It does this by finding the first junction in the ArrayList
that has the same x and y coordinates as the robot.*/
public int searchJunction(IRobot robot) {
Junction currentJunction = null;
Iterator<Junction> junctionIterator = junctionList.iterator();
while (junctionIterator.hasNext()) {
currentJunction = junctionIterator.next();
if ((((currentJunction.x)==(robot.getLocation().x))) && ((currentJunction.y)==(robot.getLocation().y)))
break;
}
return currentJunction.arrived;
}
// Returns the reverse of the heading the robot had when first approaching the junction.
public int reverseHeading(IRobot robot) {
int firstHeading = searchJunction(robot);
int reverseHeading = 1; // Random integer to Iniitalise variable.
switch (firstHeading) {
case IRobot.NORTH:
if (robot.getHeading() == IRobot.NORTH)
reverseHeading = IRobot.BEHIND;
else if (robot.getHeading() == IRobot.EAST)
reverseHeading = IRobot.RIGHT;
else if (robot.getHeading() == IRobot.SOUTH)
reverseHeading = IRobot.AHEAD;
else
reverseHeading = IRobot.LEFT;
break;
case IRobot.EAST:
if (robot.getHeading() == IRobot.NORTH)
reverseHeading = IRobot.LEFT;
else if (robot.getHeading() == IRobot.EAST)
reverseHeading = IRobot.BEHIND;
else if (robot.getHeading() == IRobot.SOUTH)
reverseHeading = IRobot.RIGHT;
else
reverseHeading = IRobot.AHEAD;
break;
case IRobot.SOUTH:
if (robot.getHeading() == IRobot.NORTH)
reverseHeading = IRobot.AHEAD;
else if (robot.getHeading() == IRobot.EAST)
reverseHeading = IRobot.LEFT;
else if (robot.getHeading() == IRobot.SOUTH)
reverseHeading = IRobot.BEHIND;
else
reverseHeading = IRobot.RIGHT;
break;
case IRobot.WEST:
if (robot.getHeading() == IRobot.NORTH)
reverseHeading = IRobot.RIGHT;
else if (robot.getHeading() == IRobot.EAST)
reverseHeading = IRobot.AHEAD;
else if (robot.getHeading() == IRobot.SOUTH)
reverseHeading = IRobot.LEFT;
else
reverseHeading = IRobot.BEHIND;
break;
}
return reverseHeading;
}
}
class Junction {
int x;
int y;
int arrived;
public Junction(int xcoord, int ycoord, int course) {
x = xcoord;
y = ycoord;
arrived = course;
}
}
class Square {
int x;
int y;
public Square(int cordx, int cordy){
x = cordx;
y = cordy;
}
}
IntStream.range(0, al1.length)
.filter(index -> al2.contains(al1.get(index)))
.forEach(index -> al3.remove(index));
Slightly more complex than this if removing elements from al3 shifts them left but in that case just reverse the stream before the .filter- then it will delete from the end. The easiest way to do that is:
.map(index -> al1.length - index - 1)
Without Streams the equivalent would be
for (int i = 0; i < al1.length; i++) {
if (al2.contains(al1.get(i))) {
al3.remove(i);
}
}
Similarly, if you need to delete from the right then the for loop would need to count down rather than up.
Without further details on arraylist structure it's hard to give any more hints.

Numbering A Crossword Java ACM Graphics

The problem asks for an acm graphics program that reads a txt file like this:
R
FUN
SALES
RECEIPT
MERE#FARM
DOVE###RAIL
MORE#####DRAW
HARD###TIED
LION#SAND
EVENING
EVADE
ARE
D
and makes a crossword puzzle, with blank squares on letters, black squares on '#', and nothing on empty spaces. The problem also asks that "if the square is at the beginning of a word running across, down, or both, the square should contain a number that is assigned sequentially through the puzzle."
I have the square drawing working, but I'm stuck on drawing the numbers correctly. There is something wrong with how I'm detecting null space and black squares. Can someone tell me what I'm doing wrong, please?
Here is the code:
import acm.program.*;
import java.io.*;
import java.util.*;
import acm.graphics.*;
import java.awt.*;
public class Crossword extends GraphicsProgram {
public void run() {
String fileName = "crosswordfile.txt";
makeCrosswordPuzzle(fileName);
}
private static final int sqCon = 15; // constant for square x and y dimensions
private int y = 0;
public void makeCrosswordPuzzle(String fileName) {
BufferedReader rd;
int y = 0; // y value for the square being added during that loop. increments by sqCon after every line
int wordNumber = 1; // variable for numbers added to certain boxes. increments every time the program adds a number
try {
rd = new BufferedReader(new FileReader(fileName));
String line = rd.readLine(); //reads one line of the text document at a time and makes it a string
while (line != null) {
int x = 0;
for (int i = 0; i < line.length(); i++) {
char lineChar = line.charAt(i);// the character being examined for each loop
GRect whiteSq = new GRect(sqCon,sqCon); //GRect for blank squares
GRect blackSq = new GRect(sqCon,sqCon);//GRect for black squares
blackSq.setFilled(true);
blackSq.setFillColor(Color.BLACK);
if (lineChar == '#'){
add (blackSq,x,y);
}
if (Character.isLetter(lineChar)) {
add (whiteSq, x, y);
// if the element above or to the left of the current focus is null or blackSq, place the number and then increment wordNumber
GObject above = getElementAt(x+sqCon/2,y-sqCon/2);
GObject left = getElementAt(x-sqCon/2, y+sqCon/2);
GLabel wordNumberLabel = new GLabel(Integer.toString(wordNumber));
if (above == null || left == null || above == blackSq || left == blackSq) {
add(wordNumberLabel,x,y+sqCon);
wordNumber++;
}
}
x += sqCon;
}
line = rd.readLine();
y += sqCon;
}
rd.close();
}
catch (IOException e) {
throw new ErrorException(e);
}
}
}
Edited to add:
I copied your code over to my Eclipse and ran it. Here's the result.
You did fine on the upper half, but you missed the down numbers on the lower half.
Here's the same code, reformatted so it's easier to read.
import java.awt.Color;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import acm.graphics.GLabel;
import acm.graphics.GObject;
import acm.graphics.GRect;
import acm.program.GraphicsProgram;
import acm.util.ErrorException;
public class Crossword extends GraphicsProgram {
private static final long serialVersionUID = -7971434624427958742L;
public void run() {
// String fileName = "crosswordfile.txt";
String fileName = "C:/Eclipse/eclipse-4.2-work/com.ggl.testing/crosswordfile.txt";
makeCrosswordPuzzle(fileName);
}
private static final int sqCon = 15; // constant for square x and y
// dimensions
private int y = 0;
public void makeCrosswordPuzzle(String fileName) {
BufferedReader rd;
int y = 0; // y value for the square being added during that loop.
// increments by sqCon after every line
int wordNumber = 1; // variable for numbers added to certain boxes.
// increments every time the program adds a number
try {
rd = new BufferedReader(new FileReader(fileName));
String line = rd.readLine(); // reads one line of the text document
// at a time and makes it a string
while (line != null) {
int x = 0;
for (int i = 0; i < line.length(); i++) {
char lineChar = line.charAt(i);// the character being
// examined for each loop
GRect whiteSq = new GRect(sqCon, sqCon); // GRect for blank
// squares
GRect blackSq = new GRect(sqCon, sqCon);// GRect for black
// squares
blackSq.setFilled(true);
blackSq.setFillColor(Color.BLACK);
if (lineChar == '#') {
add(blackSq, x, y);
}
if (Character.isLetter(lineChar)) {
add(whiteSq, x, y);
// if the element above or to the left of the current
// focus is null or blackSq, place the number and then
// increment wordNumber
GObject above = getElementAt(x + sqCon / 2, y - sqCon
/ 2);
GObject left = getElementAt(x - sqCon / 2, y + sqCon
/ 2);
GLabel wordNumberLabel = new GLabel(
Integer.toString(wordNumber));
if (above == null || left == null || above == blackSq
|| left == blackSq) {
add(wordNumberLabel, x, y + sqCon);
wordNumber++;
}
}
x += sqCon;
}
line = rd.readLine();
y += sqCon;
}
rd.close();
} catch (IOException e) {
throw new ErrorException(e);
}
}
}
I followed the advice of my own comment. I created the crossword puzzle answer, numbered the crossword puzzle answer, and finally drew the crossword puzzle answer.
Here's the applet result:
I kept a List of crossword puzzle cells. That way, I could determine the length and the width of the puzzle by the number of characters on a row and the number of rows of the input text file. I didn't have to hard code the dimensions.
For each crossword cell, I kept track of whether or not it was a letter, and whether or not it was a dark space.
When determining where to put the numbers, I followed 2 rules.
An across number is placed where the cell left of the cell is empty or dark, and there are three or more letters across.
A down number is placed where the cell above the cell is empty or dark, there are three or more letters down, and there is no across number.
You can see in the code that I had to do some debug printing to get the crossword puzzle clue numbering correct. I broke the process into many methods to keep each method as simple as possible.
Finally, I drew the crossword puzzle answer from the information in the List.
Here's the code:
import java.awt.Color;
import java.awt.Point;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import acm.graphics.GLabel;
import acm.graphics.GRect;
import acm.program.GraphicsProgram;
import acm.util.ErrorException;
public class Crossword extends GraphicsProgram {
private static final boolean DEBUG = false;
private static final long serialVersionUID = -7971434624427958742L;
private List<CrosswordCell> crosswordCellList;
#Override
public void run() {
this.crosswordCellList = new ArrayList<CrosswordCell>();
// String fileName = "crosswordfile.txt";
String fileName = "C:/Eclipse/eclipse-4.2-work/" +
"com.ggl.testing/crosswordfile.txt";
try {
readCrosswordAnswer(fileName);
if (DEBUG) printCrosswordAnswer();
numberCrosswordCells();
if (DEBUG) printCrosswordAnswer();
drawCrosswordAnswer();
} catch (FileNotFoundException e) {
throw new ErrorException(e);
} catch (IOException e) {
throw new ErrorException(e);
}
}
private void readCrosswordAnswer(String fileName)
throws FileNotFoundException, IOException {
BufferedReader reader =
new BufferedReader(new FileReader(fileName));
String line = "";
int row = 0;
while ((line = reader.readLine()) != null) {
for (int column = 0; column < line.length(); column++) {
CrosswordCell cell = new CrosswordCell(column, row);
char lineChar = line.charAt(column);
if (lineChar == '#') {
cell.setDarkCell(true);
} else if (Character.isLetter(lineChar)) {
cell.setLetter(true);
}
crosswordCellList.add(cell);
}
row++;
}
reader.close();
}
public void printCrosswordAnswer() {
for (CrosswordCell cell : crosswordCellList) {
System.out.println(cell);
}
}
private void numberCrosswordCells() {
int clueNumber = 1;
for (CrosswordCell cell : crosswordCellList) {
if (cell.isLetter()) {
clueNumber = testCell(cell, clueNumber);
}
}
}
private int testCell(CrosswordCell cell, int clueNumber) {
Point p = cell.getLocation();
CrosswordCell leftCell = getLeftCell(p.x, p.y);
List<CrosswordCell> acrossList = getRightCells(p.x, p.y);
if (DEBUG) {
System.out.print(p);
System.out.println(", " + leftCell + " " +
acrossList.size());
}
if ((leftCell == null) && (acrossList.size() >= 3)) {
cell.setClueNumber(clueNumber++);
} else {
CrosswordCell aboveCell = getAboveCell(p.x, p.y);
List<CrosswordCell> downList = getBelowCells(p.x, p.y);
if (DEBUG) {
System.out.print(p);
System.out.println(", " + aboveCell + " " +
downList.size());
}
if ((aboveCell == null) && (downList.size() >= 3)) {
cell.setClueNumber(clueNumber++);
}
}
return clueNumber;
}
private CrosswordCell getAboveCell(int x, int y) {
int yy = y - 1;
return getCell(x, yy);
}
private CrosswordCell getLeftCell(int x, int y) {
int xx = x - 1;
return getCell(xx, y);
}
private List<CrosswordCell> getBelowCells(int x, int y) {
List<CrosswordCell> list = new ArrayList<CrosswordCell>();
for (int i = y; i < (y + 3); i++) {
CrosswordCell cell = getCell(x, i);
if (cell != null) {
list.add(cell);
}
}
return list;
}
private List<CrosswordCell> getRightCells(int x, int y) {
List<CrosswordCell> list = new ArrayList<CrosswordCell>();
for (int i = x; i < (x + 3); i++) {
CrosswordCell cell = getCell(i, y);
if (cell != null) {
list.add(cell);
}
}
return list;
}
private CrosswordCell getCell(int x, int y) {
for (CrosswordCell cell : crosswordCellList) {
Point p = cell.getLocation();
if ((p.x == x) && (p.y == y)) {
if (cell.isDarkCell()) {
return null;
} else if (cell.isLetter()){
return cell;
} else {
return null;
}
}
}
return null;
}
private void drawCrosswordAnswer() {
int sqCon = 32;
for (CrosswordCell cell : crosswordCellList) {
Point p = cell.getLocation();
if (cell.isDarkCell()) {
drawDarkCell(p, sqCon);
} else if (cell.isLetter()) {
drawLetterCell(cell, p, sqCon);
}
}
}
private void drawDarkCell(Point p, int sqCon) {
GRect blackSq = new GRect(sqCon, sqCon);
blackSq.setFilled(true);
blackSq.setFillColor(Color.BLACK);
add(blackSq, p.x * sqCon, p.y * sqCon);
}
private void drawLetterCell(CrosswordCell cell, Point p, int sqCon) {
GRect whiteSq = new GRect(sqCon, sqCon);
add(whiteSq, p.x * sqCon, p.y * sqCon);
if (cell.getClueNumber() > 0) {
String label = Integer.toString(cell.getClueNumber());
GLabel wordNumberLabel = new GLabel(label);
add(wordNumberLabel, p.x * sqCon + 2, p.y * sqCon + 14);
}
}
class CrosswordCell {
private boolean darkCell;
private boolean isLetter;
private int clueNumber;
private Point location;
public CrosswordCell(int x, int y) {
this.location = new Point(x, y);
this.clueNumber = 0;
this.darkCell = false;
this.isLetter = false;
}
public boolean isDarkCell() {
return darkCell;
}
public void setDarkCell(boolean darkCell) {
this.darkCell = darkCell;
}
public boolean isLetter() {
return isLetter;
}
public void setLetter(boolean isLetter) {
this.isLetter = isLetter;
}
public int getClueNumber() {
return clueNumber;
}
public void setClueNumber(int clueNumber) {
this.clueNumber = clueNumber;
}
public Point getLocation() {
return location;
}
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("CrosswordCell [location=");
builder.append(location);
builder.append(", clueNumber=");
builder.append(clueNumber);
builder.append(", darkCell=");
builder.append(darkCell);
builder.append(", isLetter=");
builder.append(isLetter);
builder.append("]");
return builder.toString();
}
}
}

How do I get one client thread to sleep, in order for the another client to execute?

I am working on a client/server Tic-Tac-Toe game that consists of one server, and a client that consists of two threads. The entire program includes a TicTacToeServer class, TicTacToeService class, and TicTacToeClientPanel (which is the GUI and the client put together).
The main problem I am facing is within the client class itself. I launch two windows of the GUI/client (for the two different players), and am able to place one marker (X) on the first player. After this, the threads seem to halt, and I am unable to continue playing the game.
If I attempt to put client 1's (player 1) thread to sleep, it sleeps for its given allotment, but client 2's (player 2) thread never begins.
Is there any way that I can alternate between these two threads and go through my program, dependent on which player's turn it is?
import java.awt.*; //Color and GridLayout
import java.awt.event.*;
import java.io.*; //DataInputStream & DataOutputStream
import java.net.Socket;
import java.util.Scanner;
import javax.swing.*; //JPanel & JPanel
import javax.swing.border.LineBorder;
/**
* This is the Main Panel for the TicTacToe Client.
* It uses a displayBoard of Cell objects to display the TicTacToe board
* #author Professor Myers
*
*/
public class TicTacToeClientPanel extends JPanel implements Runnable {
//instance variables and constants
private Cell displayBoard[][] = new Cell[3][3];
private Scanner fromServer;
private PrintWriter out;
private Boolean myTurn, waiting, inputReady;
private Thread thread;
private char mySymbol;
private int rowSelected, columnSelected;
private JLabel statusLabel, playerInfo;
public static final int PLAYER1 = 1, PLAYER2 = 2;
public TicTacToeClientPanel()
{
//give initial values to instance variables
mySymbol = ' ';
myTurn = false;
JPanel sub1 = new JPanel();
playerInfo = new JLabel("");
statusLabel = new JLabel("");
sub1.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
//initialize Cells in board array and add to display
for (int y = 0; y < 3; y++)
{
for (int x = 0; x < 3; x++)
{
displayBoard[y][x] = new Cell(x+1, y+1);
c.gridx = y;
c.gridy = x;
c.fill = GridBagConstraints.BOTH;
sub1.add(displayBoard[y][x], c);
}
}
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
add(new JPanel().add(playerInfo));
add(sub1);
add(new JPanel().add(statusLabel));
connectToServer();
}
private void connectToServer()
{
try
{
//create socket
//set up Scanner and PrintWriter
Socket s = new Socket("localhost", 8880);
InputStream instream = s.getInputStream();
OutputStream outstream = s.getOutputStream();
fromServer = new Scanner(instream);
out = new PrintWriter(outstream);
}
catch (Exception e)
{
System.err.println(e);
}
//start the thread
thread = new Thread(this);
thread.start();
}
public void run()
{
int otherPRow, otherPColumn;
try {
int player = Integer.parseInt(fromServer.nextLine()); //Begin the game
int message = 0;
//set up symbol
//keep track of who's turn it is
//Display the player number and symbol (JLabel)
//Display the status of the player (who's turn is it)
if (player == PLAYER1) {
mySymbol = 'X';
playerInfo.setText("Player 1 with symbol \'X\'");
statusLabel.setText("My turn");
myTurn = true; //player1 goes first
message = Integer.parseInt(fromServer.nextLine());
}
else if (player == PLAYER2) {
mySymbol = 'O';
playerInfo.setText("Player 2 with symbol \'O\'");
statusLabel.setText("Waiting for Player 1 to move");
//what to do with waiting?
myTurn = false;
while (!myTurn) {
if (fromServer.hasNextLine()) {
System.out.println("ITS HAPPENING");
myTurn = true;
thread.setPriority(thread.MAX_PRIORITY);
}
}
}
while(message != 1 && message != 2 && message != 3) //CHANGE TO GAME NOT OVER
{
if(player == PLAYER1)
{
//wait for user to select a cell - sleep for awhile
//"write" the row and column to server
//"read" from the server - perform the appropriate action
//this code is only reached if server passes 5 or 4 to the first player
if (myTurn) {
waiting = true;
while(waiting) {
Thread.sleep(1000);
} //thread sleeps until something is clicked
}
//if this cell value is not empty (WRITE)
if (displayBoard[rowSelected-1][columnSelected-1].getSymbol() != ' ') {
System.out.println("Success");
out.println(rowSelected + '\n' + columnSelected);
out.flush();
statusLabel.setText("Waiting for Player 2 to move");
}
waiting = true;
while (waiting)
Thread.currentThread().sleep(1000);
//READ from server
message = Integer.parseInt(fromServer.nextLine());
if (message == 1) {
statusLabel.setText("I Won! (X)");
return;
}
else if (message == 2) {
//update from player 2's turn
otherPRow = Integer.parseInt(fromServer.nextLine());
otherPColumn = Integer.parseInt(fromServer.nextLine());
displayBoard[otherPRow-1][otherPColumn-1].setSymbol('O');
statusLabel.setText("Player 2 has won (O)");
return;
}
else if (message == 3) {
//update from player 2's turn
otherPRow = Integer.parseInt(fromServer.nextLine());
otherPColumn = Integer.parseInt(fromServer.nextLine());
displayBoard[otherPRow-1][otherPColumn-1].setSymbol('O');
statusLabel.setText("Game is over, no winner");
return;
}
else if (message == 4) { //traverses back to beginning of loop
otherPRow = Integer.parseInt(fromServer.nextLine());
otherPColumn = Integer.parseInt(fromServer.nextLine()); //What kind does it send? normal or +1?
displayBoard[otherPRow-1][otherPColumn-1].setSymbol('O');
statusLabel.setText("My turn");
myTurn = true;
}
}
else if(player == PLAYER2)
{
//"read" from the server - perform the appropriate action
//wait for the user to select a cell - sleep for a while
//"write" the row and column to server
myTurn = true;
statusLabel.setText("My turn");
message = Integer.parseInt(fromServer.nextLine());
System.out.println(message);
//player1 has won or game is full
if (message == 1 || message == 3) {
otherPRow = Integer.parseInt(fromServer.nextLine());
otherPColumn = Integer.parseInt(fromServer.nextLine());
displayBoard[otherPRow-1][otherPColumn-1].setSymbol('X');
if (message == 1) {
statusLabel.setText("Player 1 (X) won");
return;
}
else {
statusLabel.setText("Game is over, no winner");
return;
}
}
else if (message == 2) { //player2 has won
statusLabel.setText("I won! (O)");
return;
}
else if (message == 4) {
otherPRow = Integer.parseInt(fromServer.nextLine());
otherPColumn = Integer.parseInt(fromServer.nextLine());
displayBoard[otherPRow-1][otherPColumn-1].setSymbol('X');
//SLEEP for user input
statusLabel.setText("My turn");
myTurn = true;
waiting = true;
while (waiting) {
Thread.sleep(1000);
}
//WRITE to server
char s = displayBoard[rowSelected-1][columnSelected-1].getSymbol();
if (s != ' ' && s != 'X' && waiting == false) {
out.println(rowSelected + '\n' + columnSelected);
out.flush();
}
statusLabel.setText("Waiting for Player 1 to move");
if (!myTurn)
Thread.currentThread().sleep(10000);
}
}
}
}
catch (Exception e)
{
}
}
public class Cell extends JPanel
{
int row;
int column;
private char symbol;
public Cell(int r, int c)
{
row = r;
column = c;
symbol = ' ';
setBorder(new LineBorder(Color.black,1));
setPreferredSize(new Dimension(100,150));
addMouseListener(new ClickListener());
}
public void setSymbol(char c)
{
symbol = c;
repaint();
}
public char getSymbol()
{
return symbol;
}
protected void paintComponent (Graphics g)
{
super.paintComponent(g);
if(symbol == 'X')
{
g.drawLine(10, 10, getWidth()-10, getHeight()-10);
g.drawLine(getWidth()-10, 10, 10, getHeight()-10);
}
else if(symbol == 'O')
{
g.drawOval(10, 10, getWidth()-10, getHeight()-20);
}
}
private class ClickListener extends MouseAdapter
{
public void mouseClicked(MouseEvent e)
{
System.out.println("Clicked: " + row + " " + column);
if(symbol == ' ' && myTurn)
{
setSymbol(mySymbol);
myTurn = false;
rowSelected = row;
columnSelected = column;
statusLabel.setText("Waiting for the other player to move");
waiting = false;
}
}
}
}
public static void main (String[] args)
{
JFrame frame = new JFrame();
frame.setBounds(0, 0, 1000, 1200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TicTacToeClientPanel ttt = new TicTacToeClientPanel();
frame.getContentPane().add(ttt);
frame.pack();
frame.setVisible(true);
}
}
I quickly looked at your code. One tip: the variable waiting is not volatile. Therefore, there is no guarantee that the following loop will ever end:
waiting = true;
while(waiting) {
Thread.sleep(1000);
} //thread sleeps until something is clicked
On a mouse click waiting is set to false. That happens in a different thread. Because the variable waiting is not volatile, the JVM is allowed to optimize the above loop to:
while (true) {
Thread.sleep(1000);
}
Try making waiting volatile. That forces each write to this variable to become visible by other threads. If the variable is not volatile, then each thread may keep its own local copy of this variable.

Categories