Calculating the optimal move in checkers - java

I created a checkress game and I would like the computer to calculate the most optimal move.
Here is what I've done so far:
public BoardS calcNextMove(BoardS bs)
{
ArrayList<BoardS>options = calcPossibleOptions(bs);
int max = -1;
int temp;
int bestMove = 0;
for(int k=0;k<options.size();k++)
{
temp = calculateNextMove2(options.get(k));
if(max<temp)
{
max = temp;
bestMove = k;
}
}
return options.get(bestMove);
}
public int calculateNextMove2(BoardS bs)
{
int res = soWhoWon(bs);
if(res == 2) //pc won(which is good so we return 1)
return 1;
if(res == 1)
return 0;
ArrayList<BoardS>options = calcPossibleOptions(bs);
int sum = 0;
for(int k=0;k<options.size();k++)
{
sum += calculateNextMove2(options.get(k));
}
return sum;
}
I keep getting
Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
calcPossibleOptions works good, it's a function that returns an array of all the possible options.
BoardS is a clas that represent a game board.
I guess I have to make it more efficient, how?

The recursion on "calculateNextMove2()" will run too deep and this is why you get a StackOverFlow. If you expect the game to run to the end (unless relatively close to an actual win) this may take a very long time indeed. Like with chess e.g. (which I have more experience with) an engine will go maybe 20 moves deep before you will likely go with what it's found thus far. If you ran it from the start of a chess game... it can run for 100s of years on current technology (and still not really be able to say what the winning first move is). Maybe just try 10 or 20 moves deep? (which would still beat most humans - and would still probably classify as "best move"). As with chess you will have the difficulty of assessing a position as good or bad for this to work (often calculated as a combination of material advantage and positional advantage). That is the tricky part. Note: Project Chinook has done what you're looking to achieve - it has "defeated" the game of Checkers (no such thing exists yet for chess EDIT: Magnus Carslen has "deafeted" the game for all intents and purposes :D).
see: Alpha-beta pruning
(it may help somewhat)
Also here is an (oldish) paper I saw on the subject:
Graham Owen 1997 Search Algorithms and Game Playing
(it may be useful)
Also note that returning the first move that results in a "win" is 'naive' - because it may be a totally improbably line of moves where the opponent will gain an advantage if they don't play in a very particular win - e.g. Playing for Fools Mate or Scholars Mate in chess... (quick but very punishable)

You're going to need to find an alternative to MinMax, even with alpha-beta pruning most likely, as the board is too large making too many possible moves, and counter moves. This leads to the stack overflow.
I was fairly surprised to see that making the full decision tree for Tic-Tac-Toe didn't overflow myself, but I'm afraid I don't know enough about AI planning, or another algorithm for doing these problems, to help you beyond that.

Related

Is there a better method for randomizing functions besides Random?

I have 2 strings in an array. I want there to be a 10% chance of one and 90% chance to select the other. Right now I am using:
Random random = new Random();
int x = random.nextInt(100 - 1) + 1;
if (x < 10) {
string = stringArray(0);
} else {
string = stringArray(1);
}
Is this the best way of accomplishing this or is there a better method?
I know it's typically a bad idea to submit a stack overflow response without submitting code, but I really challenge this question of " the best way." People ask this all the time and, while there are established design patterns in software worth knowing, this question almost always can be answered by "it depends."
For example, your pattern looks fine (I might add some comments). You might get a minuscule performance increase by using 1 - 10 instead of 1 - 100, but the things you need to ask yourself are as follows :
If I get hit by a bus, is the person who is going to be working on the application going to know what I was trying to do?
If it isn't intuitive, I should write a comment. Then I should ask myself, "Can I change this code so that a comment isn't necessary?"
Is there an existing library that solves this problem? If so, is it FOSS approved (if applicable) / can I use it?
What is the size of this codebase eventually going to be? Am I making a full program with microservices, a DAO, DTO, Controller, View, and different layers for validation?
Is there an existing convention to solve my problem (either at my company or in general), or is it unique enough that I can take my own spin on it?
Does this follow the DRY principle?
I'm in (apparently) a very small camp on stack overflow that doesn't always believe in universal "bests" for solving code problems. Just remember, programming is only as hard as the problem you're trying to solve.
EDIT
Since people asked, I'd do it like this:
/*
* #author DaveCat
* #version 1.0
* #since 2019-03-9
* Convenience method that calculates 90% odds of A and 10% odds of B.
*
*/
public static String[] calculatesNinetyPercent()
{
Random random = new Random();
int x = random.nextInt(10 - 1 ) + 1
//Option A
if(x <= 9) {
return stringArray(0);
}
else
{
//Option B
return stringArray(1);
}
}
As an aside, one of the common mistakes junior devs make in enterprise level development is excessive comments.This has a javadoc, which is probably overkill, but I'm assuming this is a convenience method you're using in a greater program.
Edit (again)
You guys keep confusing me. This is how you randomly generate between 2 given numbers in Java
One alternative is to use a random float value between 0..1 and comparing it to the probability of the event. If the random value is less than the probability, then the event occurs.
In this specific example, set x to a random float and compare it to 0.1
I like this method because it can be used for probabilities other than percent integers.

