AI How to model genetic programming for Battleships

前端 未结 4 1331
-上瘾入骨i
-上瘾入骨i 2021-01-01 05:46

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 \

4条回答
  •  灰色年华
    2021-01-01 06:43

    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 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(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 {
        private static final int NUM_SHOTS = 40;
        private List shots;
        private int aveScore;
    
        // Make a new set of random shots.
        public Shooter newShots() {
            shots = new ArrayList(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

    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.

提交回复
热议问题