I'm trying to implement a program to solve the n-puzzle problem.
I have written a simple implementation in Java that has a state of the problem characterized by a matrix representing the tiles. I am also able to auto-generate the graph of all the states giving the starting state. On the graph, then, I can do a BFS to find the path to the goal state.
But the problem is that I run out of memory and I cannot even create the whole graph.
I tried with a 2x2 tiles and it works. Also with some 3x3 (it depends on the starting state and how many nodes are in the graph). But in general this way is not suitable.
So I tried generating the nodes at runtime, while searching. It works, but it is slow (sometimes after some minutes it still have not ended and I terminate the program).
Btw: I give as starting state only solvable configurations and I don't create duplicated states.
So, I cannot create the graph. This leads to my main problem: I have to implement the A* algorithm and I need the path cost (i.e. for each node the distance from the starting state), but I think I cannot calculate it at runtime. I need the whole graph, right? Because A* does not follow a BFS exploration of the graph, so I don't know how to estimate the distance for each node. Hence, I don't know how to perform an A* search.
Any suggestion?
EDIT
State:
private int[][] tiles;
private int pathDistance;
private int misplacedTiles;
private State parent;
public State(int[][] tiles) {
this.tiles = tiles;
pathDistance = 0;
misplacedTiles = estimateHammingDistance();
parent = null;
}
public ArrayList<State> findNext() {
ArrayList<State> next = new ArrayList<State>();
int[] coordZero = findCoordinates(0);
int[][] copy;
if(coordZero[1] + 1 < Solver.SIZE) {
copy = copyTiles();
int[] newCoord = {coordZero[0], coordZero[1] + 1};
switchValues(copy, coordZero, newCoord);
State newState = checkNewState(copy);
if(newState != null)
next.add(newState);
}
if(coordZero[1] - 1 >= 0) {
copy = copyTiles();
int[] newCoord = {coordZero[0], coordZero[1] - 1};
switchValues(copy, coordZero, newCoord);
State newState = checkNewState(copy);
if(newState != null)
next.add(newState);
}
if(coordZero[0] + 1 < Solver.SIZE) {
copy = copyTiles();
int[] newCoord = {coordZero[0] + 1, coordZero[1]};
switchValues(copy, coordZero, newCoord);
State newState = checkNewState(copy);
if(newState != null)
next.add(newState);
}
if(coordZero[0] - 1 >= 0) {
copy = copyTiles();
int[] newCoord = {coordZero[0] - 1, coordZero[1]};
switchValues(copy, coordZero, newCoord);
State newState = checkNewState(copy);
if(newState != null)
next.add(newState);
}
return next;
}
private State checkNewState(int[][] tiles) {
State newState = new State(tiles);
for(State s : Solver.states)
if(s.equals(newState))
return null;
return newState;
}
#Override
public boolean equals(Object obj) {
if(this == null || obj == null)
return false;
if (obj.getClass().equals(this.getClass())) {
for(int r = 0; r < tiles.length; r++) {
for(int c = 0; c < tiles[r].length; c++) {
if (((State)obj).getTiles()[r][c] != tiles[r][c])
return false;
}
}
return true;
}
return false;
}
Solver:
public static final HashSet<State> states = new HashSet<State>();
public static void main(String[] args) {
solve(new State(selectStartingBoard()));
}
public static State solve(State initialState) {
TreeSet<State> queue = new TreeSet<State>(new Comparator1());
queue.add(initialState);
states.add(initialState);
while(!queue.isEmpty()) {
State current = queue.pollFirst();
for(State s : current.findNext()) {
if(s.goalCheck()) {
s.setParent(current);
return s;
}
if(!states.contains(s)) {
s.setPathDistance(current.getPathDistance() + 1);
s.setParent(current);
states.add(s);
queue.add(s);
}
}
}
return null;
}
Basically here is what I do:
- Solver's solve has a SortedSet. Elements (States) are sorted according to Comparator1, which calculates f(n) = g(n) + h(n), where g(n) is the path cost and h(n) is a heuristic (the number of misplaced tiles).
- I give the starting configuration and look for all the successors.
- If a successor has not been already visited (i.e. if it is not in the global set States) I add it to the queue and to States, setting the current state as its parent and parent's path + 1 as its path cost.
- Dequeue and repeat.
I think it should work because:
- I keep all the visited states so I'm not looping.
- Also, there won't be any useless edge because I immediately store current node's successors. E.g.: if from A I can go to B and C, and from B I could also go to C, there won't be the edge B->C (since path cost is 1 for each edge and A->B is cheaper than A->B->C).
- Each time I choose to expand the path with the minimum f(n), accordin to A*.
But it does not work. Or at least, after a few minutes it still can't find a solution (and I think is a lot of time in this case).
If I try to create a tree structure before executing A*, I run out of memory building it.
EDIT 2
Here are my heuristic functions:
private int estimateManhattanDistance() {
int counter = 0;
int[] expectedCoord = new int[2];
int[] realCoord = new int[2];
for(int value = 1; value < Solver.SIZE * Solver.SIZE; value++) {
realCoord = findCoordinates(value);
expectedCoord[0] = (value - 1) / Solver.SIZE;
expectedCoord[1] = (value - 1) % Solver.SIZE;
counter += Math.abs(expectedCoord[0] - realCoord[0]) + Math.abs(expectedCoord[1] - realCoord[1]);
}
return counter;
}
private int estimateMisplacedTiles() {
int counter = 0;
int expectedTileValue = 1;
for(int i = 0; i < Solver.SIZE; i++)
for(int j = 0; j < Solver.SIZE; j++) {
if(tiles[i][j] != expectedTileValue)
if(expectedTileValue != Solver.ZERO)
counter++;
expectedTileValue++;
}
return counter;
}
If I use a simple greedy algorithm they both work (using Manhattan distance is really quick (around 500 iterations to find a solution), while with number of misplaced tiles it takes around 10k iterations). If I use A* (evaluating also the path cost) it's really slow.
Comparators are like that:
public int compare(State o1, State o2) {
if(o1.getPathDistance() + o1.getManhattanDistance() >= o2.getPathDistance() + o2.getManhattanDistance())
return 1;
else
return -1;
}
EDIT 3
There was a little error. I fixed it and now A* works. Or at least, for the 3x3 if finds the optimal solution with only 700 iterations. For the 4x4 it's still too slow. I'll try with IDA*, but one question: how long could it take with A* to find the solution? Minutes? Hours? I left it for 10 minutes and it didn't end.
There is no need to generate all state space nodes for solving a problem using BFS, A* or any tree search, you just add states you can explore from current state to the fringe and that's why there is a successor function.
If BFS consumes much memory it is normal. But I don't know exactly fro what n it would make problem. Use DFS instead.
For A* you know how many moves you made to come to current state and you can estimate moves need to solve problem, simply by relaxing problem. As an example you can think that any two tiles can replace and then count moves needed to solve the problem. You heuristic just needs to be admissible ie. your estimate be less then actual moves needed to solve the problem.
add a path cost to your state class and every time you go from a parent state P to another state like C do this : c.cost = P.cost + 1 this will compute the path cost for every node automatically
this is also a very good and simple implementation in C# for 8-puzzle solver with A* take a look at it you will learn many things :
http://geekbrothers.org/index.php/categories/computer/12-solve-8-puzzle-with-a
Related
I'm a first-year computer science student and I am currently dabbling in some algorithmic competitions. The code below that I made has a flaw that I'm not sure how to fix
Here is the problem statement:
http://www.usaco.org/index.php?page=viewproblem2&cpid=811
In the statement, I missed where it said that Farmer John could only switch boots on tiles that both boots can stand on. I tried adding constraints in different places but none seemed to address the problem fully. I don't really see a way to do it without butchering the code
Basically, the problem is that John keeps switching boots on tiles where the new boots can't stand on, and I can't seem to fix it
Here is my code (sorry for the one letter variables):
import java.io.*;
import java.util.*;
public class snowboots {
static int n,k;
static int[] field,a,b; //a,b --> strength, distance
static int pos;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("snowboots.in"));
PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter("snowboots.out")));
StringTokenizer st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
k = Integer.parseInt(st.nextToken());
st = new StringTokenizer(br.readLine());
field = new int[n];
a = new int[k];
b = new int[k];
for (int i = 0; i < n; i++)
field[i] = Integer.parseInt(st.nextToken());
for (int i = 0; i < k; i++) {
st = new StringTokenizer(br.readLine());
a[i] = Integer.parseInt(st.nextToken());
b[i] = Integer.parseInt(st.nextToken());
}
pw.println(solve());
pw.close();
}
static int solve() {
pos = 0;
int i = 0; //which boot are we on?
while(pos < n-1) {
while(move(i)); //move with boot i as far as possible
i++; //use the next boot
}
i--;
return i;
}
static boolean move(int c) {
for (int i = pos+b[c]; i > pos; i--) {
if (i < n && field[i] <= a[c]) { //snow has to be less than boot strength
pos = i;
return true;
}
}
return false;
}
}
I tried adding a constraint in the "move" method, and one when updating I, but they both are too strict and activate at unwanted times
Is it salvageable?
Yes, it's possible to salvage your solution, by adding an extra for-loop.
What you need to do is, if you find that your previous pair of boots can get you all the way to a tile that's too deep in snow for your next pair, then you need to try "backtracking" to the latest tile that's not too deep. This ends up giving a solution in worst-case O(N·B) time and O(1) extra space.
It may not be obvious why it's OK to backtrack to that tile — after all, just because you can reach a given tile, that doesn't necessarily mean that you were able to reach all the tiles before it — so let me explain a bit why it is OK.
Let maxReachableTileNum be the number (between 1 and N) of the last tile that you were able to reach with your previous boots, and let lastTileNumThatsNotTooDeep be the number (between 1 and N) of the last tile on or before maxReachableTileNum that's not too deeply snow-covered for your next pair. (We know that there is such a tile, because tile #1 has no snow at all, so if nothing else we know that we can backtrack to the very beginning.) Now, since we were able to get to maxReachableTileNum, then some previous boot must have either stepped on lastTileNumThatsNotTooDeep (in which case, no problem, it's reachable) or skipped over it to some later tile (on or before maxReachableTileNum). But that later tile must be deeper than lastTileNumThatsNotTooDeep (because that later tile's depth is greater than scurrentBootNum, which is at least at great as the depth of lastTileNumThatsNotTooDeep), which means that the boot that skipped over lastTileNumThatsNotTooDeep certainly could have stepped on lastTileNumThatsNotTooDeep instead: it would have meant taking a shorter step (OK) onto a less-deeply-covered tile (OK) than what it actually did. So, either way, we know that lastTileNumThatsNotTooDeep was reachable. So it's safe for us to try backtracking to lastTileNumThatsNotTooDeep. (Note: the below code uses the name reachableTileNum instead of lastTileNumThatsNotTooDeep, because it continues to use the reachableTileNum variable for searching forward to find reachable tiles.)
However, we still have to hold onto the previous maxReachableTileNum: backtracking might turn out not to be helpful (because it may not let us make any further forward progress than we already have), in which case we'll just discard these boots, and move on to the next pair, with maxReachableTileNum at its previous value.
So, overall, we have this:
public static int solve(
final int[] tileSnowDepths, // tileSnowDepths[0] is f_1
final int[] bootAllowedDepths, // bootAllowedDepths[0] is s_1
final int[] bootAllowedTilesPerStep // bootAllowedTilesPerStep[0] is d_1
) {
final int numTiles = tileSnowDepths.length;
final int numBoots = bootAllowedDepths.length;
assert numBoots == bootAllowedTilesPerStep.length;
int maxReachableTileNum = 1; // can reach tile #1 even without boots
for (int bootNum = 1; bootNum <= numBoots; ++bootNum) {
final int allowedDepth = bootAllowedDepths[bootNum-1];
final int allowedTilesPerStep = bootAllowedTilesPerStep[bootNum-1];
// Find the starting-point for this boot -- ideally the last tile
// reachable so far, but may need to "backtrack" if that tile is too
// deep; see explanation above of why it's safe to assume that we
// can backtrack to the latest not-too-deep tile:
int reachableTileNum = maxReachableTileNum;
while (tileSnowDepths[reachableTileNum-1] > allowedDepth) {
--reachableTileNum;
}
// Now see how far we can go, updating both maxReachableTileNum and
// reachableTileNum when we successfully reach new tiles:
for (int tileNumToTry = maxReachableTileNum + 1;
tileNumToTry <= numTiles
&& tileNumToTry <= reachableTileNum + allowedTilesPerStep;
++tileNumToTry
) {
if (tileSnowDepths[tileNumToTry-1] <= allowedDepth) {
maxReachableTileNum = reachableTileNum = tileNumToTry;
}
}
// If we've made it to the last tile, then yay, we're done:
if (maxReachableTileNum == numTiles) {
return bootNum - 1; // had to discard this many boots to get here
}
}
throw new IllegalArgumentException("Couldn't reach last tile with any boot");
}
(I tested this on USACO's example data, and it returned 2, as expected.)
This can potentially be optimized further, e.g. with logic to skip pairs of boots that clearly aren't helpful (because they're neither stronger nor more agile than the previous successful pair), or with an extra data structure to keep track of the positions of latest minima (to optimize the backtracking process), or with logic to avoid backtracking further than is conceivably useful; but given that N·B ≤ 2502 = 62,500, I don't think any such optimizations are warranted.
Edited to add (2019-02-23): I've thought about this further, and it occurs to me that it's actually possible to write a solution in worst-case O(N + B log N) time (which is asymptotically better than O(N·B)) and O(N) extra space. But it's much more complicated; it involves three extra data-structures (one to keep track of the positions of latest minima, to allow backtracking in O(log N) time; one to keep track of the positions of future minima, to allow checking in O(log N) time if the backtracking is actually helpful (and if so to move forward to the relevant minimum); and one to maintain the necessary forward-looking information in order to let the second one be maintained in amortized O(1) time). It's also complicated to explain why that solution is guaranteed to be within O(N + B log N) time (because it involves a lot of amortized analysis, and making a minor change that might seem like an optimization — e.g., replacing a linear search with a binary search — can break the analysis and actually increase the worst-case time complexity. Since N and B are both known to be at most 250, I don't think all the complication is worth it.
You can solve this problem by Dynamic Programming. You can see the concept in this link (Just read the Computer programming part).
It has following two steps.
First solve the problem recursively.
Memoize the states.
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mx 100005
#define mod 1000000007
int n, b;
int f[333], s[333], d[333];
int dp[251][251];
int rec(int snowPos, int bootPos)
{
if(snowPos == n-1){
return 0;
int &ret = dp[snowPos][bootPos];
if(ret != -1) return ret;
ret = 1000000007;
for(int i = bootPos+1; i<b; i++)
{
if(s[i] >= f[snowPos]){
ret = min(ret, i - bootPos + rec(snowPos, i));
}
}
for(int i = 1; i<=d[bootPos] && snowPos+i < n; i++){
if(f[snowPos + i] <= s[bootPos]){
ret = min(ret, rec(snowPos+i, bootPos));
}
}
return ret;
}
int main()
{
freopen("snowboots.in", "r", stdin);
freopen("snowboots.out", "w", stdout);
scanf("%d %d", &n, &b);
for(int i = 0; i<n; i++)
scanf("%d", &f[i]);
for(int i = 0; i<b; i++){
scanf("%d %d", &s[i], &d[i]);
}
memset(dp, -1, sizeof dp);
printf("%d\n", rec(0, 0));
return 0;
}
This is my solution to this problem (in C++).
This is just a recursion. As problem says,
you can change boot, Or
you can do a jump by current boot.
Memoization part is done by the 2-Dimensional array dp[][].
One way which to solve it using BFS. You may refer below code for details. Hope this helps.
import java.util.*;
import java.io.*;
public class SnowBoots {
public static int n;
public static int[] deep;
public static int nBoots;
public static Boot[] boots;
public static void main(String[] args) throws Exception {
// Read the grid.
Scanner stdin = new Scanner(new File("snowboots.in"));
// Read in all of the input.
n = stdin.nextInt();
nBoots = stdin.nextInt();
deep = new int[n];
for (int i = 0; i < n; ++i) {
deep[i] = stdin.nextInt();
}
boots = new Boot[nBoots];
for (int i = 0; i < nBoots; ++i) {
int d = stdin.nextInt();
int s = stdin.nextInt();
boots[i] = new boot(d, s);
}
PrintWriter out = new PrintWriter(new FileWriter("snowboots.out"));
out.println(bfs());
out.close();
stdin.close();
}
// Breadth First Search Algorithm [https://en.wikipedia.org/wiki/Breadth-first_search]
public static int bfs() {
// These are all valid states.
boolean[][] used = new boolean[n][nBoots];
Arrays.fill(used[0], true);
// Put each of these states into the queue.
LinkedList<Integer> q = new LinkedList<Integer>();
for (int i = 0; i < nBoots; ++i) {
q.offer(i);
}
// Usual bfs.
while (q.size() > 0) {
int cur = q.poll();
int step = cur / nBoots;
int bNum = cur % nBoots;
// Try stepping with this boot...
for (int i = 1; ((step + i) < n) && (i <= boots[bNum].maxStep); ++i) {
if ((deep[step+i] <= boots[bNum].depth) && !used[step+i][bNum]) {
q.offer(nBoots * (step + i) + bNum);
used[step + i][bNum] = true;
}
}
// Try switching to another boot.
for (int i = bNum + 1; i < nBoots; ++i) {
if ((boots[i].depth >= deep[step]) && !used[step][i]) {
q.offer(nBoots * step + i);
used[step][i] = true;
}
}
}
// Find the earliest boot that got us here.
for (int i = 0; i < nBoots; ++i) {
if (used[n - 1][i]) {
return i;
}
}
// Should never get here.
return -1;
}
}
class Boot {
public int depth;
public int maxStep;
public Boot(int depth, int maxStep) {
this.depth = depth;
this.maxStep = maxStep;
}
}
I have a question regarding Genetic Programming. I am going to work on a genetic algorithm for a game called Battleships.
My question is: How would I decide upon a "decision" model for the AI to evolve? And how does that work?
I have read multiple papers and multiple answers that just speak about using different models, but could not find something specific, which, unfortunately, I apparently need to wrap my head around the problem.
I want it to evolve over multiple iterations and "learn" what works best, but not sure how to save these "decisions" (I know to a file, but "encoded" how?)
in a good way, so it will learn to take a stance to previous actions and base off info from the current board state.
I have been contemplating a "Tree structure" for the AI to base decisions on, but I don't actually know how to get started.
If someone could either point me in the right direction (a link? Some pseudo-code? Something like that), that'd be very much appreciated, I tried to google as much as possible, watch multiple youtube videos about the subject, but I think I just need that little nudge in the right direction.
I may also just not know what exactly to search for, and this is why I come up blank with results on what and how I implement this.
ANSWER PART I: The basis for a genetic algorithm is a having a group of actors, some of which reproduce. The fittest are chosen for reproduction and the offspring are copies of the parents that are slightly mutated. It's a pretty simple concept, but to program it you have to have actions that can be randomly chosen and dynamically modified. For the battleship simulation I created a class called a Shooter because it 'shoots' at a position. The assumption here is that the first position has been hit, and the shooter is now trying to sink the battleship.
public class Shooter implements Comparable<Shooter> {
private static final int NUM_SHOTS = 100;
private List<Position> shots;
private int score;
// Make a new set of random shots.
public Shooter newShots() {
shots = new ArrayList<Position>(NUM_SHOTS);
for (int i = 0; i < NUM_SHOTS; ++i) {
shots.add(newShot());
}
return this;
}
// Test this shooter against a ship
public void testShooter(Ship ship) {
score = shots.size();
int hits = 0;
for (Position shot : shots) {
if (ship.madeHit(shot)) {
if (++hits >= ship.getSize())
return;
} else {
score = score - 1;
}
}
}
// get the score of the testShotr operation
public int getScore() {
return score;
}
// compare this shooter to other shooters.
#Override
public int compareTo(Shooter o) {
return score - o.score;
}
// getter
public List<Position> getShots() {
return shots;
}
// reproduce this shooter
public Shooter reproduce() {
Shooter offspring = new Shooter();
offspring.mutate(shots);
return offspring;
}
// mutate this shooter's offspring
private void mutate(List<Position> pShots) {
// copy parent's shots (okay for shallow)
shots = new ArrayList<Position>(pShots);
// 10% new mutations, in random locations
for (int i = 0; i < NUM_SHOTS / 10; i++) {
int loc = (int) (Math.random() * 100);
shots.set(loc, newShot());
}
}
// make a new random move
private Position newShot() {
return new Position(((int) (Math.random() * 6)) - 3, ((int) (Math.random() * 6)) - 3);
}
}
The idea here is that a Shooter has up to 100 shots, randomly chosen between +-3 in the X and +- 3 in the Y. Yea, 100 shots is overkill, but hey, whatever. Pass a Ship to this Shooter.testShooter and it will score itself, 100 being the best score, 0 being the worst.
This Shooter actor has reproduce and mutate methods that will return an offspring that has 10% of its shots randomly mutated. The general idea is that the best Shooters have 'learned' to shoot their shots in a cross pattern ('+') as quickly as possible, since a ship is oriented in one of four ways (North, South, East, West).
The program that runs the simulation, ShooterSimulation, is pretty simple:
public class ShooterSimulation {
private int NUM_GENERATIONS = 1000;
private int NUM_SHOOTERS = 20;
private int NUM_SHOOTERS_NEXT_GENERATION = NUM_SHOOTERS / 10;
List<Shooter> shooters = new ArrayList<Shooter>(NUM_SHOOTERS);
Ship ship;
public static void main(String... args) {
new ShooterSimulation().run();
}
// do the work
private void run() {
firstGeneration();
ship = new Ship();
for (int gen = 0; gen < NUM_GENERATIONS; ++gen) {
ship.newOrientation();
testShooters();
Collections.sort(shooters);
printAverageScore(gen, shooters);
nextGeneration();
}
}
// make the first generation
private void firstGeneration() {
for (int i = 0; i < NUM_SHOOTERS; ++i) {
shooters.add(new Shooter().newShots());
}
}
// test all the shooters
private void testShooters() {
for (int mIdx = 0; mIdx < NUM_SHOOTERS; ++mIdx) {
shooters.get(mIdx).testShooter(ship);
}
}
// print the average score of all the shooters
private void printAverageScore(int gen, List<Shooter> shooters) {
int total = 0;
for (int i = 0, j = shooters.size(); i < j; ++i) {
total = total + shooters.get(i).getScore();
}
System.out.println(gen + " " + total / shooters.size());
}
// throw away the a tenth of old generation
// replace with offspring of the best fit
private void nextGeneration() {
for (int l = 0; l < NUM_SHOOTERS_NEXT_GENERATION; ++l) {
shooters.set(l, shooters.get(NUM_SHOOTERS - l - 1).reproduce());
}
}
}
The code reads as pseudo-code from the run method: make a firstGeneration then iterate for a number of generations. For each generation, set a newOrientation for the ship, then do testShooters, and sort the results of the test with Collections.sort. printAverageScore of the test, then build the nextGeneration. With the list of average scores you can, cough cough, do an 'analysis'.
A graph of the results looks like this:
As you can see it starts out with pretty low average scores, but learns pretty quickly. However, the orientation of the ship keeps changing, causing some noise in addition to the random component. Every now and again a mutation messes up the group a bit, but less and less as the group improves overall.
Challenges, and the reason for many papers to be sure, is to make more things mutable, especially in a constructive way. For example, the number of shots could be mutable. Or, replacing the list of shots with a tree that branches depending on whether the last shot was a hit or miss might improve things, but it's difficult to say. That's where the 'decision' logic considerations come in. Is it better to have a list of random shots or a tree that decides which branch to take depending on the prior shot? Higher level challenges include predicting what changes will make the group learn faster and be less susceptible to bad mutations.
Finally, consider that there could be multiple groups, one group a battleship hunter and one group a submarine hunter for example. Each group, though made of the same code, could 'evolve' different internal 'genetics' that allow them to specialize for their task.
Anyway, as always, start somewhere simple and learn as you go until you get good enough to go back to reading the papers.
PS> Need this too:
public class Position {
int x;
int y;
Position(int x, int y ) {this.x=x; this.y=y;}
#Override
public boolean equals(Object m) {
return (((Position)m).x==x && ((Position)m).y==y);
}
}
UDATE: Added Ship class, fixed a few bugs:
public class Ship {
List<Position> positions;
// test if a hit was made
public boolean madeHit(Position shot) {
for (Position p: positions) {
if ( p.equals(shot)) return true;
}
return false;
}
// make a new orientation
public int newOrientation() {
positions = new ArrayList<Position>(3);
// make a random ship direction.
int shipInX=0, oShipInX=0 , shipInY=0, oShipInY=0;
int orient = (int) (Math.random() * 4);
if( orient == 0 ) {
oShipInX = 1;
shipInX = (int)(Math.random()*3)-3;
}
else if ( orient == 1 ) {
oShipInX = -1;
shipInX = (int)(Math.random()*3);
}
else if ( orient == 2 ) {
oShipInY = 1;
shipInY = (int)(Math.random()*3)-3;
}
else if ( orient == 3 ) {
oShipInY = -1;
shipInY = (int)(Math.random()*3);
}
// make the positions of the ship
for (int i = 0; i < 3; ++i) {
positions.add(new Position(shipInX, shipInY));
if (orient == 2 || orient == 3)
shipInY = shipInY + oShipInY;
else
shipInX = shipInX + oShipInX;
}
return orient;
}
public int getSize() {
return positions.size();
}
}
I would suggest you another approach. This approach is based on the likelihood where a ship can be. I will show you an example on a smaller version of the game (the same idea is for all other versions). In my example it is 3x3 area and has only one 1x2 ship.
Now you take an empty area, and put the ship in all possible positions (storing the number of times the part of the ship was in the element of the matrix). If you will do this for a ship 1x2, you will get the following
1 2 1
1 2 1
1 2 1
Ship can be in another direction 2x1 which will give you the following matrix:
1 1 1
2 2 2
1 1 1
Summing up you will get the matrix of probabilities:
2 3 2
3 4 3
2 3 2
This means that the most probable location is the middle one (where we have 4). Here is where you should shoot.
Now lets assume you hit the part of the ship. If you will recalculate the likelihood matrix, you will get:
0 1 0
1 W 1
0 1 0
which tells you 4 different possible positions for a next shoot.
If for example you would miss on the previous step, you will get the following matrix:
2 2 2
2 M 2
2 2 2
This is the basic idea. The way how you try to reposition the ships is based on the rules how the ships can be located and also what information you got after each move. It can be missed/got or missed/wounded/killed.
ANSWER PART III: As you can see, the Genetic Algorithm is generally not the hard part. Again, it's a simple piece of code that is really meant to exercise another piece of code, the actor. Here, the actor is implemented in a Shooter class. These actor's are often modelled in the fashion of Turning Machines, in the sense that the actor has a defined set of outputs for a set of inputs. The GA helps you to determine the optimal configuration of the state table. In the prior answers to this question, the Shooter implemented a probability matrix like what was described by #SalvadorDali in his answer.
Testing the prior Shooter thoroughly, we find that the best it can do is something like:
BEST Ave=5, Min=3, Max=9
Best=Shooter:5:[(1,0), (0,0), (2,0), (-1,0), (-2,0), (0,2), (0,1), (0,-1), (0,-2), (0,1)]
This shows it takes 5 shots average, 3 at a minimum, and 9 at a maximum to sink a 3X3 battleship. The locations of the 9 shots are shown a X/Y coordinate pairs. The question "Can this be done better?" depends on human ingenuity. A Genetic Algorithm can't write new actors for us. I wondered if a decision tree could do better than a probability matrix, so I implemented one to try it out:
public class Branch {
private static final int MAX_DEPTH = 10;
private static final int MUTATE_PERCENT = 20;
private Branch hit;
private Branch miss;
private Position shot;
public Branch() {
shot = new Position(
(int)((Math.random()*6.0)-3),
(int)((Math.random()*6.0)-3)
);
}
public Branch(Position shot, Branch hit, Branch miss) {
this.shot = new Position(shot.x, shot.y);
this.hit = null; this.miss = null;
if ( hit != null ) this.hit = hit.clone();
if ( miss != null ) this.miss = miss.clone();
}
public Branch clone() {
return new Branch(shot, hit, miss);
}
public void buildTree(Counter c) {
if ( c.incI1() > MAX_DEPTH ) {
hit = null;
miss = null;
c.decI1();
return;
} else {
hit = new Branch();
hit.buildTree(c);
miss = new Branch();
miss.buildTree(c);
}
c.decI1();
}
public void shoot(Ship ship, Counter c) {
c.incI1();
if ( ship.madeHit(shot)) {
if ( c.incI2() == ship.getSize() ) return;
if ( hit != null ) hit.shoot(ship, c);
}
else {
if ( miss != null ) miss.shoot(ship, c);
}
}
public void mutate() {
if ( (int)(Math.random() * 100.0) < MUTATE_PERCENT) {
shot.x = (int)((Math.random()*6.0)-3);
shot.y = (int)((Math.random()*6.0)-3);
}
if ( hit != null ) hit.mutate();
if ( miss != null ) miss.mutate();
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(shot.toString());
if ( hit != null ) sb.append("h:"+hit.toString());
if ( miss != null ) sb.append("m:"+miss.toString());
return sb.toString();
}
}
The Branch class is a node in a decision tree (ok, maybe poorly named). At every shot, the next branch chosen depends on whether the shot was awarded a hit or not.
The shooter is modified somewhat to use the new decisionTree.
public class Shooter implements Comparable<Shooter> {
private Branch decisionTree;
private int aveScore;
// Make a new random decision tree.
public Shooter newShots() {
decisionTree = new Branch();
Counter c = new Counter();
decisionTree.buildTree(c);
return this;
}
// Test this shooter against a ship
public int testShooter(Ship ship) {
Counter c = new Counter();
decisionTree.shoot(ship, c);
return c.i1;
}
// compare this shooter to other shooters, reverse order
#Override
public int compareTo(Shooter o) {
return o.aveScore - aveScore;
}
// mutate this shooter's offspring
public void mutate(Branch pDecisionTree) {
decisionTree = pDecisionTree.clone();
decisionTree.mutate();
}
// min, max, setters, getters
public int getAveScore() {
return aveScore;
}
public void setAveScore(int aveScore) {
this.aveScore = aveScore;
}
public Branch getDecisionTree() {
return decisionTree;
}
#Override
public String toString() {
StringBuilder ret = new StringBuilder("Shooter:"+aveScore+": [");
ret.append(decisionTree.toString());
return ret.append(']').toString();
}
}
The attentive reader will notice that while the methods themselves have changed, which methods a Shooter needs to implement is not different from the prior Shooters. This means the main GA simulation has not changed except for one line related to mutations, and that probably could be worked on:
Shooter child = shooters.get(l);
child.mutate( shooters.get(NUM_SHOOTERS - l - 1).getDecisionTree());
A graph of a typical simulation run now looks like this:
As you can see, the final best average score evolved using a Decision Tree is one shot less than the best average score evolved for a Probability Matrix. Also notice that this group of Shooters has taken around 800 generations to train to their optimum, about twice as long than the simpler probability matrix Shooters. The best decision tree Shooter gives this result:
BEST Ave=4, Min=3, Max=6
Best=Shooter:4: [(0,-1)h:(0,1)h:(0,0) ... ]
Here, not only does the average take one shot less, but the maximum number of shots is 1/3 lower than a probability matrix Shooter.
At this point it takes some really smart guys to determine whether this actor has achieved the theoretical optimum for the problem domain, i.e., is this the best you can do trying to sink a 3X3 ship? Consider that the answer to that question would become more complex in the real battleship game, which has several different size ships. How would you build an actor that incorporates the knowledge of which of the boats have already been sunk into actions that are randomly chosen and dynamically modified? Here is where understanding Turing Machines, also known as CPUs, becomes important.
PS> You will need this class also:
public class Counter {
int i1;
int i2;
public Counter() {i1=0;i2=0;}
public int incI1() { return ++i1; }
public int incI2() { return ++i2; }
public int decI1() { return --i1; }
public int decI2() { return --i2; }
}
ANSWER PART II: A Genetic Algorithm is not a end unto itself, it is a means to accomplish an end. In the case of this example of battleship, the end is to make the best Shooter. I added the a line to the prior version of the program to output the best shooter's shot pattern, and noticed something wrong:
Best shooter = Shooter:100:[(0,0), (0,0), (0,0), (0,-1), (0,-3), (0,-3), (0,-3), (0,0), (-2,-1) ...]
The first three shots in this pattern are at coordinates (0,0), which in this application are guaranteed hits, even though they are hitting the same spot. Hitting the same spot more than once is against the rules in battleship, so this "best" shooter is the best because it has learned to cheat!
So, clearly the program needs to be improved. To do that, I changed the Ship class to return false if a position has already been hit.
public class Ship {
// private class to keep track of hits
private class Hit extends Position {
boolean hit = false;
Hit(int x, int y) {super(x, y);}
}
List<Hit> positions;
// need to reset the hits for each shooter test.
public void resetHits() {
for (Hit p: positions) {
p.hit = false;
}
}
// test if a hit was made, false if shot in spot already hit
public boolean madeHit(Position shot) {
for (Hit p: positions) {
if ( p.equals(shot)) {
if ( p.hit == false) {
p.hit = true;
return true;
}
return false;
}
}
return false;
}
// make a new orientation
public int newOrientation() {
positions = new ArrayList<Hit>(3);
int shipInX=0, oShipInX=0 , shipInY=0, oShipInY=0;
// make a random ship orientation.
int orient = (int) (Math.random() * 4.0);
if( orient == 0 ) {
oShipInX = 1;
shipInX = 0-(int)(Math.random()*3.0);
}
else if ( orient == 1 ) {
oShipInX = -1;
shipInX = (int)(Math.random()*3.0);
}
else if ( orient == 2 ) {
oShipInY = 1;
shipInY = 0-(int)(Math.random()*3.0);
}
else if ( orient == 3 ) {
oShipInY = -1;
shipInY = (int)(Math.random()*3.0);
}
// make the positions of the ship
for (int i = 0; i < 3; ++i) {
positions.add(new Hit(shipInX, shipInY));
if (orient == 2 || orient == 3)
shipInY = shipInY + oShipInY;
else
shipInX = shipInX + oShipInX;
}
return orient;
}
public int getSize() {
return positions.size();
}
}
After I did this, my shooters stopped "cheating", but that got me to thinking about the scoring in general. What the prior version of the application was doing was scoring based on how many shots missed, and hence a shooter could get a perfect score if none of the shots missed. However, that is unrealistic, what I really want is shooters that shoot the least shots. I changed the shooter to keep track of the average of shots taken:
public class Shooter implements Comparable<Shooter> {
private static final int NUM_SHOTS = 40;
private List<Position> shots;
private int aveScore;
// Make a new set of random shots.
public Shooter newShots() {
shots = new ArrayList<Position>(NUM_SHOTS);
for (int i = 0; i < NUM_SHOTS; ++i) {
shots.add(newShot());
}
return this;
}
// Test this shooter against a ship
public int testShooter(Ship ship) {
int score = 1;
int hits = 0;
for (Position shot : shots) {
if (ship.madeHit(shot)) {
if (++hits >= ship.getSize())
return score;
}
score++;
}
return score-1;
}
// compare this shooter to other shooters, reverse order
#Override
public int compareTo(Shooter o) {
return o.aveScore - aveScore;
}
... the rest is the same, or getters and setters.
}
I also realized that I had to test each shooter more than once in order to be able to get an average number of shots fired against battleships. For that, I subjected each shooter individually to a test multiple times.
// test all the shooters
private void testShooters() {
for (int i = 0, j = shooters.size(); i<j; ++i) {
Shooter current = shooters.get(i);
int totalScores = 0;
for (int play=0; play<NUM_PLAYS; ++play) {
ship.newOrientation();
ship.resetHits();
totalScores = totalScores + current.testShooter(ship);
}
current.setAveScore(totalScores/NUM_PLAYS);
}
}
Now, when I run the simulation, I get the average of the averages an output. The graph generally looks something like this:
Again, the shooters learn pretty quickly, but it takes a while for random changes to bring the averages down. Now my best Shooter makes a little more sense:
Best=Shooter:6:[(1,0), (0,0), (0,-1), (2,0), (-2,0), (0,1), (-1,0), (0,-2), ...
So, a Genetic Algorithm is helping me to set the configuration of my Shooter, but as another answer here pointed out, good results can be achieved just by thinking about it. Consider that if I have a neural network with 10 possible settings with 100 possible values in each setting, that's 10^100 possible settings and the theory for how those settings should be set may a little more difficult than battleship shooter theory. In this case, a Genetic Algorithm can help determine optimal settings and test current theory.
I work on a genetic algorithm for a robotic assembly line balancing problem (assigning assembly operations and robots to stations to minimize the cycle time for a given number of stations). The solution is represented by an ArrayList (configuration) which holds all the operations in the sequence assigned to different stations. Furthermore, I have two more ArrayLists (robotAssignment, operationPartition) which indicate where a new station starts and which robot is assigned to a station. For example, a solution candidate looks like this (configuration, robotAssignment, operationPartition from top to bottom):
Initial cycle time: 50.0
|2|7|3|9|1|5|4|6|8|10|
|2|1|3|2|
|0|2|5|7|
From this solution representation we know that operations 3, 9, and 1 are assigned to the second sation and robot 1 is used.
I need to keep track of the station an operation is assigned to. I tried a lot to store this in the Object Operation itself but I always ended up in problems and therefore I want to write a method that gives me the stations index of an operation.
Here is what I have coded so far:
// Get the station of an operation
public int getStation(Operation operation) {
int stationIndex = 0;
int position = configuration.indexOf(operation);
for (int i = 0; i < GA_RALBP.numberOfStations ; i++ ) {
if (i < GA_RALBP.numberOfStations - 1 && operationPartition.get(i) != null) {
if (isBetween(position, (int) operationPartition.get(i), (int) operationPartition.get(i + 1))) {
return stationIndex + 1;
} else {
stationIndex++;
}
}
else if (i >= GA_RALBP.numberOfStations - 1 && operationPartition.get(i) != null) {
if (isBetween(position, (int) operationPartition.get(i), configurationSize())) {
return stationIndex + 1;
}
}
}
return -1;
}
// Check if value x is between values left and right including left
public static boolean isBetween(int x, int left, int right) {
if (left <= x && x < right ) {
return true;
}
else {
return false;
}
}
However, this does not seem to be (a) very elegant and (b) if I have to do this for a large number of operations the runtime could become a problem. Has anoyone an idea how to solve this more efficiently?
Why not make the partitioning explicit (replaces your operationPartition) - something like:
Map<Integer, Integer> operationToStationMapping = new HashMap<>();
operationToStationMapping.put(2,0);
operationToStationMapping.put(7,0);
operationToStationMapping.put(3,2);
operationToStationMapping.put(9,2);
operationToStationMapping.put(1,2);
operationToStationMapping.put(5,5);
operationToStationMapping.put(6,7);
operationToStationMapping.put(8,-1);
operationToStationMapping.put(10,-1);
Then getStation() becomes:
getStation(int operation) {return operationToStationMapping.get(operation);}
This is not homework, I don't have money for school so I am teaching myself whilst working shifts at a tollbooth on the highway (long nights with few customers)
I was trying to implement a simple "mergesort" by thinking first, stretching my brain a little if you like for some actual learning, and then looking at the solution on the manual I am using: "2008-08-21 | The Algorithm Design Manual | Springer | by Steven S. Skiena | ISBN-1848000693".
I came up with a solution which implements the "merge" step using an array as a buffer, I am pasting it below. The author uses queues so I wonder:
Should queues be used instead?
What are the advantages of one method Vs the other? (obviously his method will be better as he is a top algorist and I am a beginner, but I can't quite pinpoint the strengths of it, help me please)
What are the tradeoffs/assumptions that governed his choice?
Here is my code (I am including my implementation of the splitting function as well for the sake of completeness but I think we are only reviewing the merge step here; I do not believe this is a Code Review post by the way as my questions are specific to just one method and about its performance in comparison to another):
package exercises;
public class MergeSort {
private static void merge(int[] values, int leftStart, int midPoint,
int rightEnd) {
int intervalSize = rightEnd - leftStart;
int[] mergeSpace = new int[intervalSize];
int nowMerging = 0;
int pointLeft = leftStart;
int pointRight = midPoint;
do {
if (values[pointLeft] <= values[pointRight]) {
mergeSpace[nowMerging] = values[pointLeft];
pointLeft++;
} else {
mergeSpace[nowMerging] = values[pointRight];
pointRight++;
}
nowMerging++;
} while (pointLeft < midPoint && pointRight < rightEnd);
int fillFromPoint = pointLeft < midPoint ? pointLeft : pointRight;
System.arraycopy(values, fillFromPoint, mergeSpace, nowMerging,
intervalSize - nowMerging);
System.arraycopy(mergeSpace, 0, values, leftStart, intervalSize);
}
public static void mergeSort(int[] values) {
mergeSort(values, 0, values.length);
}
private static void mergeSort(int[] values, int start, int end) {
int intervalSize = end - start;
if (intervalSize < 2) {
return;
}
boolean isIntervalSizeEven = intervalSize % 2 == 0;
int splittingAdjustment = isIntervalSizeEven ? 0 : 1;
int halfSize = intervalSize / 2;
int leftStart = start;
int rightEnd = end;
int midPoint = start + halfSize + splittingAdjustment;
mergeSort(values, leftStart, midPoint);
mergeSort(values, midPoint, rightEnd);
merge(values, leftStart, midPoint, rightEnd);
}
}
Here is the reference solution from the textbook: (it's in C so I am adding the tag)
merge(item_type s[], int low, int middle, int high)
{
int i; /* counter */
queue buffer1, buffer2; /* buffers to hold elements for merging */
init_queue(&buffer1);
init_queue(&buffer2);
for (i=low; i<=middle; i++) enqueue(&buffer1,s[i]);
for (i=middle+1; i<=high; i++) enqueue(&buffer2,s[i]);
i = low;
while (!(empty_queue(&buffer1) || empty_queue(&buffer2))) {
if (headq(&buffer1) <= headq(&buffer2))
s[i++] = dequeue(&buffer1);
else
s[i++] = dequeue(&buffer2);
}
while (!empty_queue(&buffer1)) s[i++] = dequeue(&buffer1);
while (!empty_queue(&buffer2)) s[i++] = dequeue(&buffer2);
}
Abstractly, a queue is just some object that supports the enqueue, dequeue, peek, and is-empty operations. It can be implemented in many different ways (using a circular buffer, using linked lists, etc.)
Logically speaking, the merge algorithm is easiest to describe in terms of queues. You begin with two queues holding the values to merge together, then repeatedly apply peek, is-empty, and dequeue operations on those queues to reconstruct a single sorted sequence.
In your implementation using arrays, you are effectively doing the same thing as if you were using queues. You have just chosen to implement those queues using arrays. There isn't necessarily "better" or "worse" than using queues. Using queues makes the high-level operation of the merge algorithm clearer, but might introduce some inefficiency (though it's hard to say for certain without benchmarking). Using arrays might be slightly more efficient (again, you should test this!), but might obscure the high-level operation of the algorithm. From Skienna's point of view, using queues might be better because it makes the high-level details of the algorithm clear. From your point of view, arrays might be better because of the performance concerns.
Hope this helps!
You're worrying about minor constant factors which are largely down to the quality of your compiler. Given that you seem to be worried about that, arrays are your friend. Below is my C# implementation for integer merge-sort which, I think, is close to as tight as you can get. [EDIT: fixed a buglet.]
If you want to do better in practice, you need something like natural merge-sort, where, instead of merging up in powers of two, you simply merge adjacent non-decreasing sequences of the input. This is certainly no worse than powers-of-two, but is definitely faster when the input data contains some sorted sequences (i.e., anything other than a purely descending input sequence). That's left as an exercise for the student.
int[] MSort(int[] src) {
var n = src.Length;
var from = (int[]) src.Clone();
var to = new int[n];
for (var span = 1; span < n; span += span) {
var i = 0;
for (var j = 0; j < n; j += span + span) {
var l = j;
var lend = Math.Min(l + span, n);
var r = lend;
var rend = Math.Min(r + span, n);
while (l < lend && r < rend) to[i++] = (from[l] <= from[r] ? from[l++] : from[r++]);
while (l < lend) to[i++] = from[l++];
while (r < rend) to[i++] = from[r++];
}
var tmp = from; from = to; to = tmp;
}
return from;
}
Given the adjacency matrix of a graph, I need to obtain the chromatic number (minimum number of colours needed to paint every node of a graph so that adjacent nodes get different colours).
Preferably it should be a java algorithm, and I don't care about performance.
Thanks.
Edit:
recently introduced a fix so the answer is more accurately. now it will recheck his position with his previous positions.
Now a new question comes up. Which will be better to raise his 'number-color'? the node in which i am standing, or the node i am visiting (asking if i am adjacent to it)?
public class Modelacion {
public static void main(String args[]) throws IOException{
// given the matrix ... which i have hidden the initialization here
int[][] matriz = new int[40][40];
int color[] = new int[40];
for (int i = 0 ; i<40;i++)
color[i]=1;
Cromatico c = new Cromatico(matriz, color);
}
}
import java.io.IOException;
public class Cromatico {
Cromatico(int[][]matriz, int[] color, int fila) throws IOException{
for (int i = 0; i<fila;i++){
for (int j = 0 ; j<fila;j++){
if (matriz[i][j] == 1 && color[i] == color [j]){
if (j<i)
color [i] ++;
else
color [j] ++;
}
}
}
int numeroCromatico = 1;
for (int k = 0; k<fila;k++){
System.out.print(".");
numeroCromatico = Math.max(numeroCromatico, color[k]);
}
System.out.println();
System.out.println("el numero cromatico del grafo es: " + numeroCromatico);
}
}
Finding the chromatic number of a graph is NP-Complete (see Graph Coloring). It is NP-Complete even to determine if a given graph is 3-colorable (and also to find a coloring).
The wiki page linked to in the previous paragraph has some algorithms descriptions which you can probably use.
btw, since it is NP-Complete and you don't really care about performance, why don't you try using brute force?
Guess a chromatic number k, try all possibilities of vertex colouring (max k^n possibilities), if it is not colorable, new guess for chromatic number = min{n,2k}. If it is k-colorable, new guess for chromatic number = max{k/2,1}. Repeat, following the pattern used by binary search and find the optimal k.
Good luck!
And to answer your edit.
Neither option of incrementing the color will work. Also, your algorithm is O(n^2). That itself is enough to tell it is highly likely that your algorithm is wrong, even without looking for counterexamples. This problem is NP-Complete!
Super slow, but it should work:
int chromaticNumber(Graph g) {
for (int ncolors = 1; true; ncolors++) {
if (canColor(g, ncolors)) return ncolors;
}
}
boolean canColor(Graph g, int ncolors) {
return canColorRemaining(g, ncolors, 0));
}
// recursive routine - the first colors_so_far nodes have been colored,
// check if there is a coloring for the rest.
boolean canColorRemaining(Graph g, int ncolors, int colors_so_far) {
if (colors_so_far == g.nodes()) return true;
for (int c = 0; c < ncolors; c++) {
boolean ok = true;
for (int v : g.adjacent(colors_so_far)) {
if (v < colors_so_far && g.getColor(v) == c) ok = false;
}
if (ok) {
g.setColor(colors_so_far, c);
if (canColorRemaining(g, ncolors, colors_so_far + 1)) return true;
}
}
return false;
}