Count how many list entries have a string property that ends with a particular char

I have an array list with some names inside it (first and last names). What I have to do is go through each "first name" and see how many times a character (which the user specifies) shows up at the end of every first name in the array list, and then print out the number of times that character showed up.
public int countFirstName(char c) {
int i = 0;
for (Name n : list) {
if (n.getFirstName().length() - 1 == c) {
i++;
}
}
return i;
}
That is the code I have. The problem is that the counter (i) doesn't add 1 even if there is a character that matches the end of the first name.
You're comparing the index of last character in the string to the required character, instead of the last character itself, which you can access with charAt:
String firstName = n.getFirstName()
if (firstName.charAt(firstName.length() - 1) == c) {
i++;
}
When you're setting out learning to code, there is a great value in using pencil and paper, or describing your algorithm ahead of time, in the language you think in. Most people that learn a foreign language start out by assembling a sentence in their native language, translating it to foreign, then speaking the foreign. Few, if any, learners of a foreign language are able to think in it natively
Coding is no different; all your life you've been speaking English and thinking in it. Now you're aiming to learn a different pattern of thinking, syntax, key words. This task will go a lot easier if you:
work out in high level natural language what you want to do first
write down the steps in clear and simple language, like a recipe
don't try to do too much at once
Had I been a tutor marking your program, id have been looking for something like this:
//method to count the number of list entries ending with a particular character
public int countFirstNamesEndingWith(char lookFor) {
//declare a variable to hold the count
int cnt = 0;
//iterate the list
for (Name n : list) {
//get the first name
String fn = n.getFirstName();
//get the last char of it
char lc = fn.charAt(fn.length() - 1);
//compare
if (lc == lookFor) {
cnt++;
}
}
return cnt;
}
Taking the bullet points in turn:
The comments serve as a high level description of what must be done. We write them aLL first, before even writing a single line of code. My course penalised uncommented code, and writing them first was a handy way of getting the requirement out of the way (they're a chore, right? Not always, but..) but also it is really easy to write a logic algorithm in high level language, then translate the steps into the language learning. I definitely think if you'd taken this approach you wouldn't have made the error you did, as it would have been clear that the code you wrote didn't implement the algorithm you'd have described earlier
Don't try to do too much in one line. Yes, I'm sure plenty of coders think it looks cool, or trick, or shows off what impressive coding smarts they have to pack a good 10 line algorithm into a single line of code that uses some obscure language features but one day it's highly likely that someone else is going to have to come along to maintain that code, improve it or change part of what it does - at that moment it's no longer cool, and it was never really a smart thing to do
Aominee, in their comment, actually gives us something like an example of this:
return (int)list.stream().filter(e -> e.charAt.length()-1)==c).count();
It's a one line implementation of a solution to your problem. Cool huh? Well, it has a bug* (for a start) but it's not the main thrust of my argument. At a more basic level: have you got any idea what it's doing? can you look at it and in 2 seconds tell me how it works?
It's quite an advanced language feature, it's trick for sure, but it might be a very poor solution because it's hard to understand, hard to maintain as a result, and does a lot while looking like a little- it only really makes sense if you're well versed in the language. This one line bundles up a facility that loops over your list, a feature that effectively has a tiny sub method that is called for every item in the list, and whose job is to calculate if the name ends with the sought char
It p's a brilliant feature, a cute example and it surely has its place in production java, but it's place is probably not here, in your learning exercise
Similarly, I'd go as far to say that this line of yours:
if (n.getFirstName().length() - 1 == c) {
Is approaching "doing too much" - I say this because it's where your logic broke down; you didn't write enough code to effectively implement the algorithm. You'd actually have to write even more code to implement this way:
if (n.getFirstName().charAt(n.getFirstName().length() - 1) == c) {
This is a right eyeful to load into your brain and understand. The accepted answer broke it down a bit by first getting the name into a temporary variable. That's a sensible optimisation. I broke it out another step by getting the last char into a temp variable. In a production system I probably wouldn't go that far, but this is your learning phase - try to minimise the number of operations each of your lines does. It will aid your understanding of your own code a great deal
If you do ever get a penchant for writing as much code as possible in as few chars, look at some code golf games here on the stack exchange network; the game is to abuse as many language features as possible to make really short, trick code.. pretty much every winner stands as a testament to condense that should never, ever be put into a production system maintained by normal coders who value their sanity
*the bug is it doesn't get the first name out of the Name object

Reducing amount of RAM BFS algorithm takes

I have written a 2x2x2 rubiks cube solver that uses a breadth first search algorithm to solve a cube position entered by the user. The program does solve the cube. However I encounter a problem when I enter in a hard position to solve which would be found deep in the search, I run out of heap space. My computer only has 4 GB of RAM and when I run the program I give 3GB to it. I was wondering what I could do to reduce the amount of ram the search takes. Possibly by changing a few aspects of the BFS.
static private void solve(Cube c) {
Set<Cube> cubesFound = new HashSet<Cube>();
cubesFound.add(c);
Stack<Cube> s = new Stack<Cube>();
s.push(c);
Set<Stack<Cube>> initialPaths = new HashSet<Stack<Cube>>();
initialPaths.add(s);
solve(initialPaths, cubesFound);
}
static private void solve(Set<Stack<Cube>> livePaths, Set<Cube> cubesFoundSoFar) {
System.out.println("livePaths size:" + livePaths.size());
int numDupes = 0;
Set<Stack<Cube>> newLivePaths = new HashSet<Stack<Cube>>();
for(Stack<Cube> currentPath : livePaths) {
Set<Cube> nextStates = currentPath.peek().getNextStates();
for (Cube next : nextStates) {
if (currentPath.size() > 1 && next.isSolved()) {
currentPath.push(next);
System.out.println("Path length:" + currentPath.size());
System.out.println("Path:" + currentPath);
System.exit(0);
} else if (!cubesFoundSoFar.contains(next)) {
Stack<Cube> newCurrentPath = new Stack<Cube>();
newCurrentPath.addAll(currentPath);
newCurrentPath.push(next);
newLivePaths.add(newCurrentPath);
cubesFoundSoFar.add(next);
} else {
numDupes += 1;
}
}
}
String storeStates = "positions.txt";
try {
PrintWriter outputStream = new PrintWriter(storeStates);
outputStream.println(cubesFoundSoFar);
outputStream.println(storeStates);
outputStream.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Duplicates found " + numDupes + ".");
solve(newLivePaths, cubesFoundSoFar);
}
That is the BFS but I fear that its not all the information needed to understand what is going on so here is the link to file with all the code. https://github.com/HaginCodes/2x2-Cube-Solver/blob/master/src/com/haginonyango/pocketsolver/Cube.java
By definition, "Best first search" keeps the entire search frontier of possible paths through the space.
That can be exponentially large. With 3x3x3 Rubik's cube, I think there are 12? possible moves at each point, so a 10 move sequence to solve arguably requires 12^10 combinations which is well over a billion (10^9). WIth this many states, you'll want to minimize the size of the state to minimize total storage. (Uh, you actually print all the states? " outputStream.println(cubesFoundSoFar);" Isnt that a vast amount of output?)
With 2x2x2, you only have 8 possible moves at each point. I don't know solution lengths here for random problems. If it is still length 10, you get 8^10 which is still pretty big.
Now, many move sequences lead to the same cube configuration. To recognize this you need to check that a generated move does not re-generate a position already visited. You seem to be doing that (good!) and tracking the number of hits; I'd expect that hit count to be pretty high as many paths should lead to the same configuration.
What you don't show, is how you score each move sequence to guide the search. What node does it expand next? This is where best comes into play. If you don't have any guidance (e.g., all move sequences enumerated have the same value), you truly will wander over a huge space because all move sequences are equally good. What guides your solver to a solution? You need something like a priority queue over nodes with priority being determined by score, and that I don't see in the code you presented here.
I don't know what a great heuristic for measuring the score as a quality of a move sequence, but you can start by scoring a move sequence with the number of moves it takes to arrive there. The next "best move" to try is then the one with the shortest path. That will probably help immensely.
(A simple enhancement that might work is to count the number of colors on a face; 3 colors hints [is this true?] that it might take 3-1 --> 2 moves minimum to remove the wrong colors. Then the score might be #moves+#facecolors-1, to estimate number of moves to a solution; clearly you want the shortest sequence of moves. This might be a so-called "admissible" hueristic score).
You'll also have to adjust your scheme to detecting duplicate move sequences. When you find an already encountered state, that state will now presumably have attached to it the score (move count) it takes to reach that state. When you get a hit, you've found another way to get to that same state... but the score for new path, may be smaller than what is recorded in the state. In this case, you need to revise the score of discovered duplicate state with the smaller new score. This way a path/state with score 20 may in fact be discovered to have a score of 10, which means it is suddenly improved.

Java - farkle (greed) game (die and player arrays, multiple classes)

I am trying to write code for a command like game of Farkle (greed). This is an Intro to computer science class. In a nutshell, you roll 6 die, and scores are based off of what you roll. Then you are required to remove the die that were used -> display score from that roll -> display total score -> ask if they would like to roll again. First player to a score determined by the user is the winner.
I have a bunch of code written for the model, and I am working on the view. I am struggling with the view, which makes it harder to advance on my model code. We are required to use the Die and Player classes (we were given those). I use the Die quickly, not quite sure how to apply the Player class.
When I try to run my command line, I am getting out of bounds errors on my rollCheck() array and other issues in my model that were not coming up when I simply was testing in main. I apologize for the amount of code posted, but I figure seeing everything makes it easier to solve (goes without saying really).
If anyone can give me pushes in the right direction to solving and making my program work, that would be great! Thank you.
Without being able to run the program to be sure its hard to be certain (I need the top of GreedGame) but i'd be fairly confident its the following:
in rollDie die is set to an array of ints on size remainingDie
this.die = new int [remainingDie];
later, within rollCheck the contents of the die array up to and including remainingDie, going over the array by 1
for (int i = 0; i <= remainingDie; i++) { // Count up quantity of die (6 set to remaining die)
if (die[i] == 1) {
this.numFreq[0] += 1;
}
....
....
}
So in short I believe i <= remainingDie; should be i < remainingDie; because an array with 6 entries has "boxes" 0,1,2,3,4,5

Collision Avoidance Example or Help

I have been trying to find a collision avoidance example that I can adapt and use for a game I am working on. It will be used to model a skier's movements to avoid trees on the hill. I am basing the movement off of Steering Behaviors for Autonomous Characters and there are a lot of good examples for path following and flocking, but I can't find any good ones for collision avoidance. The Nature of Code website had awesome tutorials for steering but seemed to cover everything but obstacle avoidance.
I converted the code from here but it doesn't work as well as it should because collisions are found by projecting the obstacles center onto the velocity vector without taking into account when the obstacles center may be outside the limits of collision but the circle is still colliding. Here is the code I adapted (written in Processing (Java based)).
// Method to update location
void update() {
// Update velocity
vel.add(acc);
// Limit speed
vel.limit(maxspeed);
loc.add(vel);
// Reset accelertion to 0 each cycle
acc.mult(0);
}
void obstacleAvoid() {
float checkLength = 30*vel.mag();
PVector forward,diff,ray,projection,force;
float dotProd,dis;
forward = vel.get();
forward.normalize();
ray = forward.get();
ray.mult(checkLength);
for ( int i = 0; i < obs.size(); i++ ) {
Obstacle ob = (Obstacle)obs.get(i);
diff = ob.pos.get();
diff.sub(loc);
PVector temp2 = forward.get();
temp2.mult(ob.r);
diff.sub(temp2);
dotProd = diff.dot(forward);
if ( dotProd > 0 ) {
projection = forward.get();
projection.mult(dotProd);
dis = PVector.dist(projection,diff);
if ( (dis < (ob.r + r)) && (projection.mag() < ray.mag()) ) {
ob.hit = true;
force = forward.get();
force.mult(maxforce);
if ( sign(diff,vel) == -1 ) { //CCW
force.set(force.y,-force.x,0);
}
else { //CW
force.set(-force.y,force.x,0);
}
force.mult(1-(projection.mag())/ray.mag());
force.limit(maxforce);
acc.add(force);
}
}
}
}
So to help me I was wondering if anyone knew of any complete examples of collision avoidance that follow the Steering Behaviors for Autonomous Characters way of doing things better. This Site is the example applet for the paper and is the exact example I wish I could see the code for. Sadly there is no code to come with it and I tried decompiling it but it just showed the main class so that wasn't very helpful. If someone has the code for this example or something like it, or a tutorial, I would appreciate it a lot.
Craig Reynolds cannot release the source code for the applets you're interested in. Similar source code is available in c++ at OpenSteer, which is maintained by Reynolds. Christian Schnellhammer and Thomas Feilkas worked to expand Reynolds original paper. Their paper is translated into english and contains a section on obstacle avoidance. The source code for their work is available in Java. However, I think Shiffman's code is a great starting point, and it sounds like you're pretty close to what you want already
One of my first Processing programs modified the Boids example to simulate a zombie apocalypse. Triangles chased circles that were avoiding them. Each survivor checks for other zombies in their vision, and averages the location vectors of threats in a function, PVector panic(ArrayList infected). After that, it was a matter of weighting the new vector negatively and adding it to the survivor's current vector like any other force. Something like:
void flock(ArrayList uninfected, ArrayList infected) {
PVector sep = separate(uninfected); // Separation
PVector ali = align(uninfected); // Alignment
PVector coh = cohesion(uninfected); // Cohesion
PVector pan = panic(infected); // Panic
// Arbitrarily weight these forces
sep.mult(4.0);
ali.mult(1.0);
coh.mult(2.0);
pan.mult(-3.0);
// Add the force vectors to acceleration
acc.add(sep);
acc.add(ali);
acc.add(coh);
acc.add(pan);
}
If your skier is successfully detecting the obstacles, then avoidance is the problem. Adding a stronger weight to the avoidance vector, increasing the radius the skier can 'see' to interact with objects, or even adding a method to the object that returns the location of the closest point to the skier could solve your problem. You could also add deceleration based on the distance from the skier to the nearest obstacle in front it.
Remember that even the applet you're interested in does not perfectly avoid obstacles. My solution may not be exactly what is happening in the applet, but by playing around with the forces determining you skier's direction, you can achieve a very similar (and possibly better) effect.
Checkout this link on NEHE game development site:
In this tutorial you will learn the
basics of collision detection,
collision response, and physically
based modelling effects. This tutorial
concentrates more on how collision
detection works than on the actual
code, although all of the important
code is explained.
http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=30
It is done using c++ and win32 API. Although you will find a link for Java Port using JOGL.
Also
The Source code for http://www.red3d.com/cwr/steer/ is available here http://opensteer.sourceforge.net/ though in c++. Have you checked it??

Categories

Resources