Package net.bytten.metazelda.generators

Source Code of net.bytten.metazelda.generators.LinearDungeonGenerator$AStarClient

package net.bytten.metazelda.generators;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import net.bytten.metazelda.Dungeon;
import net.bytten.metazelda.Edge;
import net.bytten.metazelda.Room;
import net.bytten.metazelda.Symbol;
import net.bytten.metazelda.constraints.IDungeonConstraints;
import net.bytten.metazelda.util.AStar;
import net.bytten.metazelda.util.Coords;
import net.bytten.metazelda.util.ILogger;

/**
* Extends DungeonGenerator to choose the least nonlinear one immediately
* available. This saves the player from having to do a lot of backtracking.
*
* Ignores switches for now.
*/
public class LinearDungeonGenerator extends DungeonGenerator {
   
    public static final int MAX_ATTEMPTS = 10;

    public LinearDungeonGenerator(ILogger logger, long seed,
            IDungeonConstraints constraints) {
        super(logger, seed, constraints);
    }
   
    public LinearDungeonGenerator(long seed, IDungeonConstraints constraints) {
        this(null, seed, constraints);
    }
   
    private class AStarClient implements AStar.IClient<Integer> {
       
        private int keyLevel;
       
        public AStarClient(int keyLevel) {
            this.keyLevel = keyLevel;
        }

        @Override
        public Collection<Integer> getNeighbors(Integer roomId) {
            List<Integer> ids = new ArrayList<Integer>();
            for (Edge edge: dungeon.get(roomId).getEdges()) {
                if (!edge.hasSymbol() || edge.getSymbol().getValue() < keyLevel) {
                    ids.add(edge.getTargetRoomId());
                }
            }
            return ids;
        }

        @Override
        public Coords getCoords(Integer roomId) {
            return dungeon.get(roomId).getCenter();
        }
    }
   
    private List<Integer> astar(int start, int goal, final int keyLevel) {
        AStar<Integer> astar = new AStar<Integer>(new AStarClient(keyLevel), start, goal);
        return astar.solve();
    }
   
    /**
     * Nonlinearity is measured as the number of rooms the player would have to
     * pass through multiple times to get to the goal room (collecting keys and
     * unlocking doors along the way).
     *
     * Uses A* to find a path from the entry to the first key, from each key to
     * the next key and from the last key to the goal.
     *
     * @return  The number of rooms passed through multiple times
     */
    public int measureNonlinearity() {
        List<Room> keyRooms = new ArrayList<Room>(constraints.getMaxKeys());
        for (int i = 0; i < constraints.getMaxKeys(); ++i) {
            keyRooms.add(null);
        }
        for (Room room: dungeon.getRooms()) {
            if (room.getItem() == null) continue;
            Symbol item = room.getItem();
            if (item.getValue() >= 0 && item.getValue() < keyRooms.size())
                keyRooms.set(item.getValue(), room);
        }
        // for N >= 0: keyRooms[N] = location of key N
       
        Room current = dungeon.findStart(),
                goal = dungeon.findGoal();
        // Clients may disable generation of the goal room -- the equivalent
        // 'ending' room becomes the boss room.
        if (goal == null) goal = dungeon.findBoss();
        assert current != null && goal != null;
        int nextKey = 0, nonlinearity = 0;
       
        Set<Integer> visitedRooms = new TreeSet<Integer>();
        while (current != goal) {
            Room intermediateGoal;
            if (nextKey == constraints.getMaxKeys())
                intermediateGoal = goal;
            else
                intermediateGoal = keyRooms.get(nextKey);
           
            List<Integer> steps = astar(current.id, intermediateGoal.id,
                    nextKey);
            for (Integer id: steps) {
                if (visitedRooms.contains(id)) ++nonlinearity;
            }
            visitedRooms.addAll(steps);
           
            nextKey++;
            current = dungeon.get(steps.get(steps.size()-1));
        }
        return nonlinearity;
    }

    @Override
    public void generate() {
        int attempts = 0, currentNonlinearity = Integer.MAX_VALUE;
        int bestAttempt = 0;
        Dungeon currentBest = null;
        while (attempts++ < MAX_ATTEMPTS) {
            super.generate();
           
            int nonlinearity = measureNonlinearity();
            log("Dungeon " + attempts + " nonlinearity: "+
                    nonlinearity);
            if (nonlinearity < currentNonlinearity) {
                currentNonlinearity = nonlinearity;
                bestAttempt = attempts;
                currentBest = dungeon;
            }
        }
        assert currentBest != null;
        log("Chose " + bestAttempt + " nonlinearity: "+
                currentNonlinearity);
        dungeon = currentBest;
    }

}
TOP

Related Classes of net.bytten.metazelda.generators.LinearDungeonGenerator$AStarClient

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.