Java structures for storing chess moves - java

I have an Integer[64] of numbers 0 - 6 which say what type of chess piece is there. I have a Boolean[64] of what color each place is. I need to be able to save them as (Strings?) and save them for later use, but I need a fast and efficient way. As of now I am looping through both arrays and creating a 64char String, but I make a few million of them because my chess AI looks deep into the game. Thoughts?

First of all you should redefine your data structure.
Instead of two arrays with integer and booleans you can define one array
byte[64] field;
Then add two methods that retrieve the information about the type and the color:
public int getType(int fieldNo) {
# this returns the first three bits (int 0-6)
return field[fieldNo] & 0x07;
}
public boolean getColor(int fieldNo) {
# this returns the fourth bit
return (field[fieldNo] & 0x08) > 0;
}
You can now save the complete chess field just by writing/reading the fields array:
public byte[] readField(String file) throws IOException {
byte[] field = new short[64];
try (DataInputStream stream = new DataInputStream(new FileInputStream(file)); ) {
stream.readFully(field,0,64);
}
return field;
}
public void writeField(String file, byte[] field) throws IOException {
try (DataOutputStream stream = new DataOutputStream(new FileOutputStream(file)); ) {
stream.write(field,0,64);
}
return field;
}
This saves a complete field in 64 bytes.
More improvements:
Compress the 64 byte filed when saving more than one field to one file. Compression should be good because most of your bytes have value 0.
Instead of using byte[64] you can use byte[32] only and map the information to the first / last 4 bits of one byte.

Related

Java Changing variable from another class and the depending values

