Package com.m00ware.vindinium

Source Code of com.m00ware.vindinium.PathFinder$BoardMarks

package com.m00ware.vindinium;

import java.util.*;

import vindinium.*;
import vindinium.Board.HeroTile;
import vindinium.Board.Mine;
import vindinium.Board.Position;
import vindinium.Board.Tile;
import vindinium.Hero.HeroState;

public class PathFinder {
    public static final boolean LOGGING = false;
    public static final int GOLD_LOSS_TAVERN = 2;
    public static final int HP_LOSS_PER_TURN = 1;
    public static final int HP_WIN_TAVERN = 50;
    public static final int HP_LOSS_MINE_FIGHT = 20;
    public static final int HP_LOSS_HERO_FIGHT = 20;
    private final boolean safe;
    private final Hero hero;
    private final Board board;
    private final int maxDist;

    public PathFinder(boolean safe, Hero hero, Board board) {
        this(safe, hero, board, board.getSize() * board.getSize());
    }

    public PathFinder(boolean safe, Hero hero, Board board, int maxDist) {
        this.safe = safe;
        this.hero = hero;
        this.board = board;
        this.maxDist = maxDist;
    }

    public Direction findNearest(Predicate<State> t) {
        BoardMarks marks = new BoardMarks(board);
        Queue<State> queue = new LinkedList<>();
        queue.offer(new State(hero.state));
        marks.mark(queue.peek().hero.position);
        while (!queue.isEmpty()) {
            State state = queue.poll();
            State move = move(state, Direction.NORTH);
            if (processCandidateState(move, queue, t, marks)) {
                return findFirstMove(move);
            }

            move = move(state, Direction.SOUTH);
            if (processCandidateState(move, queue, t, marks)) {
                return findFirstMove(move);
            }

            move = move(state, Direction.WEST);
            if (processCandidateState(move, queue, t, marks)) {
                return findFirstMove(move);
            }

            move = move(state, Direction.EAST);
            if (processCandidateState(move, queue, t, marks)) {
                return findFirstMove(move);
            }
        }
        return null;
    }

    public static void log(String s) {
        if (LOGGING) {
            System.out.println(s);
        }
    }

    private Direction findFirstMove(State s) {
        State c = s;
        while (c.prev.deltaToPrev != Direction.STAY) {
            c = c.prev;
        }
        return c.deltaToPrev;
    }

    private boolean processCandidateState(State s, Queue<State> queue, Predicate<State> t, BoardMarks marks) {
        if (!s.hero.position.isValid(board)) {
            log("  Trying " + s + "  Impossible: not on board");
            return false;
        }
        if (marks.isMarked(s.hero.position)) {
            log("  Trying " + s + " ...Already explored");
            return false;
        }
        marks.mark(s.hero.position);
        if (!isPossibleState(s)) {
            return false;
        }
        if (t.apply(s)) {
            log("  Trying " + s + "  Success!");
            return true;
        }

        if (safe && !s.isSafe) {
            log("  Trying " + s + "  Impossible: not safe");
            return false;
        }
        if (!isFinalState(s)) {
            log("  Trying " + s + "  Continuing...");
            queue.offer(s);
        } else {
            log("  Trying " + s + "  Dead end");
        }
        return false;
    }

    private static class BoardMarks {
        private final boolean marks[];
        private final int size;

        public BoardMarks(Board b) {
            this.size = b.getSize();
            this.marks = new boolean[size * size];
        }

        public boolean isMarked(Position p) {
            return marks[p.x + p.y * size];
        }

        public void mark(Position p) {
            marks[p.x + p.y * size] = true;
        }
    }

    // TODO imple respawn rules

    public boolean isPossibleState(State state) {
        if (state.hero.life <= 0) {
            log("  Trying " + state + "  Impossible: no HP");
            return false;
        }
        if (state.hero.gold < 0) {
            log("  Trying " + state + "  Impossible: no GOLD");
            return false;
        }
        if (state.dist > maxDist) {
            log("  Trying " + state + "  Impossible: too far");
            return false;
        }
        Tile tile = board.tileAt(state.hero.position);
        if (tile == Tile.WALL) {
            log("  Trying " + state + "  Impossible: it's a Wall");
            return false;
        }
        return true;
    }

    public boolean isFinalState(State state) {
        Tile tile = board.tileAt(state.hero.position);
        if (tile == Tile.AIR) {
            return false;
        }
        return true;
    }

    public static class State {
        @Override
        public String toString() {
            return "State [hero=" + hero + ", isSafe= " + isSafe + "]";
        }

        final int dist;
        final State prev;
        final Direction deltaToPrev;
        final HeroState hero;
        final boolean isSafe;

        public State(HeroState hero) {
            this.hero = hero;
            this.dist = 0;
            prev = null;
            isSafe = true;
            deltaToPrev = Direction.STAY;

        }

        public State(State prev, Direction deltaToPrev, HeroState hero) {
            this.prev = prev;
            this.deltaToPrev = deltaToPrev;
            this.hero = hero;
            this.isSafe = prev != null && prev.hero.life - this.hero.life == HP_LOSS_PER_TURN;
            this.dist = prev.dist + 1;
        }
    }

    private State move(State s, Direction d) {
        Position newPos = move(s.hero.position, d);
        return new State(s, d, new HeroState(s.hero.life + deltaHp(newPos, s.hero.life), deltaGold(newPos), deltaMines(newPos), newPos));
    }

    private static Position move(Position pos, Direction d) {
        return new Position(pos.x + d.dx, pos.y + d.dy);
    }

    private int deltaHp(Position p, int currentHealth) {
        if (!p.isValid(board)) {
            return 0;
        }
        int delta = 0;
        Tile tile = board.tileAt(p);
        if (tile instanceof Mine) {
            Mine mine = (Mine) tile;
            delta += mine.isOwnedBy(hero) ? 0 : -HP_LOSS_MINE_FIGHT;
        } else if (tile == Tile.TAVERN) {
            delta += HP_WIN_TAVERN;
        }

        delta += deltaHpFrom(move(p, Direction.NORTH));
        delta += deltaHpFrom(move(p, Direction.SOUTH));
        delta += deltaHpFrom(move(p, Direction.EAST));
        delta += deltaHpFrom(move(p, Direction.WEST));

        if (currentHealth + delta > 1) {
            delta += -HP_LOSS_PER_TURN;
        }

        return delta;
    }

    private int deltaGold(Position p) {
        if (!p.isValid(board)) {
            return 0;
        }
        int delta = board.minesForHero(hero);
        Tile tile = board.tileAt(p);
        if (tile == Tile.TAVERN) {
            delta += -GOLD_LOSS_TAVERN;
        }
        return delta;
    }

    private int deltaMines(Position p) {
        if (!p.isValid(board)) {
            return 0;
        }
        Tile tile = board.tileAt(p);
        if (tile instanceof Mine) {
            return 1;
        }
        return 0;
    }

    // TODO this is inaccurate since we could be the attacker. Here we just assume they will attack us
    private int deltaHpFrom(Position p) {
        if (!p.isValid(board) || !safe) {
            return 0;
        }
        Tile tile = board.tileAt(p);
        if (tile instanceof HeroTile) {
            HeroTile heroTile = (HeroTile) tile;
            return heroTile.is(hero) ? 0 : -HP_LOSS_HERO_FIGHT;
        }
        return 0;
    }
}
TOP

Related Classes of com.m00ware.vindinium.PathFinder$BoardMarks

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.