read temperature from DHT11, using pi4j
I the tried the code in the following link with prerequisites :
Java 1.8.0_65
pi4j 1.1
Raspberry Pi 3 Model B
DHT22 Temperature sensor.
Here when I am trying to execute the following both codes available in the link I am facing the issue regarding the LibPins in the code
public DHT11(int pin) {
final GpioController gpio = GpioFactory.getInstance();
dht11Pin = gpio.provisionDigitalMultipurposePin(LibPins.getPin(pin),
PinMode.DIGITAL_INPUT, PinPullResistance.PULL_UP);
}
and in the other code snippet I am getting the output as "Data not good,Skip"
But for the second code in the link I was getting the output for few set of readings and after its outputting as "Data not good,Skip".
I am working on reading the temperature connected to pi gpio pins using java and pi4j library.
Thanks in Advance.
I have had luck with this (modified from another thread).
You'll also need to install wiring pi sudo apt-get install wiringpi
It should be noted that this I put this class into it's own thread and loop it by calling run(). It then stuffs the variables into local state and I can reference them in my main class.
import com.pi4j.wiringpi.Gpio;
import com.pi4j.wiringpi.GpioUtil;
public class DHT22 implements Runnable {
private static final int maxTimings = 85;
private final int[] dht22_dat = {0, 0, 0, 0, 0};
private float temperature = 9999;
private float humidity = 9999;
boolean shuttingDown = false;
public DHT22() {
// setup wiringPi
if (Gpio.wiringPiSetup() == -1) {
System.out.println(" ==>> GPIO SETUP FAILED");
return;
}
GpioUtil.export(3, GpioUtil.DIRECTION_OUT);
}
private int pollDHT22() {
int lastState = Gpio.HIGH;
int j = 0;
dht22_dat[0] = dht22_dat[1] = dht22_dat[2] = dht22_dat[3] = dht22_dat[4] = 0;
int pinNumber = 16;
Gpio.pinMode(pinNumber, Gpio.OUTPUT);
Gpio.digitalWrite(pinNumber, Gpio.LOW);
Gpio.delay(18);
Gpio.digitalWrite(pinNumber, Gpio.HIGH);
Gpio.pinMode(pinNumber, Gpio.INPUT);
for (int i = 0; i < maxTimings; i++) {
int counter = 0;
while (Gpio.digitalRead(pinNumber) == lastState) {
counter++;
Gpio.delayMicroseconds(1);
if (counter == 255) {
break;
}
}
lastState = Gpio.digitalRead(pinNumber);
if (counter == 255) {
break;
}
/* ignore first 3 transitions */
if (i >= 4 && i % 2 == 0) {
/* shove each bit into the storage bytes */
dht22_dat[j / 8] <<= 1;
if (counter > 16) {
dht22_dat[j / 8] |= 1;
}
j++;
}
}
return j;
}
private void refreshData() {
int pollDataCheck = pollDHT22();
if (pollDataCheck >= 40 && checkParity()) {
final float newHumidity = (float) ((dht22_dat[0] << 8) + dht22_dat[1]) / 10;
final float newTemperature = (float) (((dht22_dat[2] & 0x7F) << 8) + dht22_dat[3]) / 10;
if (humidity == 9999 || ((newHumidity < humidity + 40) && (newHumidity > humidity - 40))) {
humidity = newHumidity;
if (humidity > 100) {
humidity = dht22_dat[0]; // for DHT22
}
}
if (temperature == 9999 || ((newTemperature < temperature + 40) && (newTemperature > temperature - 40))) {
temperature = (float) (((dht22_dat[2] & 0x7F) << 8) + dht22_dat[3]) / 10;
if (temperature > 125) {
temperature = dht22_dat[2]; // for DHT22
}
if ((dht22_dat[2] & 0x80) != 0) {
temperature = -temperature;
}
}
}
}
float getHumidity() {
if (humidity == 9999) {
return 0;
}
return humidity;
}
#SuppressWarnings("unused")
float getTemperature() {
if (temperature == 9999) {
return 0;
}
return temperature;
}
float getTemperatureInF() {
if (temperature == 9999) {
return 32;
}
return temperature * 1.8f + 32;
}
private boolean checkParity() {
return dht22_dat[4] == (dht22_dat[0] + dht22_dat[1] + dht22_dat[2] + dht22_dat[3] & 0xFF);
}
#Override
public void run() {
while (!shuttingDown) {
refreshData();
}
}
}
This version uses the java nanosecond timing to read the binary data. It uses Pi4J which uses WiringPi. I hope it is helpful. (https://github.com/dougculnane/java-pi-thing)
import java.io.Closeable;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import com.pi4j.io.gpio.Pin;
import com.pi4j.io.gpio.RaspiPin;
import com.pi4j.wiringpi.Gpio;
/**
* Implements the DHT22 / AM2302 reading in Java using Pi4J.
*
* See (AM2302.pdf) specksheet for details of timings.
*
* #author Doug Culnane
*/
public class DHT22 {
/**
* Time in nanoseconds to separate ZERO and ONE signals.
*/
private static final int LONGEST_ZERO = 50000;
/**
* PI4J Pin number.
*/
private int pinNumber;
/**
* 40 bit Data from sensor
*/
private byte[] data = null;
/**
* Value of last successful humidity reading.
*/
private Double humidity = null;
/**
* Value of last successful temperature reading.
*/
private Double temperature = null;
/**
* Last read attempt
*/
private Long lastRead = null;
/**
* Constructor with pin used for signal. See PI4J and WiringPI for
* pin numbering systems.....
*
* #param pin
*/
public DHT22(Pin pin) {
pinNumber = pin.getAddress();
}
/**
* Communicate with sensor to get new reading data.
*
* #throws Exception if failed to successfully read data.
*/
private void getData() throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor();
ReadSensorFuture readSensor = new ReadSensorFuture();
Future<byte[]> future = executor.submit(readSensor);
// Reset data
data = new byte[5];
try {
data = future.get(3, TimeUnit.SECONDS);
readSensor.close();
} catch (TimeoutException e) {
readSensor.close();
future.cancel(true);
executor.shutdown();
throw e;
}
readSensor.close();
executor.shutdown();
}
/**
* Make a new sensor reading.
*
* #throws Exception
*/
public boolean read() throws Exception {
checkLastReadDelay();
lastRead = System.currentTimeMillis();
getData();
checkParity();
humidity = getReadingValueFromBytes(data[0], data[1]);
temperature = getReadingValueFromBytes(data[2], data[3]);
lastRead = System.currentTimeMillis();
return true;
}
private void checkLastReadDelay() throws Exception {
if (Objects.nonNull(lastRead)) {
if (lastRead > System.currentTimeMillis() - 2000) {
throw new Exception("Last read was under 2 seconds ago. Please wait longer between reads!");
}
}
}
private double getReadingValueFromBytes(final byte hi, final byte low) {
ByteBuffer bb = ByteBuffer.allocate(2);
bb.order(ByteOrder.BIG_ENDIAN);
bb.put(hi);
bb.put(low);
short shortVal = bb.getShort(0);
return new Double(shortVal) / 10;
}
private void checkParity() throws ParityChheckException {
if (!(data[4] == (data[0] + data[1] + data[2] + data[3] & 0xFF))) {
throw new ParityChheckException();
}
}
public Double getHumidity() {
return humidity;
}
public Double getTemperature() {
return temperature;
}
/**
* Run from command line to loop and make readings.
* #throws IOException
*/
public static void main(String[] args) throws IOException {
System.out.println("Starting DHT22");
if (Gpio.wiringPiSetup() == -1) {
System.out.println("GPIO wiringPiSetup Failed!");
return;
}
DHT22 dht22 = new DHT22(RaspiPin.GPIO_05);
int LOOP_SIZE = 10;
int countSuccess = 0;
for (int i=0; i < LOOP_SIZE; i++) {
try {
Thread.sleep(3000);
System.out.println();
dht22.read();
System.out.println("Humidity=" + dht22.getHumidity() +
"%, Temperature=" + dht22.getTemperature() + "*C");
countSuccess++;
} catch (TimeoutException e) {
System.out.println("ERROR: " + e);
} catch (Exception e) {
System.out.println("ERROR: " + e);
}
}
System.out.println("Read success rate: "+ countSuccess + " / " + LOOP_SIZE);
System.out.println("Ending DHT22");
}
/**
* Callable Future for reading sensor. Allows timeout if it gets stuck.
*/
private class ReadSensorFuture implements Callable<byte[]>, Closeable {
private boolean keepRunning = true;
public ReadSensorFuture() {
Gpio.pinMode(pinNumber, Gpio.OUTPUT);
Gpio.digitalWrite(pinNumber, Gpio.HIGH);
}
#Override
public byte[] call() throws Exception {
// do expensive (slow) stuff before we start.
byte[] data = new byte[5];
long startTime = System.nanoTime();
sendStartSignal();
waitForResponseSignal();
for (int i = 0; i < 40; i++) {
while (keepRunning && Gpio.digitalRead(pinNumber) == Gpio.LOW) {
}
startTime = System.nanoTime();
while (keepRunning && Gpio.digitalRead(pinNumber) == Gpio.HIGH) {
}
long timeHight = System.nanoTime() - startTime;
data[i / 8] <<= 1;
if ( timeHight > LONGEST_ZERO) {
data[i / 8] |= 1;
}
}
return data;
}
private void sendStartSignal() {
// Send start signal.
Gpio.pinMode(pinNumber, Gpio.OUTPUT);
Gpio.digitalWrite(pinNumber, Gpio.LOW);
Gpio.delay(1);
Gpio.digitalWrite(pinNumber, Gpio.HIGH);
}
/**
* AM2302 will pull low 80us as response signal, then
* AM2302 pulls up 80us for preparation to send data.
*/
private void waitForResponseSignal() {
Gpio.pinMode(pinNumber, Gpio.INPUT);
while (keepRunning && Gpio.digitalRead(pinNumber) == Gpio.HIGH) {
}
while (keepRunning && Gpio.digitalRead(pinNumber) == Gpio.LOW) {
}
while (keepRunning && Gpio.digitalRead(pinNumber) == Gpio.HIGH) {
}
}
#Override
public void close() throws IOException {
keepRunning = false;
// Set pin high for end of transmission.
Gpio.pinMode(pinNumber, Gpio.OUTPUT);
Gpio.digitalWrite(pinNumber, Gpio.HIGH);
}
}
private class ParityChheckException extends Exception {
private static final long serialVersionUID = 1L;
}
}
Related
I'm doing a Java programming assignment which involves bubble sorting a .dat file BetelgeuseNames.dat with strings in it alphabetically. My AP Computer Science A teacher told me my code is correct, but it still gives the wrong output.
There are three classes called BubbleSort, BubbleSortTimer, and StopWatch. The program runs from BubbleSortTimer.
BubbleSort:
import java.util.ArrayList;
import javax.swing.JOptionPane;
import java.io.FileWriter;
import java.io.IOException;
public class BubbleSort {
// Private instance variables:
private ArrayList<String> list;
private int number;
public BubbleSort(ArrayList<String> a_list) {
list = a_list;
}
public void swap(int first, int second) {
String temp1 = list.get(first);
String temp2 = list.get(second);
list.set(first, temp2);
list.set(second, temp1);
}
public int getNumber() {
String numStr;
numStr = JOptionPane.showInputDialog("How many names do you want to sort?");
number = Integer.parseInt(numStr);
return number;
}
public void printSorted() {
try {
FileWriter writer = new FileWriter("sorted.dat");
for (int i = 0; i < number; i++) {
writer.write(list.get(i) + "\n");
}
writer.close();
} catch (IOException exception) {
System.out.println("Error processing file: " + exception);
}
}
public void bubbleSort() {
for (int i = 0; i < number; i++) {
for (int j = 0; j < number - i - 1; j++) {
if (list.get(i).compareTo(list.get(i+1)) > 0) {
swap(i, i + 1);
}
}
}
} // End method
}
BubbleSortTimer:
import java.util.ArrayList;
import java.io.BufferedReader;
import java.io.FileReader;
import javax.swing.JOptionPane;
import java.io.IOException;
public class BubbleSortTimer {
private ArrayList<String> list = new ArrayList<String>();
public void readNames() {
try {
FileReader reader = new FileReader("BetelgeuseNames.dat");
BufferedReader in = new BufferedReader(reader);
boolean done = false;
String name;
while (done == false) {
name = in.readLine();
if (name == null) {
done = true;
} else {
list.add(name);
}
}
reader.close();
} catch (IOException exception) {
System.out.println("Error processing file: " + exception);
}
} // End method
public void runSort() {
readNames();
StopWatch timer = new StopWatch();
BubbleSort sorter = new BubbleSort(list);
int number = sorter.getNumber();
timer.start();
sorter.bubbleSort();
timer.stop();
sorter.printSorted();
String msg = "Number of names sorted: " + number + "\nMilliseconds required to sort: " + timer.getElapsedTime() + "\nOutput file is \"sorted.dat\"";
JOptionPane.showMessageDialog(null, msg);
}
public static void main(String[] args) {
BubbleSortTimer bubble = new BubbleSortTimer();
bubble.runSort();
}
}
StopWatch:
/**
* A stopwatch accumulates time when it is running. You can
* repeatedly start and stop the stopwatch. You can use a
* stopwatch to measure the running time of a program.
* from section 18.2 of Horstmann's CCJ
*/
public class StopWatch {
/**
* Constructs a stopwatch that is in the stopped state
* and has no time accumulated.
*/
public StopWatch() {
reset();
}
/**
* Starts the stopwatch. Times starts accumulating now.
*/
public void start() {
if (isRunning) return;
isRunning = true;
startTime = System.currentTimeMillis();
}
/**
* Stops the stopwatch. Time stops accumulating and is
* added to the elapsed time.
*/
public void stop() {
if (!isRunning) return;
isRunning = false;
long endTime = System.currentTimeMillis();
elapsedTime = elapsedTime + endTime - startTime;
}
/**
* Returns the total elapsed time.
#return the total elapsed time
*/
public long getElapsedTime() {
if (isRunning) {
long endTime = System.currentTimeMillis();
elapsedTime = elapsedTime + endTime - startTime;
startTime = endTime;
}
return elapsedTime;
}
/**
* Stops the watch and resets the elapsed time to 0.
*/
public void reset() {
elapsedTime = 0;
isRunning = false;
}
private long elapsedTime;
private long startTime;
private boolean isRunning;
}
Input:
Moewm
Bmlzvltcso
Aqxjor
Wwgjie
Qqqtpivd
Xgyhaerv
Wqpjwdvxjq
Ecsfnow
Zlptuqxctt
Jhtprwvopk
Expected Output:
Aqxjor
Bmlzvltcso
Ecsfnow
Jhtprwvopk
Moewm
Qqqtpivd
Wqpjwdvxjq
Wwgjie
Xgyhaerv
Zlptuqxctt
Actual Output:
Bmlzvltcso
Aqxjor
Moewm
Qqqtpivd
Wwgjie
Wqpjwdvxjq
Ecsfnow
Xgyhaerv
Jhtprwvopk
Zlptuqxctt
This is how Android did (binary) sorting (edited to fix this situation):
public void binarySort() {
int lo = 0; // sort start
for (int start=lo ; start < number; start++) {
String pivot = list.get(start);
// Set left (and right) to the index where list.get(start) (pivot) belongs
int left = 0;
int right = start;
assert left <= right;
/*
* Invariants:
* pivot >= all in [lo, left].
* pivot < all in [right, start].
*/
while (left < right) {
int mid = (left + right) >>> 1;
if (pivot.compareTo(list.get(mid)) < 0)
right = mid;
else
left = mid + 1;
}
assert left == right;
/*
* The invariants still hold: pivot >= all in [lo, left] and
* pivot < all in [left, start], so pivot belongs at left. Note
* that if there are elements equal to pivot, left points to the
* first slot after them -- that's why this sort is stable.
* Slide elements over to make room for pivot.
*/
int n = start - left; // The number of elements to move
// Switch is just reshifter in default case
switch (n) {
case 2: list.set(left + 2,list.get(left + 1));
case 1: list.set(left + 1,list.get(left));
break;
default:
if(n>0){
list.add(left,list.remove(left+n));
}
}
list.set(left,pivot);
}
}
This is how you can do (bubble) sorting:
public void bubbleSort() {
for (int i = 0; i < number; i++) {
for (int j = i + 1; j < number; j++) {
if (list.get(i).compareTo(list.get(j)) > 0) {
swap(i, j);
}
}
}
}
BUBBLE SORTING V/S BINARY SORTING:
OFF TOPIC: As you can compare above, bubble sorting is easier to code/read/understand and is also faster as compared to binary sorting, because binary sorting (actually) uses array recreation many times which ofcourse takes more time compared to swap.
Because there is a problem with your bubbleSort() method. Please try this way.
public void bubbleSort() {
for (int i = 0; i < number; i++) {
for (int j = 1; j < number - i; j++) {
if (list.get(j - 1).compareTo(list.get(j)) > 0) {
swap(j - 1, j);
}
}
}
}
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
I am working on a maze solver. It runs very fast on my first 2 mazes, however, my third maze takes forever. I am supposed to be able to do it in under a minute, on reasonable hardware.
The solve method takes an immense amount of time on my high-end gaming rig.
Here is the relevant source code
import java.awt.Point;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
/**
* Created by jphamlett on 6/16/17.
*/
public class main {
static class fileIO {
public static String readFile(String path, Charset encoding)
throws IOException {
byte[] encoded = Files.readAllBytes(Paths.get(path));
return new String(encoded, encoding);
}
}
static class mazeNode {
private Point point;
private int dist;
public Point getPoint() {
return point;
}
public void setPoint(Point point) {
this.point = point;
}
public int getDist() {
return dist;
}
public void setDist(int dist) {
this.dist = dist;
}
public mazeNode(Point point, int dist) {
setPoint(point);
setDist(dist);
}
}
static class Solver {
private String[] pathGrid;
private int[][] gridLength;
public void setPath(String path) {
try {
this.pathGrid = generatePath(fileIO.readFile(path, Charset.defaultCharset()));
} catch (IOException e) {
e.printStackTrace();
}
}
public Point findA() {
for (int row = 0; row < pathGrid.length; row++) {
int pos = pathGrid[row].indexOf("A");
if (pos != -1) {
return new Point(row, pos);
}
}
return null; // Something went wrong
}
public Point findB() {
for (int row = 0; row < pathGrid.length; row++) {
int pos = pathGrid[row].indexOf("B");
if (pos != -1) {
return new Point(row, pos);
}
}
return null; // Something went wrong
}
public Boolean canMove(char symbol) {
return symbol != '#';
}
public String[] generatePath(String path) {
return path.split("\n");
}
public String[] getPath() {
return this.pathGrid;
}
// Use BFS to solve the maze
public int[][] solve(int[][] gridLength, Point src, Point dest) {
if (src == null || dest == null) {
return null;
}
gridLength[src.x][src.y] = 0; // Distance to self is 0
Boolean visited[][] = new Boolean[gridLength.length][gridLength[0].length]; //Set all booleans to false
for (Boolean[] booleans : visited) {
Arrays.fill(booleans, Boolean.FALSE);
}
//System.out.println("Finished making visited array");
visited[src.x][src.y] = Boolean.TRUE;
Queue<mazeNode> queue = new LinkedList<>();
mazeNode initialNode = new mazeNode(src, 0);
queue.add(initialNode);
while (!queue.isEmpty()) {
mazeNode currentNode = queue.peek();
Point currentPoint = currentNode.getPoint();
//System.out.println("Point: " + currentPoint);
visited[currentPoint.x][currentPoint.y] = Boolean.TRUE;
if (currentPoint.equals(dest)) {
return gridLength;
}
queue.poll();
// Add adjacent valid cells
try {
if (canMove(pathGrid[currentPoint.x].charAt(currentPoint.y - 1)) && !visited[currentPoint.x][currentPoint.y - 1]) {
gridLength[currentPoint.x][currentPoint.y - 1] = currentNode.getDist() + 1;
queue.add(new mazeNode(new Point(currentPoint.x, currentPoint.y - 1), currentNode.getDist() + 1));
}
} catch (IndexOutOfBoundsException e) {
}
try {
if (canMove(pathGrid[currentPoint.x].charAt(currentPoint.y + 1)) && !visited[currentPoint.x][currentPoint.y + 1]) {
gridLength[currentPoint.x][currentPoint.y + 1] = currentNode.getDist() + 1;
queue.add(new mazeNode(new Point(currentPoint.x, currentPoint.y + 1), currentNode.getDist() + 1));
}
} catch (IndexOutOfBoundsException e) {
}
try {
if (canMove(pathGrid[currentPoint.x - 1].charAt(currentPoint.y)) && !visited[currentPoint.x - 1][currentPoint.y]) {
gridLength[currentPoint.x - 1][currentPoint.y] = currentNode.getDist() + 1;
queue.add(new mazeNode(new Point(currentPoint.x - 1, currentPoint.y), currentNode.getDist() + 1));
}
} catch (IndexOutOfBoundsException e) {
}
try {
if (canMove(pathGrid[currentPoint.x + 1].charAt(currentPoint.y)) && !visited[currentPoint.x + 1][currentPoint.y]) {
gridLength[currentPoint.x + 1][currentPoint.y] = currentNode.getDist() + 1;
queue.add(new mazeNode(new Point(currentPoint.x + 1, currentPoint.y), currentNode.getDist() + 1));
}
} catch (IndexOutOfBoundsException e) {
}
}
return null; // Cannot be reached
}
public Solver(String path) {
setPath(path);
}
}
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
Solver solver = new Solver("mazes/maze3.txt");
int[][] path = solver.solve(new int[solver.getPath().length][solver.getPath()[0].length()], solver.findA(), solver.findB());
long endTime = System.currentTimeMillis();
long totalTime = endTime - startTime;
System.out.println(totalTime);
for (int[] i : path) {
for (int j : i) {
System.out.print(j + " ");
}
System.out.println();
}
endTime = System.currentTimeMillis();
totalTime = endTime - startTime;
System.out.println(totalTime);
}
}
Here is maze2.txt
###############B#############################################
##.....########.#......................................#...##
##.###.#........####################################.#.#.#.##
##.###.#.#########..........#########.......########.#.#.#.##
##.#####...........########.#.......#.#####.########.#.#.#.##
##.########################.#.#####.#.#...#.########.#.#.#.##
##............................#####.#.##.##.########.#.#.#.##
##.###.############################.#.##.##.########.#.#.#.##
##.###.##...#...#...#...#...#.......#.##.##.########.#.#.#.##
##.###....#...#...#...#...#...#######.##.##.########.#.#.#.##
##.##################################.##.##.########.#.#.#.##
##.......................................##.########.#.#.#.##
###########################################.########.#.#.#.##
###...............................#########..........#.#.#.##
########################.###########################.#.#.#.##
#........................#...........................#.#.#.##
#.######################.#############################.#.#.##
#.#..........#.........................................#.#.##
#.#.########.#.#########################################.#.##
#.#........#.#.#.........................................#.##
#.##########.#.#.#########################################.##
#............#.#.##........................................##
##############.#.#############################.#####.########
#..............................................#####........#
########################A####################################
I have attached maze3 because the formatting here makes it shift oddly.
https://pastebin.com/c4LhG5hT
Your problem is the visited array.
First, a minor issue: The visited array should not be a Boolean[][]. Just make it a boolean[][], which is automatically initialized to all false values, so that initialization loop can be eliminated too.
Now, the main problem is that visited is not marked true until you actually process that point. This means that the same point is added many times to the queue.
Example maze:
#####################
#...#...#...#...#...#
A.#1..#2..#3..#4..#5B
#...#...#...#...#...#
#####################
In this case, point 1 is added twice to the queue. Each point up to point 2 will also be added twice. Point 2 will be added 4 times, point 3 8 times, point 4 16 times, and point 5 32 times.
As you can see, that is an exponential number of queue items for each round1 to process, doubling each time multiple paths meet.
Solution: Rename visited to queued, and mark point true at the same time you add it to the queue, thus preventing the addition of the same point multiple times.
Result: Code completes in less then 50 milliseconds for maze 3.
1) By "round" I mean processing of all queued points that is one step further away from start (distance).
I decided to optimize the piece of code below but encounter with problem. I tried to change the ArrayList to thread-safe collection by using this discussion but unfortunately something went wrong. The code is compiling but throw the exception.
Exception in thread "main" java.lang.ClassCastException:
java.util.Collections$SynchronizedRandomAccessList cannot be cast to
java.util.ArrayList at
bfpasswrd_multi.PasswordCracker.doItMulti(PasswordCracker.java:73) at
bfpasswrd_multi.PasswordCracker.runMulti(PasswordCracker.java:60) at
bfpasswrd_multi.Test.main(Test.java:16)
Please, tell me what is wrong ?
package bfpasswrd_multi;
import java.util.Scanner;
public class Test
{
public static void main(String[] args)
{
System.out.print("Type password to be cracked: ");
#SuppressWarnings("resource")
String input = new Scanner(System.in).nextLine();
PasswordCracker cracker = new PasswordCracker();
System.out.println("Multithreaded");
cracker.runMulti(input);
cracker = new PasswordCracker();
System.out.println("Finished...");
}
}
package bfpasswrd_multi;
import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class PasswordCracker
{
String passwordToCrack;
public boolean passwordFound;
int min;
int max;
StringBuffer crackedPassword;
public void prepare(String text)
{
passwordToCrack = text;
passwordFound = false;
min = 48;
max = 57; // http://ascii.cl/
crackedPassword = new StringBuffer();
crackedPassword.append((char) (min - 1));
}
public void result()
{
System.out.println("Cracked Password is: " + crackedPassword.toString());
}
public void incrementString(StringBuffer toCrack, int min, int max)
{
toCrack.setCharAt(0, (char) ((int) toCrack.charAt(0) + 1));
for (int i = 0; i < toCrack.length(); i++)
{
if (toCrack.charAt(i) > (char) max)
{
toCrack.setCharAt(i, (char) min);
if (toCrack.length() == i + 1)
{
toCrack.append((char) min);
}
else
{
toCrack.setCharAt(i + 1, (char) ((int) toCrack.charAt(i + 1) + 1));
}
}
}
}
public void runMulti(String text)
{
prepare(text);
double time = System.nanoTime();
doItMulti();
time = System.nanoTime() - time;
System.out.println(time / (1000000000));
result();
}
public void doItMulti()
{
int cores = Runtime.getRuntime().availableProcessors();
ArrayList<Future<?>> tasks ; // How do I make my ArrayList Thread-Safe? Another approach to problem in Java?
// https://stackoverflow.com/questions/2444005/how-do-i-make-my-arraylist-thread-safe-another-approach-to-problem-in-java
tasks = (ArrayList<Future<?>>) Collections.synchronizedList(new ArrayList<Future<?>>(cores));
// ArrayList<Future<?>> tasks = new ArrayList<>(cores);
ExecutorService executor = Executors.newFixedThreadPool(cores);
final long step = 2000;
for (long i = 0; i < Long.MAX_VALUE; i += step)
{
while(tasks.size() > cores)
{
for(int w = 0; w < tasks.size();w++)
{
if(tasks.get(w).isDone())
{
tasks.remove(w);
break;
}
}
try
{
Thread.sleep(0);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
{
final long j = i;
if (passwordFound == false)
{
tasks.add(executor.submit(new Runnable()
{
public void run()
{
long border = j + step;
StringBuffer toCrack = new StringBuffer(10);
toCrack.append(constructString3(j, min, max));
for (long k = j; k < border; k++)
{
incrementString(toCrack, min, max);
boolean found = toCrack.toString().equals(passwordToCrack);
if (found)
{
crackedPassword = toCrack;
passwordFound = found;
break;
}
}
}
}));
}
else
{
break;
}
}
}
executor.shutdownNow();
}
public String constructString3(long number, long min, long max)
{
StringBuffer text = new StringBuffer();
if (number > Long.MAX_VALUE - min)
{
number = Long.MAX_VALUE - min;
}
ArrayList<Long> vector = new ArrayList<Long>(10);
vector.add(min - 1 + number);
long range = max - min + 1;
boolean nextLetter = false;
for (int i = 0; i < vector.size(); i++)
{
long nextLetterCounter = 0;
while (vector.get(i) > max)
{
nextLetter = true;
long multiplicator = Math.abs(vector.get(i) / range);
if ((vector.get(i) - (multiplicator * range)) < min)
{
multiplicator -= 1;
}
vector.set(i, vector.get(i) - (multiplicator * range));
nextLetterCounter += multiplicator;
}
if (nextLetter)
{
vector.add((long) (min + nextLetterCounter - 1));
nextLetter = false;
}
text.append((char) vector.get(i).intValue());
}
return text.toString();
}
}
Many thanks in advance !
The issue that you're seeing is with this line:
tasks = (ArrayList<Future<?>>) Collections.synchronizedList(new ArrayList<Future<?>>(cores));
Collections.synchronizedList doesn't return an ArrayList; it returns some subclass of List - java.util.Collections$SynchronizedRandomAccessList to be exact - and I don't know anything about that class other than it's a List, but it's not an ArrayList.
The easy solution to this is to declare tasks to be a List<Future<?>>:
List<Future<?>> tasks =
Collections.synchronizedList(new ArrayList<Future<?>>(cores));
Dear community members thanks you for your comments. It seems that now my safe-thread list is working. For the people who interesting in solution I will submit the resolved code below. Also, probably I should mention that I rename task
to futures, please pay attention. Once again everybody thanks !
package bfpasswrd_multi;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class PasswordCracker
{
String passwordToCrack;
public boolean passwordFound;
int min;
int max;
StringBuffer crackedPassword;
public void prepare(String text)
{
passwordToCrack = text;
passwordFound = false;
min = 48;
max = 57; // http://ascii.cl/
crackedPassword = new StringBuffer();
crackedPassword.append((char) (min - 1));
}
public void result()
{
System.out.println("Cracked Password is: " + crackedPassword.toString());
}
public void incrementString(StringBuffer toCrack, int min, int max)
{
toCrack.setCharAt(0, (char) ((int) toCrack.charAt(0) + 1));
for (int i = 0; i < toCrack.length(); i++)
{
if (toCrack.charAt(i) > (char) max)
{
toCrack.setCharAt(i, (char) min);
if (toCrack.length() == i + 1)
{
toCrack.append((char) min);
}
else
{
toCrack.setCharAt(i + 1, (char) ((int) toCrack.charAt(i + 1) + 1));
}
}
}
}
public void runMulti(String text)
{
prepare(text);
double time = System.nanoTime();
doItMulti();
time = System.nanoTime() - time;
System.out.println(time / (1000000000));
result();
}
public void doItMulti()
{
int cores = Runtime.getRuntime().availableProcessors();
// ArrayList<Future<?>> task; // HOW IT WAS
//
// tasks = (ArrayList<Future<?>>) Collections.synchronizedList(new ArrayList<Future<?>>(cores)); // HOW IT WAS
List<Future<?>> futures ; // THE SOLUTION
futures = Collections.synchronizedList(new ArrayList<Future<?>>(cores)); // THE SOLUTION
// ArrayList<Future<?>> tasks = new ArrayList<>(cores);
ExecutorService executor = Executors.newFixedThreadPool(cores);
final long step = 2000;
for (long i = 0; i < Long.MAX_VALUE; i += step)
{
while(futures.size() > cores)
{
for(int w = 0; w < futures.size();w++)
{
if(futures.get(w).isDone())
{
futures.remove(w);
break;
}
}
try
{
Thread.sleep(0);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
{
final long j = i;
if (passwordFound == false)
{
futures.add(executor.submit(new Runnable()
{
public void run()
{
long border = j + step;
StringBuffer toCrack = new StringBuffer(10);
toCrack.append(constructString3(j, min, max));
for (long k = j; k < border; k++)
{
incrementString(toCrack, min, max);
boolean found = toCrack.toString().equals(passwordToCrack);
if (found)
{
crackedPassword = toCrack;
passwordFound = found;
break;
}
}
}
}));
}
else
{
break;
}
}
}
executor.shutdownNow();
}
public String constructString3(long number, long min, long max)
{
StringBuffer text = new StringBuffer();
if (number > Long.MAX_VALUE - min)
{
number = Long.MAX_VALUE - min;
}
ArrayList<Long> vector = new ArrayList<Long>(10);
vector.add(min - 1 + number);
long range = max - min + 1;
boolean nextLetter = false;
for (int i = 0; i < vector.size(); i++)
{
long nextLetterCounter = 0;
while (vector.get(i) > max)
{
nextLetter = true;
long multiplicator = Math.abs(vector.get(i) / range);
if ((vector.get(i) - (multiplicator * range)) < min)
{
multiplicator -= 1;
}
vector.set(i, vector.get(i) - (multiplicator * range));
nextLetterCounter += multiplicator;
}
if (nextLetter)
{
vector.add((long) (min + nextLetterCounter - 1));
nextLetter = false;
}
text.append((char) vector.get(i).intValue());
}
return text.toString();
}
}
I wrote a custom sound system for my game, but if two sounds are requested to play within a few ms of eachother only one sound clip will play.
I tried running the playback on a new thread like this but it did not work.
No exceptions are being thrown, it just wont play both sounds.
Thread one = new Thread() {
public void run() {
try {
CustomSound.playSound(id, loop, dist);
} catch (Exception e) {
e.printStackTrace();
}
}
};
Here is the sound player class
public class CustomSound {
/*
* Directory of your sound files
* format is WAV
*/
private static final String DIRECTORY = sign.signlink.findcachedir()+"audio/effects/";
/*
* Current volume state
* 36 chosen for default 50% volume state
*/
public static float settingModifier = 70f;
/*
* Current volume state
*/
public static boolean isMuted;
/*
* Clips
*/
private static Clip[] clipIndex = null;
/*
* Get number of files in directory
*/
private static final int getDirectoryLength() {
return new File(DIRECTORY).list().length;
}
/**
* Loads the sound clips into memory
* during startup to prevent lag if loading
* them during runtime.
**/
public static void preloadSounds() {
clipIndex = new Clip[getDirectoryLength()];
int counter = 0;
for (int i = 0; i < clipIndex.length; i++) {
try {
File f = new File(DIRECTORY+"sound "+i+".wav");
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(f);
clipIndex[i] = AudioSystem.getClip();
clipIndex[i].open(audioInputStream);
counter++;
} catch (MalformedURLException e) {
System.out.println("Sound effect not found: "+i);
e.printStackTrace();
return;
} catch (UnsupportedAudioFileException e) {
System.out.println("Unsupported format for sound: "+i);
return;
} catch (LineUnavailableException e) {
e.printStackTrace();
return;
} catch (Exception e) {
e.printStackTrace();
return;
}
}
System.out.println("Succesfully loaded: "+counter+" custom sound clips.");
}
/**
* Plays a sound
* #param soundID - The ID of the sound
* #param loop - How many times to loop this sound
* #param distanceFromSource - The distance from the source in tiles
*/
public static void playSound(final int soundID, int loop, int distanceFromSource) {
try {
if (!isMuted) {
clipIndex[soundID].setFramePosition(0);
applyVolumeSetting(clipIndex[soundID], getDistanceModifier(distanceFromSource)*settingModifier);
if (loop == 1 || loop == 0) {
clipIndex[soundID].start();
} else {
clipIndex[soundID].loop(loop);
}
/* shows how to close line when clip is finished playing
clipIndex[soundID].addLineListener(new LineListener() {
public void update(LineEvent myLineEvent) {
if (myLineEvent.getType() == LineEvent.Type.STOP)
clipIndex[soundID].close();
}
});
*/
}
} catch (Exception e) {
System.out.println("Error please report: ");
e.printStackTrace();
}
}
/**
* Applies volume setting to the clip
* #param line - the Clip to adjust volume setting for
* #param volume - the volume percentage (0-100)
* #return - the volume with applied setting
*/
public static float applyVolumeSetting(Clip line, double volume) {
//System.out.println("Modifying volume to "+volume);
if (volume > 100.0) volume = 100.0;
if (volume >= 0.0) {
FloatControl ctrl = null;
try {
ctrl = (FloatControl)(line.getControl(FloatControl.Type.MASTER_GAIN));
} catch (IllegalArgumentException iax1) {
try {
ctrl = (FloatControl)(line.getControl(FloatControl.Type.VOLUME));
} catch (IllegalArgumentException iax2) {
System.out.println("Controls.setVolume() not supported.");
return -1;
}
}
float minimum = ctrl.getMinimum();
float maximum = ctrl.getMaximum();
float newValue = (float)(minimum + volume * (maximum - minimum) / 100.0F);
//System.out.println("System min: " + minimum);
//System.out.println("System max: " + maximum);
if (newValue <= ctrl.getMinimum())
newValue = ctrl.getMinimum();
if (newValue >= ctrl.getMaximum())
newValue = ctrl.getMaximum();
ctrl.setValue(newValue);
//System.out.println("Setting modifier = " + volume);
//System.out.println("New value = " + newValue);
return newValue;
}
return -1;
}
/**
* Calculates tile distance modifier
* #param tileDistance - distance in tiles from source
* #return - the distance modifier
*/
public static float getDistanceModifier(int tileDistance) {
if (tileDistance <= 0) {
tileDistance = 0;
}
if (tileDistance >= 10) {
tileDistance = 10;
}
float distanceModifier = 0;
if (tileDistance == 10)
distanceModifier = 0.40f;
if (tileDistance == 9)
distanceModifier = 0.55f;
if (tileDistance == 8)
distanceModifier = 0.60f;
if (tileDistance == 7)
distanceModifier = 0.65f;
if (tileDistance == 6)
distanceModifier = 0.70f;
if (tileDistance == 5)
distanceModifier = 0.75f;
if (tileDistance == 4)
distanceModifier = 0.80f;
if (tileDistance == 3)
distanceModifier = 0.85f;
if (tileDistance == 2)
distanceModifier = 0.90f;
if (tileDistance == 1)
distanceModifier = 0.95f;
if (tileDistance == 0)
distanceModifier = 1.00f;
return distanceModifier;
}
}
When I tested your code on my Windows machine, I had no problems playing two different sounds in short succession:
public static void main(String[] args) throws Exception {
CustomSound.preloadSounds();
CustomSound.playSound(0, 0, 0);
CustomSound.playSound(1, 0, 0);
Thread.sleep(5000);
}
Note however, that DataLine#start() is an asynchronous call. That could be related to your problem.
Also, according to the documentation of DataLine#start(),
If invoked on a line that is already running, this method does nothing.
If that is your problem, and you want to play the same sound twice simultaneously, one possible solution would be to get another Clip instance that plays the same sound and start that.
However I'm no expert at Java's sound API so there might a more efficient way.