I have a problem with my class variables, as always ^^
So I'm constructing a class named Prng, with variables
private int randListSize = 10;
private byte randList[] = new byte[randListSize];
private byte[] seed = new byte[]{ 34, -70, -4, 117, 98 };
the getters/setters associated
and the method
public void prng() {
SecureRandom random;
try {
random = SecureRandom.getInstance("SHA1PRNG");
random.setSeed(seed);
random.nextBytes(randList);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
in another class named Test.java, I want to :
1) set randListSize to /number of random bytes I want
2) have the randList of this size, and not from original 10 size
whenever I try, my randList is always of size 10. Can you help me please ?
in my class Test I've written :
Prng prng = new Prng();
System.out.println(prng.getRandListSize() + " " + prng.getRandList().length);
prng.setRandListSize(11);
System.out.println(prng.getRandListSize()+ " " + prng.getRandList().length);
which returns me "10 10 ; 11 10" and I want "11 11" at the end.
EDIT : here's my getters/setters :
public int getRandListSize() {
return randListSize;
}
public void setRandListSize(int randListSize) {
this.randListSize = randListSize;
}
public byte[] getSeed() {
return seed;
}
public void setSeed(byte[] seed) {
this.seed = seed;
}
public byte[] getRandList() {
return randList;
}
public void setRandList(byte[] randList) {
this.randList = randList;
}
First, randListSize, in my opinion, is a useless field, as that property can be retrieved directly from the array, and as the operation isn't expensive the value doesn't need to be cached. Thus, you really don't need getters/setters for that field either. I see you're using it as an initial size variable, but in that case I think it'd be better for it to be a parameter for a constructor/factory method instead, as it really doesn't need to be used anywhere else.
Second, setRandListSize() doesn't actually change randList's size, as arrays, once created, cannot be structurally modified (i.e. you can't make arrays longer/shorter after creating them). You're just changing an unrelated variable, which leads to some confusion once randListSize stops matching randList.length. This is the reason you're seeing 11 10 instead of 11 11 -- randListSize is only used at the moment of array creation, and later changes to randListSize don't affect the array.
In order to get the result you want, you're going to have to allocate an entirely new array and set randList to point to it instead of your old one, which you can do using your setRandList() method. Alternatively, you can write a method, perhaps called createNewRandList(int newLength), to do all the work at once.
Your setRandListSize method will need to recreate the randList array. If you need to keep the data in it, your method should copy whatever data can fit into the new array.
public void setRandListSize(int randListSize) {
this.randListSize = randListSize;
this.randList = new byte[randListSize];
}

Java: How to have one array reference the start of another?

Im trying to make a fun application that will take a sound file and modify it, and create a new sound file.
One of the things I am trying to do is make the sound file twice as long. So I essentially make a new array that goes {2,2,3,3,7,7,8,8} instead of the original {2,3,7,8}. I am using doubles, this is simply an example
I want the original array (samples) to now reference the start of the array I just created (temp) so when the file saves it now save the temp array.
I can increase or decrease the volume of the music file no problem, and save it as such. I omitted that part of the code as it is not pertinent here.
If anyone is kind enough to help me, I also want to know the why behind it
public class Sound {
double[] samples;
//So we only have to declare it once. Reference to an array
public Sound() {
//This constructor should initialize the samples array to be empty
samples = new double[0];
//Initialize an array with nothing because we will be using that to reference the
//location of other arrays
}
public void wavRead(String fileName) {
samples = WavIO.read(fileName);
//Samples was an adress of an array we set to 0. Then we used WavIO to create an aray of doubles, now
//we tell samples to reference this new address over here. Samples has the addsss of the new array
}
public void wavSave(String fileName) {
WavIO.write(fileName, samples);
}
public void lengthen() {
double[] temp = new double[(samples.length *2)];
int t = 0;
for(int i = 0; i < samples.length; i++) {
//Set a variable to increase the temp array by
temp[t] = samples[i];
//Have position 0 of temp = position 0 of soundRaw
t++;
//Increase the position in the temp array by one
temp[t] = samples[i];
//Have position 1 of temp array = position 0 of soundRaw
}
samples[0] = temp;
//Here is where I try and have the samples array reference the start of another array. I tried multiple things, this is simply the last effort I tried
}
And here is the application I am using to test the code
public class App {
public static void main(String[] args) {
Sound s = new Sound();
//We are now calling the other code
s.wavRead("bye8");
//If you want to mess with your own .wav file, replace this name
s.lengthen();
s.wavSave("bye8New");
}
}
Replacing this code line
samples[0] = temp;
with just
samples = temp;
will suffice! :)
Use a DoubleBuffer, it is much easier to do what you want to achieve.
To create a new DoubleBuffer which is... Double... The size and duplicates, you'll then do:
// Important!
origBuf.rewind();
final DoubleBuffer newBuf = DoubleBuffer.allocate(origBuf.remaining() * 2);
double value;
while (origBuf.hasRemaining()) {
value = origBuf.get();
newBuf.put(value).put(value);
}
Then newBuf.array() will return the double[] array "with duplicates".
Also note that a DoubleBuffer, like any XBuffer, allows you to set endianness.
Just use samples=temp; instead of samples[0] = temp;!

Library for serializing java objects to fixed-width byte arrays

I would like to store a very simple pojo object in binary format:
public class SampleDataClass {
private long field1;
private long field2;
private long field3;
}
To do this, I have written a simple serialize/deserialize pair of methods:
public class SampleDataClass {
// ... Fields as above
public static void deserialize(ByteBuffer buffer, SampleDataClass into) {
into.field1 = buffer.getLong();
into.field2 = buffer.getLong();
into.field3 = buffer.getLong();
}
public static void serialize(ByteBuffer buffer, SampleDataClass from) {
buffer.putLong(from.field1);
buffer.putLong(from.field2);
buffer.putLong(from.field3);
}
}
Simple and efficient, and most importantly the size of the objects in binary format is fixed. I know the size of each record serialized will be 3 x long, i.e. 3 x 8bytes = 24 bytes.
This is crucial, as I will be recording these sequentially and I need to be able to find them by index later on, i.e. "Find me the 127th record".
This is working fine for me, but I hate the boilerplate - and the fact that at some point I'm going to make a mistake and end up write a load of data that can't be read-back because there's an inconsistency between my serialize / deserialize method.
Is there a library that generate something like this for me?
Ideally I'm looking for something like protobuf, with a fixed-length encoding scheme. Later-on, I'd like to encode strings too. These will also have a fixed length. If a string exceeds the length it's truncated to n bytes. If a string is too short, I'll null-terminate it (or similar).
Finally, protobuf supports different versions of the protocol. It is inevitable I'll need to do that eventually.
I was hoping someone had a suggestion, before I start rolling-my-own
Make your class inherit the java.io.Serializable interface. Then you can use java.io.ObjectOutputStream and java.io.ObjectInputStream to serialize / deserialize objects to / from streams. The write and read methods take byte arrays as arguments.
To make it fixed length, standardize the size of the byte[] arrays used.
The most difficult part here is capping your strings or collections. You can do this with Kryo for Strings by overriding default serializers. Placing strings into a custom buffer class (i.e. FixedSerializableBuffer) which stores or is annotated with a length to cut also makes sense.
public class KryoDemo {
static class Foo{
String s;
long v;
Foo() {
}
Foo(String s, long v) {
this.s = s;
this.v = v;
}
#Override
public String toString() {
final StringBuilder sb = new StringBuilder("Foo{");
sb.append("s='").append(s).append('\'');
sb.append(", v=").append(v);
sb.append('}');
return sb.toString();
}
}
public static void main(String[] args) {
Kryo kryo = new Kryo();
Foo foo = new Foo("test string", 1);
kryo.register(String.class, new Serializer<String>() {
{
setImmutable(true);
setAcceptsNull(true);
}
public void write(Kryo kryo, Output output, String s) {
if (s.length() > 4) {
s = s.substring(0, 4);
}
output.writeString(s);
}
public String read(Kryo kryo, Input input, Class<String> type) {
return input.readString();
}
});
// serialization part, data is binary inside this output
ByteBufferOutput output = new ByteBufferOutput(100);
kryo.writeObject(output, foo);
System.out.println("before: " + foo);
System.out.println("after: " + kryo.readObject(new Input(output.toBytes()), Foo.class));
}
}
This prints:
before: Foo{s='test string', v=1}
after: Foo{s='test', v=1}
If the only additional requirement over standard serialization is efficient random access to the n-th entry, there are alternatives to fixed-size entries, and that you will be storing variable length entries (such as strings) makes me think that these alternatives deserve consideration.
One such alternative is to have a "directory" with fixed length entries, each of which points to the variable length content. Random access to an entry is then implemented by reading the corresponding pointer from the directory (which can be done with random access, as the directory entries are fixed size), and then reading the block it points to. This approach has the disadvantage that an additional I/O access is required to access the data, but permits a more compact representation of the data, as you don't have to pad variable length content, which in turn speeds up sequential reading. Of course, neither the problem nor the above solution is novel - file systems have been around for a long time ...

How can I avoid using a lot of variables?

I would like to create a simple program that would output the atomic mass of any element entered. I am taking a Java course that I recently started so I don't know how to avoid using over 100 variables each with the elements atomic mass.
Also how could I get a if statement to use the name input from the user (which I know how to store in a string) and match it with one of the elements, in order to output the element's mass (corresponding to method used to store the multiple elements).
How can I condense this example code:
int carbon = 12;
int oxygen = 16;
int hydrogen = 1;
int sulfur = 32;
etc....
Sounds like your first step is to learn about the Map data structure. You can use it to associate the string names to integer values and then look them back up later.
Map<String, Integer> elements = new HashMap<String, Integer>();
elements.put("CARBON", 12);
elements.put("OXYGEN", 16);
//etc
Then if you have some input you can look up the number.
String userInput = scanner.next(); // or however you're getting input
Integer atomicWeight = elements.get(userInput.toUpper());
if (atomicWeight == null) //print element not found etc
Then once you have the program down and working you can learn about whatever technology is appropriate for loading the reference data from outside of the source code, whether that's a file or a database or a webservice or whatever.
I'd likely define an enum if confronted with this problem.
public enum Elements
{
HYDROGEN(1),
...
UNOBTANIUM(666);
public final int atomicWeight;
Elements(int atomicWeight)
{
this.atomicWeight = atomicWeight;
}
}
then to get the right element it's
String name = ...// from user input
Elements e = Elements.valueOf(name.toUpperCase());
I'd recommend using an enum as some have suggested, though i'd do it a little different. Maps have lots of overhead, and since your data is not dynamic it's not a great fit. Atomic mass should be a decimal value (double or BigDecimal depending on what you're using it for), not an int
public enum AtomicElement {
HYDROGEN(1.00794),
HELIUM(4.002602),
...;
private double atomicMass;
private AtomicElement (double atomicMass) {
this.atomicMass = atomicMass;
}
public int getAtomicNumber() {
return ordinal();
}
public double getAtomicMass() {
return atomicMass;
}
public static AtomicElement forAtomicNumber(int atomicNumber) {
return AtomicElement.values()[atomicNumber];
}
public static AtomicElement forElementName(String elementName) {
return AtomicElement.valueOf(elementName);
}
}
Then you can search by atomic number or element name
AtomicElement.forAtomicNumber(2);
AtomicElement.forElementName("CARBON");
This does however assume you're going to represent the entire periodic table with no gaps in the data, since it's using the ordinal() value as the atomic number. If you want gaps, you'll have to have an int field for the atomic number and your "forAtomicNumber" function will have to cycle through the "values()" to find the one with the given number.
You could even extend this if you wanted to include known isotopes, etc... if your requirements dictate that.
Because the atomic mass of the elements is not going to change at any point in your app, you should define them as final:
public class AtomicMass {
public static final int CARBON = 12;
public static final int OXYGEN = 16;
...
}
...or, you could use an enum:
public static enum Element {
carbon(12),
oxygen(16),
hydrogen(1),
sulfur(32);
private int atomicMass;
private Element( int mass ) {
this.atomicMass = mass;
}
}
If you order your elements sequentially (and add an UNKNOWN for 0) you wouldn't even need to explicitly provide the mass.
I like to group related data into arrays or arrayLists.
String[] elements = new String[# of elements in table];
Based on the position of the element you can have the atomic number.
Then I would loop through them to find any element or fill the array.
You can look into Java Scanner class to get input from user.
Create a class called Element that contains attributes like name, atomic number, etc. Each element will correspond to an instance of Element. You can then put all the Elementss in several maps, keyed by name, atomic number, etc. Use a factory class to instantiate and initialize the maps, and provide lookup methods.
If I understand you correctly you just want to only have 1 variable to store all the elements and their masses in which case I would recommend a HashMap. It will not really save on code lines but will let you do number 2 pretty easily. HashMaps store a set of key-value pairs and you can get the value if you have the key so this would create the list:
//Declare a new hashmap and initialize it
HashMap<String, Integer> elements = new HashMap<>();
//Add element information
elements.put("CARBON", 12);
elements.put("OXYGEN", 16);
elements.put("HYDROGEN", 1);
elements.put("SULFUR", 32);
Then for example to get user input from a dialog box and print the result to command line you do something like this:
//Collect user input and convert it to all upper case (in real life you would validate this)
String input = JOptionPane.showInputDialog(null, "Please enter an element name").toUpperCase();
//If element name exists in hashmap print its atomic weight
if(elements.containsKey(input.toUpperCase())){
System.out.println("Atomic Weight: " + elements.get(input));
}
Store your data in a file
Element, Weight
oxygen = 16
carbon, 12
.
.
.
Pseudocode:
//Read data file into a `Map<String, int>`
//Get user input
//Access map
//Output

Is There a More Efficient Way to Convert Between ArrayList and Array

Using Java, I have a class which retrieves a webpage as a byte array. I then need to strip out some content if it exists. (The application monitors web pages for changes, but needs to remove session Ids from the html which are created by php, and would mean changes were detected each visit to the page).
Some of the resulting byte arrays could be 10s of 1000s bytes long. They're not stored like this - a 16 byte MD5 of the page is stored. However, it is the original full size byte array which needs to be processed.
(UPDATE - the code does not work. See comment from A.H. below)
A test showing my code:
public void testSessionIDGetsRemovedFromData() throws IOException
{
byte[] forumContent = "<li class=\"icon-logout\">Logout [ barry ]</li>".getBytes();
byte[] sidPattern = "&sid=".getBytes();
int sidIndex = ArrayCleaner.getPatternIndex(forumContent, sidPattern);
assertEquals(54, sidIndex);
// start of cleaning code
ArrayList<Byte> forumContentList = new ArrayList<Byte>();
forumContentList.addAll(forumContent);
forumContentList.removeAll(Arrays.asList(sidPattern));
byte[] forumContentCleaned = new byte[forumContentList.size()];
for (int i = 0; i < forumContentCleaned.length; i++)
{
forumContentCleaned[i] = (byte)forumContentList.get(i);
}
//end of cleaning code
sidIndex = ArrayCleaner.getPatternIndex(forumContentCleaned, sidPattern);
assertEquals(-1, sidIndex);
}
This all works fine, but I'm worried about the efficiency of the cleaning section. I had hoped to operate solely on arrays, but the ArrayList has nice built in functions to removed a collection from the ArrayList, etc, which is just what I need. So I have had to create an ArrayList of Byte, as I can't have an ArrayList of the primitive byte (can anyone tell me why?), convert the pattern to remove to another ArrayList (I suppose this could be an ArrayList all along) to pass to removeAll(). I then need to create another byte[] and cast each element of the ArrayList of Bytes to a byte and add it to the byte[].
Is there a more efficient way of doing all this?
Can it be performed using arrays?
UPDATE
This is the same functionality using strings:
public void testSessionIDGetsRemovedFromDataUsingStrings() throws IOException
{
String forumContent = "<li class=\"icon-logout\">Logout [ barry ]</li>";
String sidPattern = "&sid=";
int sidIndex = forumContent.indexOf(sidPattern);
assertEquals(54, sidIndex);
forumContent = forumContent.replaceAll(sidPattern, "");
sidIndex = forumContent.indexOf(sidPattern);
assertEquals(-1, sidIndex);
}
Is this as efficient as the array/arrayList method?
Thanks,
Barry
You can use List#toArray() to convert any list to an array.
Things are a bit more complicated in this specific use case because there is no elegant way to auto-unbox (from Byte to byte) when converting the list. Good ol' Java generics. Which is a nice segue into...
So I have had to create an ArrayList of Byte, as I can't have an ArrayList of the primitive byte (can anyone tell me why?)
Because, in Java, generic type parameters cannot be primitives. See Why can Java Collections not directly store Primitives types?
Side note: as a matter of style, you should almost always declare ArrayList types as List:
List<Byte> forumContentList = new ArrayList<Byte>();
See Java - declaring from Interface type instead of Class and Type List vs type ArrayList in Java.
This all works fine, I'm worried about the efficiency of the cleaning section...
Really? Did you inspect the resulting "string"? On my machine the data in forumContentCleaned still contains the &sid=... data.
That's because
forumContentList.removeAll(Arrays.asList(sidPattern));
tries to remove a List<byte[]> from a List<Byte>. This will do nothing. And even if you replace the argument of removeAll with a real List<Byte> containing the bytes of "&sid=", then you will remove ALL occurences of each a, each m, each p and so forth. The resulting data will look like this:
<l cl"con-logout">< href"./uc.h?oelogout34043284674572e35881e022c68fc8" ttle....
Well, strictly speaking, the &sid= part is gone, but I'm quite sure this is not what you wanted.
Therefore take a step back and think: You are doing string manipulation here, so use a StringBuilder, feed it with the String(forumContent) and do your manipulation there.
Edit
Looking at the given example input string, I guess, that also the value of sid should be removed, not only the key. This code should do it efficiently without regular expresions:
String removeSecrets(String input){
StringBuilder sb = new StringBuilder(input);
String sidStart = "&sid=";
String sidEnd = "\"";
int posStart = 0;
while ((posStart = sb.indexOf(sidStart, posStart)) >= 0) {
int posEnd = sb.indexOf(sidEnd, posStart);
if (posEnd < 0) // delete as far as possible - YMMV
posEnd = sb.length();
sb.delete(posStart, posEnd);
}
return sb.toString();
}
Edit 2
Here is a small benchmark between StringBuilder and String.replaceAll:
public class ReplaceAllBenchmark {
public static void main(String[] args) throws Throwable {
final int N = 1000000;
String input = "<li class=\"icon-logout\">Logout [ barry ]&sid=3a4043284674572e35881e022c68fcd8\"</li>";
stringBuilderBench(input, N);
regularExpressionBench(input, N);
}
static void stringBuilderBench(String input, final int N) throws Throwable{
for(int run=0; run<5; ++run){
long t1 = System.nanoTime();
for(int i=0; i<N; ++i)
removeSecrets(input);
long t2 = System.nanoTime();
System.out.println("sb: "+(t2-t1)+"ns, "+(t2-t1)/N+"ns/call");
Thread.sleep(1000);
}
}
static void regularExpressionBench(String input, final int N) throws Throwable{
for(int run=0; run<5; ++run){
long t1 = System.nanoTime();
for(int i=0; i<N; ++i)
removeSecrets2(input);
long t2 = System.nanoTime();
System.out.println("regexp: "+(t2-t1)+"ns, "+(t2-t1)/N+"ns/call");
Thread.sleep(1000);
}
}
static String removeSecrets2(String input){
return input.replaceAll("&sid=[^\"]*\"", "\"");
}
}
Results:
java version "1.6.0_20"
OpenJDK Runtime Environment (IcedTea6 1.9.9) (6b20-1.9.9-0ubuntu1~10.04.2)
OpenJDK 64-Bit Server VM (build 19.0-b09, mixed mode)
sb: 538735438ns, 538ns/call
sb: 457107726ns, 457ns/call
sb: 443282145ns, 443ns/call
sb: 453978805ns, 453ns/call
sb: 458895308ns, 458ns/call
regexp: 2404818405ns, 2404ns/call
regexp: 2196834572ns, 2196ns/call
regexp: 2239056178ns, 2239ns/call
regexp: 2164337638ns, 2164ns/call
regexp: 2177091893ns, 2177ns/call
I dont think two codes have the same function.
the first code removes all characters in the sidPattern from forumContent.
the second code removes the sidPattern string from forumContnt, maybe not functional, cause replaceAll() accept the argument as regular expression pattern.
are you sure you want to remove "&sid=" rather than "&sid=3a4043284674572e35881e022c68fcd8" ?
anyway, I think String is fine, List is a little bit heavy.

Categories