Server Side Client Side JAVA game moves - java

I'm new to server-client coding. I have a project making a 3 stones game, I am supposed to make a connection between the client and the server. I connect the client to the server but I don't know how can I pass the client's moves (Point's coordinates) to the server and then return the proper message from the server to the client. and I don't know what is byte[] data does also the BUFFSize
Can you please explain why I have to use byte[] also BUFFSIZE? and how can I hell server where the client placed the stone on the board?
CilentSide :
public class ThreeStonesGameClientSide {
private static final int BUFSIZE = 32;
private final static org.slf4j.Logger LOG = LoggerFactory.getLogger(ThreeStonesGameClientSide.class);
private String ip;
private int port;
public ThreeStonesGameClientSide(String ip, int port) {
this.ip = ip;
this.port = port;
}
public void connectToServer() throws IOException {
Socket socket = new Socket(this.ip, this.port);
LOG.info("Connected to the server");
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
Point recivedPoint = new Point();
int x = (int) recivedPoint.getX();
int y = (int) recivedPoint.getY();
byte[] data = new byte[BUFSIZE];
// Receive the same string back from the server
int totalBytesRcvd = 0; // Total bytes received so far
int bytesRcvd; // Bytes received in last read
while (totalBytesRcvd < data.length) {
if ((bytesRcvd = in.read(data, totalBytesRcvd,
data.length - totalBytesRcvd)) == -1) {
throw new SocketException("Connection closed prematurely");
}
totalBytesRcvd += bytesRcvd;
} // data array is full
System.out.println("Received: " + new String(data));
socket.close(); // Close the socket and its streams
}
}
and this is the Server-side
public class ThreeStonesGameClientSide {
private static final int BUFSIZE = 32;
private final static org.slf4j.Logger LOG = LoggerFactory.getLogger(ThreeStonesGameClientSide.class);
private String ip;
private int port;
public ThreeStonesGameClientSide(String ip, int port) {
this.ip = ip;
this.port = port;
}
public void connectToServer() throws IOException {
Socket socket = new Socket(this.ip, this.port);
LOG.info("Connected to the server");
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
Point recivedPoint = new Point();
int x = (int) recivedPoint.getX();
int y = (int) recivedPoint.getY();
byte[] data = new byte[BUFSIZE];
// Receive the same string back from the server
int totalBytesRcvd = 0; // Total bytes received so far
int bytesRcvd; // Bytes received in last read
while (totalBytesRcvd < data.length) {
if ((bytesRcvd = in.read(data, totalBytesRcvd,
data.length - totalBytesRcvd)) == -1) {
throw new SocketException("Connection closed prematurely");
}
totalBytesRcvd += bytesRcvd;
} // data array is full
System.out.println("Received: " + new String(data));
socket.close(); // Close the socket and its streams
}
}
this is the Board class
public class Board implements Serializable {
public final IntegerProperty numOfWhiteStones;
public final IntegerProperty numOfBlackStones;
public final ObjectProperty<Stone[][]> board;
private Point lastPoint;
public Board(Player p1, Player p2) {
this.numOfBlackStones = new SimpleIntegerProperty();
this.numOfWhiteStones = new SimpleIntegerProperty();
this.board = new SimpleObjectProperty<Stone[][]>(new Stone[11][11]);
}
/**
* Checks if chosen point is along the same x and y axis as the last placed point.
* #param placementPoint
* #return
*/
public boolean checkSlot(Point placement) {
Stone[][] board = getBoard();
int x = placement.x;
int y = placement.y;
// Check if placement is within the limits of the inner arry
if ((x < 0 || x > board.length - 1) && (y < 0 || y > board.length - 1)) {
return false;
}
// Check if place on board is empty
if (board[x][y] != Stone.EMPTY) {
return false;
}
if (lastPoint == null){
return true;
}
// Check if placement is within the same colum or row as the last played stone
return (x == lastPoint.x ^ y == lastPoint.y);
}
public void placeStone(Point placement, Stone stone) {
Stone[][] board = getBoard();
int x = placement.x;
int y = placement.y;
board[x][y] = stone;
if (stone == Stone.BLACK) {
numOfBlackStones.add(1);
} else {
numOfWhiteStones.add(1);
}
lastPoint = placement;
}
public int calculatePointsFor(Stone stone) {
Stone[][] board = this.board.get();
int counter = 0;
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board.length; j++) {
for (int k = 0; k < 4; k++) {
if (directionCheck(stone, new Point(i, j), k)){
counter++;
}
}
}
}
return counter;
}
boolean directionCheck(Stone stone, Point coord, int direction) {
Stone[][] board = getBoard();
int x = coord.x;
int y = coord.y;
switch (direction) {
case 0:
if (coord.x + 2 < board.length) {
return (board[x][y] == board[x + 1][y] && board[x + 1][y] == board[x + 2][y]);
}
break;
case 1:
if ((coord.x + 2 < board.length) && (coord.y + 2 < board.length)) {
return (board[x][y] == board[x + 1][y + 1] && board[x + 1][y + 1] == board[x + 2][y + 2]);
}
break;
case 2:
if (coord.y + 2 < board.length) {
return (board[x][y] == board[x][y + 1] && board[x][y + 1] == board[x][y + 2]);
}
break;
case 3:
if ((coord.x - 2 >= 0) && (coord.y + 2 < board.length)) {
return (board[x][y] == board[x - 1][y + 1] && board[x - 1][y + 1] == board[x - 2][y + 2]);
}
break;
}
return false;
}
public final Stone[][] getBoard() {
return board.get();
}
public void setBoard(final Stone[][] isbn) {
this.board.set(isbn);
}
public final ObjectProperty boardProperty() {
return board;
}
public final int getNumOfWhiteStones() {
return numOfWhiteStones.get();
}
public final IntegerProperty numOfWhiteStonesProperty() {
return numOfWhiteStones;
}
public final int getNumOfBlackStones() {
return numOfBlackStones.get();
}
public final IntegerProperty numOfBlackStonesProperty() {
return numOfBlackStones;
}
public final Point getLastPoint() {
return lastPoint;
}
}

