123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318 |
- /// <reference path="../Room.ts" />
- interface TrickierOptions {
- region : RegionRandom;
- map : RoomRandomMap;
- otherRoom : RoomRandom;
- }
- interface TrickyOptions extends TrickierOptions {
- otherRoomDirection : number;
- trickyRoomDirection : number;
- x : number;
- y : number;
- }
- interface RoomRandomNode {
- room : RoomRandom;
- coordinates : Array<number>;
- distance : number;
- }
- class RoomRandom extends Room {
- public connectableOn : Array<number> = [Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST];
- public randomizable = true; // non-randomizable rooms don't get placed automatically
- public placed = false;
- public appearChance = 75;
- public extraConnectionChance = 15;
- public backgroundImage = "tomato";
- public lastMap : RoomRandomMap;
- public constructor (id? : string, fodder? : boolean, forbidden? : boolean) {
- super(id, fodder);
- this.randomizable = forbidden != true;
- }
- public getBackgroundClass () {
- if (this.isImageDefined()) {
- return this.backgroundImage;
- }
- return "tomato";
- }
- private isImageDefined () {
- try {
- for (var i = 0; i < document.styleSheets.length; i++) {
- var rules = document.styleSheets[i]['rules'] || document.styleSheets[i]['cssRules'];
- for (var x in rules) {
- if (typeof rules[x].selectorText == 'string' && rules[x].selectorText == "." + this.backgroundImage) {
- return true;
- }
- }
- }
- console.warn("Room background " + this.backgroundImage + " not found.");
- return false;
- } catch (e) {
- console.warn("Unable to read image");
- return true;
- }
- }
- public isConnectableOn (oppositeDirection : number) {
- return this.connectableOn.indexOf(oppositeDirection) != -1;
- }
- public trickyCode : (options : TrickyOptions) => boolean;
- public getAnyDirection (options : TrickierOptions) : TrickyOptions {
- let directionShuffler = new Shuffler<number>(this.connectableOn);
- for (let direction = directionShuffler.getOne(); direction != undefined; direction = directionShuffler.getOne()) {
- let oppositeDirection = OppositeDirection[Direction[direction]];
- let otherCoordinates = options.map.getCoordinates(options.otherRoom);
- let wouldbeCoordinates = Room.shift(otherCoordinates, oppositeDirection);
- let trickyOptions = {
- otherRoom : options.otherRoom,
- otherRoomDirection : oppositeDirection,
- trickyRoomDirection : direction,
- map : options.map,
- region : options.region,
- x : wouldbeCoordinates[0],
- y : wouldbeCoordinates[1]
- };
- if (this.isPlaceable(trickyOptions)) {
- return trickyOptions;
- }
- }
- }
- public isPlaceable (options : TrickyOptions) {
- if (!this.isConnectableOn(options.trickyRoomDirection) || !options.map.isFree(options.x, options.y)) {
- // This can't connect through that!
- // That coordinate isn't free!
- return false;
- }
- if (options.otherRoom == undefined || !options.otherRoom.isConnectableOn(options.otherRoomDirection)) {
- // There is no other room there?
- // The other room doesn't like it this way
- return false;
- }
- // Do I have my own tricky code?
- if (this.trickyCode != undefined) {
- return this.trickyCode(options);
- }
- return true;
- }
- public getDistanceTo (room : RoomRandom) {
- let otherCoordinates = this.lastMap.getCoordinates(room);
- return this.getDistanceToCoordinates(otherCoordinates);
- }
- public getDistanceToCoordinates (otherCoordinates) {
- let myCoordinates = this.lastMap.getCoordinates(this);
- if (myCoordinates != undefined && otherCoordinates != undefined) {
- let c1 = myCoordinates;
- let c2 = otherCoordinates;
- return Math.abs(c1[0] - c2[0]) + Math.abs(c1[1] - c2[1]);
- }
- }
- /**
- * Returns the closest direction we have in North, South, etc.
- * @param coordinates
- */
- public getOverallDirectionTo (coordinates) {
- let myCoordinates = this.lastMap.getCoordinates(this);
- let dy = (coordinates[1] - myCoordinates[1]);
- let dx = (coordinates[0] - myCoordinates[0]);
- let theta = Math.atan2(dy, dx); // range (-PI, PI]
- theta *= 180 / Math.PI; // rads to degs, range (-180, 180];
- theta = Math.round(theta / 45);
- if (theta < 0) {
- theta = 8 + theta;
- }
- let directions = [Direction.EAST, Direction.NORTHEAST, Direction.NORTH, Direction.NORTHWEST, Direction.WEST, Direction.SOUTHWEST, Direction.SOUTH, Direction.SOUTHEAST];
- return directions[theta];
- //if (theta < 0) theta = 360 + theta; // range [0, 360)
- }
- /**
- * This implementation is sufficiently fast for constant use.
- * @param pathEnd
- * @param map
- * @param availableRooms
- * @returns {Array}
- */
- public findPathTo (pathEnd : RoomRandom, validRoom? : (room : RoomRandom) => boolean) {
- validRoom = validRoom == undefined ? () => {return true;} : validRoom;
- let map = this.lastMap;
- let endPosition = map.getCoordinates(pathEnd);
- let open = [];
- let distance = (c1, c2) => {
- return Math.abs(c1[0] - c2[0]) + Math.abs(c1[1] - c2[1]);
- };
- let neighbors = (room : RoomRandom, x : number, y : number) => {
- let neighs = [];
- for (let direction = 0; direction < room.connections.length; direction++) {
- let otherRoom = room.connections[direction];
- if (otherRoom != undefined && open.indexOf(otherRoom) == -1 && validRoom(<RoomRandom> otherRoom)) {
- let dirCoordinates = Room.shift([x, y], direction);
- let dir = [otherRoom, dirCoordinates, distance(endPosition, dirCoordinates)];
- neighs.push(dir);
- }
- }
- return neighs.sort((a,b) => { return (<number> a[2]) - (<number> b[2]);});
- };
- let shortestPath = {
- length : map.getRoomCount()
- };
- let noPath = shortestPath;
- let cPath = [];
- let findPath = (myArray) => {
- let room = myArray[0];
- cPath.push(myArray);
- if (room == pathEnd) {
- if (shortestPath.length >= cPath.length) {
- shortestPath = cPath.slice(0);
- }
- } else if (shortestPath.length > (cPath.length)) {
- open.push(room);
- let otherRooms = neighbors(room, myArray[1][0], myArray[1][1]);
- for (let i = 0; i < otherRooms.length; i++) {
- if ((cPath.length + 1) < shortestPath.length) {
- findPath(otherRooms[i]);
- }
- }
- open.pop();
- }
- cPath.pop();
- };
- findPath([this, map.getCoordinates(this)]);
- return shortestPath != noPath ? shortestPath : undefined;
- }
- public getBestDirectionTo (otherRoom : RoomRandom, validRoom? : (room : RoomRandom) => boolean) {
- let path = this.findPathTo(otherRoom, validRoom);
- if (path != undefined) {
- if (path.length == 1) {
- return undefined;
- }
- return this.connections.indexOf(path[1][0]);
- }
- }
- public getAStarPathTo (otherRoom : RoomRandom, validRoom? : (room : RoomRandom) => boolean) {
- validRoom = validRoom != undefined ? validRoom : () => {return true};
- let distance = (c1, c2) => {
- return Math.abs(c1[0] - c2[0]) + Math.abs(c1[1] - c2[1]);
- };
- let isVisited = (room) => {
- return visited.indexOf(room) != -1;
- };
- let getNeighbors = (node : RoomRandomNode) => {
- let neighbors : Array<RoomRandomNode> = [];
- for (let direction = 0; direction < node.room.connections.length; direction++) {
- if (node.room.connections[direction] != undefined && !isVisited(node.room.connections[direction]) && validRoom(<RoomRandom> node.room.connections[direction])) {
- let coordinates = Room.shift(node.coordinates, direction);
- neighbors.push({
- room : <RoomRandom> node.room.connections[direction],
- coordinates : coordinates,
- distance : distance(coordinates, endNode.coordinates)
- });
- visited.push(<RoomRandom> node.room.connections[direction]);
- }
- }
- return neighbors;
- };
- let getClosestPath = () => {
- let shortest = 0;
- for (let i = 1; i < open.length; i++) {
- let lastPoint = open[i][open[i].length - 1];
- if (lastPoint.distance < open[shortest][open[shortest].length - 1].distance) {
- shortest = i;
- }
- }
- return shortest;
- };
- let endNode = {room : otherRoom, coordinates : this.lastMap.getCoordinates(otherRoom), distance : 0};
- let startCoordinates = this.lastMap.getCoordinates(this);
- let startNode = {room : this, coordinates : startCoordinates, distance : distance(startCoordinates, endNode.coordinates)};
- let open : Array<Array<RoomRandomNode>> = [[startNode]];
- let closed : Array<Array<RoomRandomNode>> = [];
- let shortestPath = this.lastMap.getRoomCount();
- let shortestIndex;
- let myPath;
- let closest = 0;
- let visited : Array<RoomRandom> = [this];
- while (open.length > 0) {
- myPath = open.splice(closest, 1)[0];
- if (myPath[myPath.length - 1].distance == 0) {
- let push = closed.push(myPath);
- if (myPath.length < shortestPath) {
- shortestPath = myPath.length;
- shortestIndex = push - 1;
- }
- // lazy, first path is very likely to be the best
- break;
- } else {
- let neighbors = getNeighbors(myPath[myPath.length - 1]);
- for (let i = 0; i < neighbors.length; i++) {
- open.push(myPath.concat([neighbors[i]]));
- }
- }
- for (let i = open.length - 1; i >= 0; i--) {
- if (open[i].length >= shortestPath) {
- open.splice(i, 1);
- }
- }
- closest = getClosestPath();
- }
- return closed[shortestIndex];
- }
- public getAStarBestDirectionTo (otherRoom : RoomRandom, validRoom? : (room : RoomRandom) => boolean) {
- let path = this.getAStarPathTo(otherRoom, validRoom);
- if (path != undefined) {
- if (path.length == 1) {
- return undefined;
- }
- return this.connections.indexOf(path[1].room);
- }
- }
- public getConnectedDirection () {
- let shuffler = new Shuffler(Room.DIRECTIONS);
- for (let direction = shuffler.getOne(); direction != undefined; direction = shuffler.getOne()) {
- if (this.connections[direction] != undefined) {
- return direction;
- }
- }
- }
- // TODO: Return all things of type that are in placed RoomRandom.
- public static getActive (type : typeof Thing) {
- }
- }
- // random = new RoomRandom...
- // random.connectableOn = [Room.DIRECTION_NORTH, Room.DIRECTION_SOUTH...]
|