jbyoshi.robotgame.impl.GameView.java Source code

Java tutorial

Introduction

Here is the source code for jbyoshi.robotgame.impl.GameView.java

Source

/*
 * Copyright (C) 2016 JBYoshi.
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package jbyoshi.robotgame.impl;

import java.util.*;
import java.util.function.*;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import jbyoshi.robotgame.action.*;
import jbyoshi.robotgame.api.*;
import jbyoshi.robotgame.model.*;
import jbyoshi.robotgame.util.*;

public final class GameView implements Game {
    private final GameModel model;
    final PlayerImpl player;
    private final Function<Model, ModelView<?>> views;
    private final Set<BoundAction> actions = new LinkedHashSet<>();

    public GameView(GameModel game, PlayerImpl player) {
        this.model = game;
        this.player = player;
        views = CacheBuilder.newBuilder().weakValues().<Model, ModelView<?>>build(
                CacheLoader.from(model -> ViewRegistry.wrap(model, this)))::getUnchecked;
    }

    @Override
    public Set<MyRobotView> getMyRobots() {
        return getMyViews(RobotModel.class, MyRobotView.class);
    }

    @Override
    public Set<MySpawnerView> getMySpawners() {
        return getMyViews(SpawnerModel.class, MySpawnerView.class);
    }

    @Override
    public Set<? extends Robot> getEnemyRobots() {
        return getEnemyViews(RobotModel.class, MyRobotView.class);
    }

    @Override
    public Set<? extends Spawner> getEnemySpawners() {
        return getEnemyViews(SpawnerModel.class, MySpawnerView.class);
    }

    @Override
    public Set<? extends ObjectInGame> getObjectsNear(Located loc, int distance) {
        Set<ModelView<?>> out = new HashSet<>();
        getObjectsNear(loc, distance, new HashSet<>(), out);
        return out;
    }

    private static final int WORLD_SIZE_HALF = WORLD_SIZE / 2;

    @Override
    public Optional<Path> createPath(Located start, Located end, Predicate<Point> isWalkable) {
        return new AStarPathFinder<Point>() {
            @Override
            protected Iterable<Point> getNeighbors(Point point) {
                return Arrays.stream(Direction.values()).map(point::add).filter(isWalkable)::iterator;
            }

            @Override
            protected int getResistance(Point from, Point to) {
                return getObjectsAt(to).isEmpty() ? 1 : 1000;
            }

            @Override
            protected int estimateDistanceToEnd(Point point, Point end) {
                return Math.min(
                        Math.min(estimateDistance(point, end),
                                estimateDistance(point.add(WORLD_SIZE_HALF, 0), end.add(WORLD_SIZE_HALF, 0))),
                        Math.min(estimateDistance(point.add(0, WORLD_SIZE_HALF), end.add(0, WORLD_SIZE_HALF)),
                                estimateDistance(point.add(WORLD_SIZE_HALF, WORLD_SIZE_HALF), end.add(50, 50))));
            }

            private int estimateDistance(Point a, Point b) {
                return Math.abs(a.getX() - b.getX()) + Math.abs(a.getY() - b.getY());
            }
        }.search(start.getLocation(), end.getLocation()).map(points -> new Path(start.getLocation(), points));
    }

    @Override
    public Optional<Path> createPath(Located start, Predicate<Point> end, Predicate<Point> isWalkable) {
        return new DijkstraPathFinder<Point>() {
            @Override
            protected Iterable<Point> getNeighbors(Point point) {
                return Arrays.stream(Direction.values()).map(point::add).filter(isWalkable)::iterator;
            }

            @Override
            protected int getResistance(Point from, Point to) {
                return getObjectsAt(to).isEmpty() ? 1 : 1000;
            }
        }.search(start.getLocation(), end).map(points -> new Path(start.getLocation(), points));
    }

    @Override
    public <T extends ObjectInGame> Optional<T> findNearest(Located start, Class<T> type, Predicate<T> acceptTarget,
            Predicate<Point> isWalkable) {
        Map<Point, T> objects = new HashMap<>();
        model.getAllModels().stream().map(views).filter(type::isInstance).map(type::cast).filter(acceptTarget)
                .forEach(view -> objects.put(view.getLocation(), view));

        if (objects.isEmpty())
            return Optional.empty();
        if (objects.containsKey(start.getLocation()))
            return Optional.of(objects.get(start.getLocation()));
        if (objects.size() == 1) {
            // Optimize using astar.
            return Optional.of(objects.values().iterator().next())
                    .filter(x -> createPath(start, x.getLocation(), isWalkable).isPresent());
        }
        return createPath(start, objects::containsKey, isWalkable).map(path -> path.getPoint(path.getLength() - 1))
                .map(objects::get);
    }

    @Override
    public boolean isWall(Point point) {
        return model.map[point.getX()][point.getY()];
    }

    private void getObjectsNear(Located loc, int distance, Set<Point> checked, Set<ModelView<?>> out) {
        if (checked.add(loc.getLocation())) {
            model.getModelsAt(loc.getLocation()).stream().map(views).forEach(out::add);
        }
        if (distance > 0) {
            for (Direction dir : Direction.values()) {
                getObjectsNear(loc.getLocation().add(dir), distance - 1, checked, out);
            }
        }
    }

    private <M extends Model, V extends ModelView<M>> Set<V> getMyViews(Class<M> modelType, Class<V> myViewClass) {
        return model.getModels(modelType).stream().map(views).flatMap(StreamHelpers.casting(myViewClass))
                .collect(StreamHelpers.toImmutableSet());
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private <M extends Model, V extends ModelView<M>> Set<V> getEnemyViews(Class<M> modelType,
            Class<? extends V> myViewClass) {
        return (Set) model.getModels(modelType).stream().map(views).filter(view -> !myViewClass.isInstance(view))
                .collect(StreamHelpers.toImmutableSet());
    }

    <T extends Model> void addAction(T model, Action<? super T> action) {
        actions.add(new BoundAction(action, model.getId()));
    }

    public Set<BoundAction> popActions() {
        Set<BoundAction> actions = new LinkedHashSet<>(this.actions);
        this.actions.clear();
        return actions;
    }

}