for your questions, IMHO:
All the data sent over the network should be in bytes array, it concerns the byte orders (Endianness) and you can check more definitions in Wiki. And if it in byte array you can do some tricks to make it as small as possible. In the network, it can a lot of problems occur, so with less data transfer, the harder it is to lose. For the byte data transfer, you can check out my small functions here: Pack data with Msgpack libraries Endianness converting
The server you created should handle all logic in-game, and the client-side is only for viewing. For example: When a client makes a moving, he only sends his action (ID of the moving object, the new object's target, ...). After that, the server must confirm that the message's information, take the calculation itself and return the results to all corresponding clients. I wrote a small project, so you can check out the examples for more detail: NIO java server game framework with examples

Related

Java Sockets - Unable to enter second input on client side [EDIT]

I am trying to make a Connect 5 game, where the game logic is held on the server side, with the client side influencing the current game state. So far, I have the game logic implemented and it works just fine if you were to run it. I am running into issues when trying to implement the actual client/server sider of things.
I am not exactly sure how to go about doing it. What I can do at the moment is get the player names and the size of the board. When it comes to actually playing the game, I run into some issues such as keeping the game running and getting the player's move. Currently the server will stop running after a short period of time. I have tried using a while(true) to keep it running but it doesn't seem to work.
Another issue is displaying the actual board on the client side - while I am able to display the board if you were to just play the game from the server class using System.out.println(fiveInARow);, which displays the board after every move. I have tried using How to send String array Object over Socket? to display the board (testing if I can even just get the empty board at the start of the game to display on the client side), I get an error.
Should I be doing something like How to get input from Console in Java Client Server Program to get an input from the user inside the for (int player = 0; moves-- > 0; player = 1 - player)?
UPDATED: So I'm able to make a move and the move will be played accordingly. However, the second player is unable to make a move (unable to enter input on client side after first input).
Server
import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
class FiveInARow implements Runnable {
private ArrayList<String> playerNames = new ArrayList<String>();
private String currPlayer;
private Socket socket;
private Scanner scanner;
private int width, height;
private static final char[] PLAYERS = { 'X', 'O' };
private char[][] gameBoard;
private int lastCol = -1, lastRow = -1;
public FiveInARow(Socket socket) {
this.socket = socket;
}
/**
*
* #param w - Width
* #param h - Height
* #param p1 - Player 1
* #param p2 - Player 2
*/
public FiveInARow(int w, int h, String p1, String p2) {
width = w;
height = h;
gameBoard = new char[h][];
playerNames.add(p1);
playerNames.add(p2);
for (int i = 0; i < h; i++) {
Arrays.fill(gameBoard[i] = new char[w], '.');
}
}
// Display the game board
public String toString() {
return IntStream.range(0, width).mapToObj(Integer::toString).collect(Collectors.joining("")) + "\n"
+ Arrays.stream(gameBoard).map(String::new).collect(Collectors.joining("\n"));
}
// Get string representation of the row containing the last play of the user
public String horizontal() {
return new String(gameBoard[lastRow]);
}
// Get string representation of the column containing the last play of the user
public String vertical() {
StringBuilder stringBuilder = new StringBuilder(height);
for (int h = 0; h < height; h++) {
stringBuilder.append(gameBoard[h][lastCol]);
}
return stringBuilder.toString();
}
// Get string representation of the "/" diagonal containing the last play of the
// user
public String fowardSlashDiagonal() {
StringBuilder stringBuilder = new StringBuilder(height);
for (int h = 0; h < height; h++) {
int w = lastCol + lastRow - h;
if (w >= 0 && w < width) {
stringBuilder.append(gameBoard[h][w]);
}
}
return stringBuilder.toString();
}
/**
* Get string representation of the "\" diagonal containing the last play of the
* user
*
* #return
*/
public String backSlashDiagonal() {
StringBuilder stringBuilder = new StringBuilder(height);
for (int h = 0; h < height; h++) {
int w = lastCol - lastRow + h;
if (0 <= w && w < width) {
stringBuilder.append(gameBoard[h][w]);
}
}
return stringBuilder.toString();
}
public static boolean contains(String str, String subString) {
return str.indexOf(subString) >= 0;
}
// Determine if a game as been won
public boolean hasWon() {
if (lastCol == -1) {
System.err.println("No move has been made yet");
return false;
}
char symbol = gameBoard[lastRow][lastCol];
String streak = String.format("%c%c%c%c%c", symbol, symbol, symbol, symbol, symbol);
return contains(horizontal(), streak) || contains(vertical(), streak) || contains(fowardSlashDiagonal(), streak)
|| contains(backSlashDiagonal(), streak);
}
/**
*
* #param symbol - Symbol/piece to be played
* #param scanner - Input
*/
public void playMove(char symbol, Scanner scanner) {
do {
if (symbol == PLAYERS[0]) {
currPlayer = playerNames.get(0);
} else {
currPlayer = playerNames.get(1);
}
System.out.println("\n" + currPlayer + "'s turn: ");
int col = scanner.nextInt();
// Check if input is valid
if (!(0 <= col && col < width)) {
System.out.println("Column must be between 0 and " + (width - 1));
continue;
}
for (int h = height - 1; h >= 0; h--) {
if (gameBoard[h][col] == '.') {
gameBoard[lastRow = h][lastCol = col] = symbol;
return;
}
}
// If column has already been filled, we need to ask for a new input
System.out.println("Column " + col + " is full");
} while (true);
}
// public static void main(String[] args) {
// try (Scanner input = new Scanner(System.in)) {
// String player1Name, player2Name;
// int height = 6;
// int width = 9;
// int moves = height * width;
//
// System.out.println("Player 1 name: ");
// player1Name = input.next();
//
// System.out.println("Player 2 name: ");
// player2Name = input.next();
//
// FiveInARow fiveInARow = new FiveInARow(width, height, player1Name, player2Name);
//
// System.out.println("Enter 0 - " + (width - 1) + " to play a piece\n");
//
// System.out.println(fiveInARow);
//
// for (int player = 0; moves-- > 0; player = 1 - player) {
// char symbol = PLAYERS[player];
//
// fiveInARow.playMove(symbol, input);
//
// System.out.println(fiveInARow);
//
// if (fiveInARow.hasWon()) {
// System.out.println("\nPlayer " + symbol + " wins!");
//
// return;
// }
// }
//
// System.out.println("Game over. Draw game!");
// }
// }
#Override
public void run() {
int height = 6;
int width = 9;
int moves = height * width;
System.out.println("Connected: " + socket);
try {
FiveInARow fiveInARow = new FiveInARow(width, height, "Kevin", "Fasha");
Scanner scanner = new Scanner(socket.getInputStream());
PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true);
// while (scanner.hasNextInt()) {
// printWriter.println(scanner.nextInt());
// }
System.out.println(fiveInARow);
// while (scanner.hasNextInt()) {
for (int player = 0; moves-- > 0; player = 1 - player) {
char symbol = PLAYERS[player];
fiveInARow.playMove(symbol, scanner);
System.out.println(fiveInARow);
if (fiveInARow.hasWon()) {
System.out.println("\nPlayer " + symbol + " wins!");
return;
}
// }
}
} catch (Exception exception) {
System.out.println("Error: " + socket);
} finally {
try {
socket.close();
} catch (IOException e) {
}
System.out.println("Closed: " + socket);
}
}
public static void main(String[] args) throws Exception {
try (ServerSocket serverSocket = new ServerSocket(59898)) {
System.out.println("The game server is running...");
ExecutorService pool = Executors.newFixedThreadPool(20);
while (true) {
pool.execute(new FiveInARow(serverSocket.accept()));
}
}
}
}
Client
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
public class FiveInARowClient {
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.err.println("Pass the server IP as the sole command line argument");
return;
}
try (Socket socket = new Socket(args[0], 59898)) {
System.out.println("Enter lines of text then Ctrl+D or Ctrl+C to quit");
Scanner scanner = new Scanner(System.in);
Scanner in = new Scanner(socket.getInputStream());
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
while (scanner.hasNextLine()) {
out.println(scanner.nextLine());
System.out.println(in.nextLine());
}
}
}
}

Android - An algorithm to check recursively if a map is solvable

I am making an android Hashikawekero puzzle game, I have implemented a algorithm to spawn nodes (Islands) at random positions using a 2-d array this works fine it creates the node at random position but most of the times the map cant be solved. The map nodes spawn at random.
BoardCreation.java Class - this generates the map.
package Island_and_Bridges.Hashi;
import android.annotation.TargetApi;
import android.os.Build;
import android.util.Log;
import java.util.Random;
import static junit.framework.Assert.*;
//This class Creates the map by random using a 2d array
public class BoardCreation {
// This class member is used for random initialization purposes.
static private final Random random = new Random();
// The difficulty levels.
private static final int EASY = 0;
static public final int MEDIUM = 1;
static public final int HARD = 2;
static public final int EMPTY = 0;
private static int ConnectionFingerprint(BoardElement start, BoardElement end) {
int x = start.row * 100 + start.col;
int y = end.row * 100 + end.col;
// Swap to get always the same fingerprint independent whether we are called
// start-end or end-start
if (x > y ) {
int temp = x;
x = y;
y = temp;
}
Log.d("", String.format("%d %d" , x ,y));
return x ^ y;
}
public class State {
// The elements of the board are stored in this array.
// A value defined by "EMPTY" means that its not set yet.
public BoardElement [][] board_elements = null;
public int [][] cell_occupied = null;
// The width of the board. We only assume squared boards.
public int board_width=0;
public State(int width) {
board_width = width;
board_elements = new BoardElement[width][width];
cell_occupied = new int[width][width];
}
public State CloneWithoutConnections() {
State newstate = new State(board_width);
if (board_elements != null) {
newstate.board_elements = new BoardElement[board_elements.length][board_elements.length];
for (int i = 0; i < board_elements.length; ++i) {
for (int j = 0; j < board_elements.length; ++j) {
if (board_elements[i][j] == null)
continue;
newstate.board_elements[i][j] = board_elements[i][j].clone();
}
}
}
if (cell_occupied != null) {
assert board_elements != null;
newstate.cell_occupied = new int[board_elements.length][board_elements.length];
for (int i = 0; i < board_elements.length; ++i) {
System.arraycopy(cell_occupied[i], 0, newstate.cell_occupied[i], 0, board_elements.length);
}
}
return newstate;
}
public void AddToBridgeCache(BoardElement first, BoardElement second) {
if (first == null || second == null) { return; }
final int fingerprint = ConnectionFingerprint(first, second);
Log.d(getClass().getName(),
String.format("Fingerprint of this bridge %d", fingerprint));
// mark the end points as occupied.
cell_occupied[first.row][first.col] = fingerprint;
cell_occupied[second.row][second.col] = fingerprint;
int dcol = second.col - first.col;
int drow = second.row - first.row;
if (first.row == second.row) {
for (int i = (int) (first.col + Math.signum(dcol)); i != second.col; i += Math.signum(dcol)) {
cell_occupied[first.row][i] = fingerprint;
String.format("deleting bridge");
}
} else {
assert first.col == second.col;
for (int i = (int) (first.row + Math.signum(drow)); i != second.row; i+= Math.signum(drow)) {
cell_occupied[i][first.col] = fingerprint;
}
}
}
} // end of state
private State current_state, old_state;
static private final int WIDTH_EASY = 7;
private void NewGame(int hardness) {
switch(hardness) {
case EASY:
Log.d(getClass().getName(), "Initializing new easy game");
InitializeEasy();
old_state = getCurrentState().CloneWithoutConnections();
break;
}
}
public void ResetGame() {
if (old_state != null) {
Log.d(getClass().getName(), "Setting board_elements to old_elements");
setCurrentState(old_state.CloneWithoutConnections());
} else {
Log.d(getClass().getName(), "old_lements are zero");
}
}
public BoardCreation(int hardness) {
NewGame(hardness);
}
public boolean TryAddNewBridge(BoardElement start, BoardElement end, int count) {
assertEquals(count, 1);
assert (start != null);
assert (end != null);
final int fingerprint = ConnectionFingerprint(start, end);
Log.d(getClass().getName(),
String.format("considering (%d,%d) and (%d,%d)", start.row,start.col, end.row,end.col));
if (start.row == end.row && start.col == end.col) {
Log.d(getClass().getName(), "Same nodes selected!");
return false;
}
assert count > 0;
int dcol = end.col - start.col;
int drow = end.row - start.row;
// It must be a vertical or horizontal bridge:
if (Math.abs(dcol) > 0 && Math.abs(drow) > 0) {
Log.d(getClass().getName(), "not a horizontal or vertical bridge.");
return false;
}
// First we check whether start and end elements can take the specified bridge counts.
int count_start = start.GetCurrentCount();
int count_end = end.GetCurrentCount();
if (count_start + count > start.max_connecting_bridges ||
count_end + count > end.max_connecting_bridges) {
Log.d(getClass().getName(), "This Bridge is not allowed");
return false;
}
Log.d(getClass().getName(),
String.format("Sums:%d # (%d,%d) and %d # (%d,%d)",
count_start, start.row, start.col,
count_end, end.row, end.col));
Connection start_connection = null;
Connection end_connection = null;
// Next we check whether we are crossing any lines.
if (start.row == end.row) {
for (int i = (int) (start.col + Math.signum(dcol)); i != end.col; i += Math.signum(dcol)) {
if (getCurrentState().cell_occupied[start.row][i] > 0 &&
getCurrentState().cell_occupied[start.row][i] != fingerprint) {
Log.d(getClass().getName(), "Crossing an occupied cell.");
return false;
}
}
assert start.col != end.col;
if (start.col > end.col) {
start.connecting_east = GetOrCreateConnection(end, start.connecting_east);
end.connecting_west = GetOrCreateConnection(start, end.connecting_west);
start_connection = start.connecting_east;
end_connection = end.connecting_west;
} else {
start.connecting_west = GetOrCreateConnection(end, start.connecting_west);
end.connecting_east = GetOrCreateConnection(start, end.connecting_east);
start_connection = start.connecting_west;
end_connection = end.connecting_east;
}
} else {
assert start.col == end.col;
for (int i = (int) (start.row + Math.signum(drow)); i != end.row ; i += Math.signum(drow)) {
if (getCurrentState().cell_occupied[i][start.col] > 0 &&
getCurrentState().cell_occupied[i][start.col] != fingerprint) {
Log.d(getClass().getName(), "Crossing an occupied cell.");
return false;
}
}
if (start.row > end.row ) {
start.connecting_north = GetOrCreateConnection(end, start.connecting_north);
end.connecting_south = GetOrCreateConnection(start, end.connecting_south);
start_connection = start.connecting_north;
end_connection = end.connecting_south;
} else {
start.connecting_south= GetOrCreateConnection(end, start.connecting_south);
end.connecting_north = GetOrCreateConnection(start, end.connecting_north);
start_connection = start.connecting_south;
end_connection = end.connecting_north;
}
}
start_connection.destination = end;
end_connection.destination = start;
start_connection.second += count;
end_connection.second += count;
getCurrentState().AddToBridgeCache(start, end);
Log.d(getClass().getName(),
String.format("New bridge added. Sums:%d # (%d,%d) and %d # (%d,%d)",
count_start, start.row,start.col,
count_end, end.row,end.col));
return true;
}
private Connection GetOrCreateConnection(
BoardElement end,
Connection connection) {
if (connection!= null) { return connection; }
return new Connection();
}
#TargetApi(Build.VERSION_CODES.N)
private void InitializeEasy() {
Random rand = new Random();
String[][] debug_board_state = new String[7][7];
setCurrentState(new State(WIDTH_EASY));
for (int row = 0; row < debug_board_state.length; row++) {
for (int column = 0; column < debug_board_state[row].length; column++) {
debug_board_state[row][column] = String.valueOf(rand.nextInt(5));
}
}
for (int row = 0; row < debug_board_state.length; row++) {
for (int column = 0; column < debug_board_state[row].length; column++) {
System.out.print(debug_board_state[row][column] + " ");
}
System.out.println();
}
for (int row = 0; row < WIDTH_EASY; ++row) {
for (int column = 0; column < WIDTH_EASY; ++column) {
getCurrentState().board_elements[row][column] = new BoardElement();
getCurrentState().board_elements[row][column].max_connecting_bridges = Integer.parseInt(debug_board_state[row][column]);
getCurrentState().board_elements[row][column].row = row;
getCurrentState().board_elements[row][column].col = column;
if (getCurrentState().board_elements[row][column].max_connecting_bridges > 0) {
getCurrentState().board_elements[row][column].is_island = true;
}
}
}
}
private void setCurrentState(State new_state) {
this.current_state = new_state;
}
public State getCurrentState() {
return current_state;
}
}
What algorithm could I use to make sure the Map can be Solved (Islands Connected with Bridges) before spawning the nodes.
This is what the map looks like (don't mind the design)
One thing to consider would be to start with a blank board. Place an island. Then place another island that can be connected to the first one (i.e. on one of the four cardinal directions). Connect the two with a bridge, and increment each island's count.
Now, pick one of the two islands and place another island that it can connect. Add the bridge and increment.
Continue in this way until you've placed the number of islands that you want to place.
The beauty here is that you start with an empty board, and during construction the board is always valid.
You'll have to ensure that you're not crossing bridges when you place new islands, but that's pretty easy to do, since you know where the existing bridges are.

Java help! implementing a 2d array of a certain object, the object has multiple private data types and objects

I'm trying to make a 2d array of an object in java. This object in java has several private variables and methods in it, but won't work. Can someone tell me why and is there a way I can fix this?
This is the exeception I keep getting for each line of code where I try to initialize and iterate through my 2d object.
"Exception in thread "main" java.lang.NullPointerException
at wumpusworld.WumpusWorldGame.main(WumpusWorldGame.java:50)
Java Result: 1"
Here is my main class:
public class WumpusWorldGame {
class Agent {
private boolean safe;
private boolean stench;
private boolean breeze;
public Agent() {
safe = false;
stench = false;
breeze = false;
}
}
/**
* #param args
* the command line arguments
* #throws java.lang.Exception
*/
public static void main(String [] args) {
// WumpusFrame blah =new WumpusFrame();
// blah.setVisible(true);
Scanner input = new Scanner(System.in);
int agentpts = 0;
System.out.println("Welcome to Wumpus World!\n ******************************************** \n");
//ArrayList<ArrayList<WumpusWorld>> woah = new ArrayList<ArrayList<WumpusWorld>>();
for (int i = 0 ; i < 5 ; i++) {
WumpusWorldObject [] [] woah = new WumpusWorldObject [5] [5];
System.out.println( "*********************************\n Please enter the exact coordinates of the wumpus (r and c).");
int wumpusR = input.nextInt();
int wumpusC = input.nextInt();
woah[wumpusR][wumpusC].setPoints(-3000);
woah[wumpusR][wumpusC].setWumpus();
if ((wumpusR <= 5 || wumpusC <= 5) && (wumpusR >= 0 || wumpusC >= 0)) {
woah[wumpusR][wumpusC].setStench();
}
if (wumpusC != 0) {
woah[wumpusR][wumpusC - 1].getStench();
}
if (wumpusR != 0) {
woah[wumpusR - 1][wumpusC].setStench();
}
if (wumpusC != 4) {
woah[wumpusR][wumpusC + 1].setStench();
}
if (wumpusR != 4) {
woah[wumpusR + 1][wumpusC].setStench();
}
System.out.println( "**************************************\n Please enter the exact coordinates of the Gold(r and c).");
int goldR = input.nextInt();
int goldC = input.nextInt();
woah[goldR][goldC].setGold();
System.out.println("***************************************\n How many pits would you like in your wumpus world?");
int numPits = input.nextInt();
for (int k = 0 ; k < numPits ; k++) {
System.out.println("Enter the row location of the pit");
int r = input.nextInt();
System.out.println("Enter the column location of the pit");
int c = input.nextInt();
woah[r][c].setPit();
if ((r <= 4 || c <= 4) && (r >= 0 || c >= 0)) {
woah[r][c].setBreeze();
}
if (c != 0) {
woah[r][c - 1].setBreeze();
}
if (r != 0) {
woah[r - 1][c].setBreeze();
}
if (c != 4) {
woah[r][c + 1].setBreeze();
}
if (r != 4) {
woah[r + 1][c].setBreeze();
}
}
for (int x = 0 ; x < 4 ; x++) {
int j = 0;
while (j < 4) {
agentpts = agentpts + woah[x][j].getPoints();
Agent [] [] k = new Agent [4] [4];
if (woah[x][j].getWumpus() == true) {
agentpts = agentpts + woah[x][j].getPoints();
System.out.println("You just got ate by the wumpus!!! THE HORROR!! Your score is " + agentpts);
}
if (woah[x][j].getStench() == true) {
k[x][j].stench = true;
System.out.println("You smell something funny... smells like old person.");
}
if (woah[x][j].getBreeze() == true) {
k[x][j].breeze = true;
System.out.println("You hear a breeze. yeah");
}
if (woah[x][j].getPit() == true) {
agentpts = agentpts + woah[x][j].getPoints();
System.out.println("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH! you dumb bith, your dead now.");
}
// if breeze or stench, if breeze and stench, if nothing, etc then move.
k[x][j].safe = true;
// if(k[i][j].isSafe()!=true){
// } else { }
}
}
}
}
}
Here is my class object that I'm trying to implement:
package wumpusworld;
/**
*
* #author Jacob
*/
public class WumpusWorldObject {
private boolean stench;
private boolean breeze;
private boolean pit;
private boolean wumpus;
private boolean gold;
private int points;
private boolean safe;
public WumpusWorldObject(){
}
public boolean getPit() {
return pit;
}
public void setPit() {
this.pit = true;
}
public boolean getWumpus() {
return wumpus;
}
public void setWumpus() {
this.wumpus = true;
}
public int getPoints() {
return points;
}
public void setPoints(int points) {
this.points = points;
}
public boolean getStench() {
return stench;
}
public void setStench() {
this.stench = true;
}
public boolean getBreeze() {
return breeze;
}
public void setBreeze() {
this.breeze = true;
}
public boolean getSafe() {
return safe;
}
public void setSafe() {
this.safe = true;
}
public void setGold(){
this.gold=true;
}
}
Creating array doesn't mean it will be automatically filled with new instances of your class. There are many reasons for that, like
which constructor should be used
what data should be passed to this constructor.
This kind of decisions shouldn't be made by compiler, but by programmer, so you need to invoke constructor explicitly.
After creating array iterate over it and fill it with new instances of your class.
for (int i=0; i<yourArray.length; i++)
for (int j=0; j<yourArray[i].length; j++)
yourArray[i][j] = new ...//here you should use constructor
AClass[][] obj = new AClass[50][50];
is not enough, you have to create instances of them like
obj[i][j] = new AClass(...);
In your code the line
woah[wumpusR][wumpusC].setPoints(-3000);
must be after
woah[wumpusR][wumpusC] = new WumpusWorldObject();
.

Random number - increase/decrease by 1

I'm working on a method, that takes steps between 3 and -3. My program will not print out the steps in a numerical order, and I can't quite figure out how to do it, and I can't find anything elsewhere.
public static final int SENTINEL = Math.abs(3);
public static void randomWalk(Random rand) {
int walk = 0;
while (walk != SENTINEL) {
walk = (rand.nextInt((3 - (-3)) + 1) - 3);
System.out.println("Position = " + walk);
}
}
If that is what you are looking for :
int walk = 0;
int randomStep = 0;
Random rand = new Random();
while (Math.abs(walk) != 3) {
randomStep = rand.nextInt(2) > 0 ? 1 : -1; // -1 or 1 with 50% probability
walk += randomStep;
System.out.print(walk + " ");
}
//sample output: -1 -2 -1 0 1 2 1 2 3
public static void randomWalk(Random rand) {
int walk = 0;
while (walk != SENTINEL) {
walk += rand.nextInt(3) - 1;
if(walk>3) walk = 3;
if(walk<-3) walk = -3;
System.out.println("Position = " + walk);
}
}
I guess you want this.
while (walk != SENTINEL) {
int walk = 0;
walk = (rand.nextInt((3 - (-3)) + 1) - 3);
System.out.println("Walk is = " + walk);
int temp = walk;
if (walk >= -3) {
System.out.println("Wlak plus = " + (temp + 1));
System.out.println("Wlak minus =" + (temp - 1));
}
}
Could this be what you are looking for?
package com.stackoverflow.random;
import java.util.Random;
public class Walking {
private final int bounds;
public Walking(int bounds) {
this.bounds = bounds;
}
private boolean isWithinBounds(int walk) {
return Math.abs(walk) < bounds;
}
public String randomWalk() {
int walk = 0;
StringBuilder sb = new StringBuilder();
while(isWithinBounds(walk)) {
sb.append(walk);
walk = getNextStep(walk);
}
return sb.toString();
}
private Random random = null;
private int getNextStep(int walk) {
if (random == null)
random = new Random();
boolean increase = random.nextBoolean();
return increase?++walk:--walk;
}
public static void main(String[] args) {
Walking app = new Walking(3);
System.out.println("walking: " + app.randomWalk());
}
}

Time delay and JInput

OK, I don't know how to word this question, but maybe my code will spell out the problem:
public class ControllerTest
{
public static void main(String [] args)
{
GamePadController rockbandDrum = new GamePadController();
DrumMachine drum = new DrumMachine();
while(true)
{
try{
rockbandDrum.poll();
if(rockbandDrum.isButtonPressed(1)) //BLUE PAD HhiHat)
{
drum.playSound("hiHat.wav");
Thread.sleep(50);
}
if(rockbandDrum.isButtonPressed(2)) //GREEN PAD (Crash)
{
//Todo: Change to Crash
drum.playSound("hiHat.wav");
Thread.sleep(50);
}
//Etc....
}
}
}
public class DrumMachine
{
InputStream soundPlayer = null;
AudioStream audio = null;
static boolean running = true;
public void playSound(String soundFile)
{
//Tak a sound file as a paramater and then
//play that sound file
try{
soundPlayer = new FileInputStream(soundFile);
audio = new AudioStream(soundPlayer);
}
catch(FileNotFoundException e){
e.printStackTrace();
}
catch(IOException e){
e.printStackTrace();
}
AudioPlayer.player.start(audio);
}
//Etc... Methods for multiple audio clip playing
}
Now the problem is, if I lower the delay in the
Thread.sleep(50)
then the sound plays multiple times a second, but if I keep at this level or any higher, I could miss sounds being played...
It's an odd problem, where if the delay is too low, the sound loops. But if it's too high it misses playing sounds. Is this just a problem where I would need to tweak the settings, or is there any other way to poll the controller without looping sound?
Edit: If I need to post the code for polling the controller I will...
import java.io.*;
import net.java.games.input.*;
import net.java.games.input.Component.POV;
public class GamePadController
{
public static final int NUM_BUTTONS = 13;
// public stick and hat compass positions
public static final int NUM_COMPASS_DIRS = 9;
public static final int NW = 0;
public static final int NORTH = 1;
public static final int NE = 2;
public static final int WEST = 3;
public static final int NONE = 4; // default value
public static final int EAST = 5;
public static final int SW = 6;
public static final int SOUTH = 7;
public static final int SE = 8;
private Controller controller;
private Component[] comps; // holds the components
// comps[] indices for specific components
private int xAxisIdx, yAxisIdx, zAxisIdx, rzAxisIdx;
// indices for the analog sticks axes
private int povIdx; // index for the POV hat
private int buttonsIdx[]; // indices for the buttons
private Rumbler[] rumblers;
private int rumblerIdx; // index for the rumbler being used
private boolean rumblerOn = false; // whether rumbler is on or off
public GamePadController()
{
// get the controllers
ControllerEnvironment ce =
ControllerEnvironment.getDefaultEnvironment();
Controller[] cs = ce.getControllers();
if (cs.length == 0) {
System.out.println("No controllers found");
System.exit(0);
}
else
System.out.println("Num. controllers: " + cs.length);
// get the game pad controller
controller = findGamePad(cs);
System.out.println("Game controller: " +
controller.getName() + ", " +
controller.getType());
// collect indices for the required game pad components
findCompIndices(controller);
findRumblers(controller);
} // end of GamePadController()
private Controller findGamePad(Controller[] cs)
/* Search the array of controllers until a suitable game pad
controller is found (eith of type GAMEPAD or STICK).
*/
{
Controller.Type type;
int i = 0;
while(i < cs.length) {
type = cs[i].getType();
if ((type == Controller.Type.GAMEPAD) ||
(type == Controller.Type.STICK))
break;
i++;
}
if (i == cs.length) {
System.out.println("No game pad found");
System.exit(0);
}
else
System.out.println("Game pad index: " + i);
return cs[i];
} // end of findGamePad()
private void findCompIndices(Controller controller)
/* Store the indices for the analog sticks axes
(x,y) and (z,rz), POV hat, and
button components of the controller.
*/
{
comps = controller.getComponents();
if (comps.length == 0) {
System.out.println("No Components found");
System.exit(0);
}
else
System.out.println("Num. Components: " + comps.length);
// get the indices for the axes of the analog sticks: (x,y) and (z,rz)
xAxisIdx = findCompIndex(comps, Component.Identifier.Axis.X, "x-axis");
yAxisIdx = findCompIndex(comps, Component.Identifier.Axis.Y, "y-axis");
zAxisIdx = findCompIndex(comps, Component.Identifier.Axis.Z, "z-axis");
rzAxisIdx = findCompIndex(comps, Component.Identifier.Axis.RZ, "rz-axis");
// get POV hat index
povIdx = findCompIndex(comps, Component.Identifier.Axis.POV, "POV hat");
findButtons(comps);
} // end of findCompIndices()
private int findCompIndex(Component[] comps,
Component.Identifier id, String nm)
/* Search through comps[] for id, returning the corresponding
array index, or -1 */
{
Component c;
for(int i=0; i < comps.length; i++) {
c = comps[i];
if ((c.getIdentifier() == id) && !c.isRelative()) {
System.out.println("Found " + c.getName() + "; index: " + i);
return i;
}
}
System.out.println("No " + nm + " component found");
return -1;
} // end of findCompIndex()
private void findButtons(Component[] comps)
/* Search through comps[] for NUM_BUTTONS buttons, storing
their indices in buttonsIdx[]. Ignore excessive buttons.
If there aren't enough buttons, then fill the empty spots in
buttonsIdx[] with -1's. */
{
buttonsIdx = new int[NUM_BUTTONS];
int numButtons = 0;
Component c;
for(int i=0; i < comps.length; i++) {
c = comps[i];
if (isButton(c)) { // deal with a button
if (numButtons == NUM_BUTTONS) // already enough buttons
System.out.println("Found an extra button; index: " + i + ". Ignoring it");
else {
buttonsIdx[numButtons] = i; // store button index
System.out.println("Found " + c.getName() + "; index: " + i);
numButtons++;
}
}
}
// fill empty spots in buttonsIdx[] with -1's
if (numButtons < NUM_BUTTONS) {
System.out.println("Too few buttons (" + numButtons +
"); expecting " + NUM_BUTTONS);
while (numButtons < NUM_BUTTONS) {
buttonsIdx[numButtons] = -1;
numButtons++;
}
}
} // end of findButtons()
private boolean isButton(Component c)
/* Return true if the component is a digital/absolute button, and
its identifier name ends with "Button" (i.e. the
identifier class is Component.Identifier.Button).
*/
{
if (!c.isAnalog() && !c.isRelative()) { // digital and absolute
String className = c.getIdentifier().getClass().getName();
// System.out.println(c.getName() + " identifier: " + className);
if (className.endsWith("Button"))
return true;
}
return false;
} // end of isButton()
private void findRumblers(Controller controller)
/* Find the rumblers. Use the last rumbler for making vibrations,
an arbitrary decision. */
{
// get the game pad's rumblers
rumblers = controller.getRumblers();
if (rumblers.length == 0) {
System.out.println("No Rumblers found");
rumblerIdx = -1;
}
else {
System.out.println("Rumblers found: " + rumblers.length);
rumblerIdx = rumblers.length-1; // use last rumbler
}
} // end of findRumblers()
// ----------------- polling and getting data ------------------
public void poll()
// update the component values in the controller
{
controller.poll();
}
public int getXYStickDir()
// return the (x,y) analog stick compass direction
{
if ((xAxisIdx == -1) || (yAxisIdx == -1)) {
System.out.println("(x,y) axis data unavailable");
return NONE;
}
else
return getCompassDir(xAxisIdx, yAxisIdx);
} // end of getXYStickDir()
public int getZRZStickDir()
// return the (z,rz) analog stick compass direction
{
if ((zAxisIdx == -1) || (rzAxisIdx == -1)) {
System.out.println("(z,rz) axis data unavailable");
return NONE;
}
else
return getCompassDir(zAxisIdx, rzAxisIdx);
} // end of getXYStickDir()
private int getCompassDir(int xA, int yA)
// Return the axes as a single compass value
{
float xCoord = comps[ xA ].getPollData();
float yCoord = comps[ yA ].getPollData();
// System.out.println("(x,y): (" + xCoord + "," + yCoord + ")");
int xc = Math.round(xCoord);
int yc = Math.round(yCoord);
// System.out.println("Rounded (x,y): (" + xc + "," + yc + ")");
if ((yc == -1) && (xc == -1)) // (y,x)
return NW;
else if ((yc == -1) && (xc == 0))
return NORTH;
else if ((yc == -1) && (xc == 1))
return NE;
else if ((yc == 0) && (xc == -1))
return WEST;
else if ((yc == 0) && (xc == 0))
return NONE;
else if ((yc == 0) && (xc == 1))
return EAST;
else if ((yc == 1) && (xc == -1))
return SW;
else if ((yc == 1) && (xc == 0))
return SOUTH;
else if ((yc == 1) && (xc == 1))
return SE;
else {
System.out.println("Unknown (x,y): (" + xc + "," + yc + ")");
return NONE;
}
} // end of getCompassDir()
public int getHatDir()
// Return the POV hat's direction as a compass direction
{
if (povIdx == -1) {
System.out.println("POV hat data unavailable");
return NONE;
}
else {
float povDir = comps[povIdx].getPollData();
if (povDir == POV.CENTER) // 0.0f
return NONE;
else if (povDir == POV.DOWN) // 0.75f
return SOUTH;
else if (povDir == POV.DOWN_LEFT) // 0.875f
return SW;
else if (povDir == POV.DOWN_RIGHT) // 0.625f
return SE;
else if (povDir == POV.LEFT) // 1.0f
return WEST;
else if (povDir == POV.RIGHT) // 0.5f
return EAST;
else if (povDir == POV.UP) // 0.25f
return NORTH;
else if (povDir == POV.UP_LEFT) // 0.125f
return NW;
else if (povDir == POV.UP_RIGHT) // 0.375f
return NE;
else { // assume center
System.out.println("POV hat value out of range: " + povDir);
return NONE;
}
}
} // end of getHatDir()
public boolean[] getButtons()
/* Return all the buttons in a single array. Each button value is
a boolean. */
{
boolean[] buttons = new boolean[NUM_BUTTONS];
float value;
for(int i=0; i < NUM_BUTTONS; i++) {
value = comps[ buttonsIdx[i] ].getPollData();
buttons[i] = ((value == 0.0f) ? false : true);
}
return buttons;
} // end of getButtons()
public boolean isButtonPressed(int pos)
/* Return the button value (a boolean) for button number 'pos'.
pos is in the range 1-NUM_BUTTONS to match the game pad
button labels.
*/
{
if ((pos < 1) || (pos > NUM_BUTTONS)) {
System.out.println("Button position out of range (1-" +
NUM_BUTTONS + "): " + pos);
return false;
}
if (buttonsIdx[pos-1] == -1) // no button found at that pos
return false;
float value = comps[ buttonsIdx[pos-1] ].getPollData();
// array range is 0-NUM_BUTTONS-1
return ((value == 0.0f) ? false : true);
} // end of isButtonPressed()
// ------------------- Trigger a rumbler -------------------
public void setRumbler(boolean switchOn)
// turn the rumbler on or off
{
if (rumblerIdx != -1) {
if (switchOn)
rumblers[rumblerIdx].rumble(0.8f); // almost full on for last rumbler
else // switch off
rumblers[rumblerIdx].rumble(0.0f);
rumblerOn = switchOn; // record rumbler's new status
}
} // end of setRumbler()
public boolean isRumblerOn()
{ return rumblerOn; }
} // end of GamePadController class
I think you are using the wrong design pattern here. You should use the observer pattern for this type of thing.
A polling loop not very efficient, and as you've noticed doesn't really yield the desired results.
I'm not sure what you are using inside your objects to detect if a key is pressed, but if it's a GUI architecture such as Swing or AWT it will be based on the observer pattern via the use of EventListeners, etc.
Here is a (slightly simplified) Observer-pattern
applied to your situation.
The advantage of this design is that when a button
is pressed and hold, method 'buttonChanged' will
still only be called once, instead of start
'repeating' every 50 ms.
public static final int BUTTON_01 = 0x00000001;
public static final int BUTTON_02 = 0x00000002;
public static final int BUTTON_03 = 0x00000004;
public static final int BUTTON_04 = 0x00000008; // hex 8 == dec 8
public static final int BUTTON_05 = 0x00000010; // hex 10 == dec 16
public static final int BUTTON_06 = 0x00000020; // hex 20 == dec 32
public static final int BUTTON_07 = 0x00000040; // hex 40 == dec 64
public static final int BUTTON_08 = 0x00000080; // etc.
public static final int BUTTON_09 = 0x00000100;
public static final int BUTTON_10 = 0x00000200;
public static final int BUTTON_11 = 0x00000400;
public static final int BUTTON_12 = 0x00000800;
private int previousButtons = 0;
void poll()
{
rockbandDrum.poll();
handleButtons();
}
private void handleButtons()
{
boolean[] buttons = getButtons();
int pressedButtons = getPressedButtons(buttons);
if (pressedButtons != previousButtons)
{
buttonChanged(pressedButtons); // Notify 'listener'.
previousButtons = pressedButtons;
}
}
public boolean[] getButtons()
{
// Return all the buttons in a single array. Each button-value is a boolean.
boolean[] buttons = new boolean[MAX_NUMBER_OF_BUTTONS];
float value;
for (int i = 0; i < MAX_NUMBER_OF_BUTTONS-1; i++)
{
int index = buttonsIndex[i];
if (index < 0) { continue; }
value = comps[index].getPollData();
buttons[i] = ((value == 0.0f) ? false : true);
}
return buttons;
}
private int getPressedButtons(boolean[] array)
{
// Mold all pressed buttons into a single number by OR-ing their values.
int pressedButtons = 0;
int i = 1;
for (boolean isBbuttonPressed : array)
{
if (isBbuttonPressed) { pressedButtons |= getOrValue(i); }
i++;
}
return pressedButtons;
}
private int getOrValue(int btnNumber) // Get a value to 'OR' with.
{
int btnValue = 0;
switch (btnNumber)
{
case 1 : btnValue = BUTTON_01; break;
case 2 : btnValue = BUTTON_02; break;
case 3 : btnValue = BUTTON_03; break;
case 4 : btnValue = BUTTON_04; break;
case 5 : btnValue = BUTTON_05; break;
case 6 : btnValue = BUTTON_06; break;
case 7 : btnValue = BUTTON_07; break;
case 8 : btnValue = BUTTON_08; break;
case 9 : btnValue = BUTTON_09; break;
case 10 : btnValue = BUTTON_10; break;
case 11 : btnValue = BUTTON_11; break;
case 12 : btnValue = BUTTON_12; break;
default : assert false : "Invalid button-number";
}
return btnValue;
}
public static boolean checkButton(int pressedButtons, int buttonToCheckFor)
{
return (pressedButtons & buttonToCheckFor) == buttonToCheckFor;
}
public void buttonChanged(int buttons)
{
if (checkButton(buttons, BUTTON_01)
{
drum.playSound("hiHat.wav");
}
if (checkButton(buttons, BUTTON_02)
{
drum.playSound("crash.wav");
}
}
Please post more information about the GamePadController class that you are using.
More than likely, that same library will offer an "event" API, where a "callback" that you register with a game pad object will be called as soon as the user presses a button. With this kind of setup, the "polling" loop is in the framework, not your application, and it can be much more efficient, because it uses signals from the hardware rather than a busy-wait polling loop.
Okay, I looked at the JInput API, and it is not really event-driven; you have to poll it as you are doing. Does the sound stop looping when you release the button? If so, is your goal to have the sound play just once, and not again until the button is release and pressed again? In that case, you'll need to track the previous button state each time through the loop.
Human response time is about 250 ms (for an old guy like me, anyway). If you are polling every 50 ms, I'd expect the controller to report the button depressed for several iterations of the loop. Can you try something like this:
boolean played = false;
while (true) {
String sound = null;
if (controller.isButtonPressed(1))
sound = "hiHat.wav";
if (controller.isButtonPressed(2))
sound = "crash.wav";
if (sound != null) {
if (!played) {
drum.playSound(sound);
played = true;
}
} else {
played = false;
}
Thread.sleep(50);
}

Categories