package com.basicalgorithms.coding_games;

import java.util.HashSet;
import java.util.Objects;
import java.util.Scanner;
import java.util.Set;

/**
 * Original question: https://www.codingame.com/multiplayer/bot-programming/coders-strike-back
 */
public class CodersStrikeBack {

    static double longestDist = Integer.MIN_VALUE;
    static Point initialPoint = null;
    static boolean hasFinishedOneLap;
    static Point from = null;
    static Point lastCheckpoint = null;
    static final Set<Point> visitedCheckPoints = new HashSet<>();
    static boolean hasBoosted = false;

    public static void main(String args[]) {
        Scanner in = new Scanner(System.in);

        // game loop
        while (true) {
            int x = in.nextInt();
            int y = in.nextInt();
            int nextCheckpointX = in.nextInt(); // x position of the next check point
            int nextCheckpointY = in.nextInt(); // y position of the next check point
            int nextCheckpointDist = in.nextInt(); // distance to the next checkpoint
            int nextCheckpointAngle = in.nextInt(); // angle between your pod orientation and the direction of the next checkpoint
            int opponentX = in.nextInt();
            int opponentY = in.nextInt();

            // Write an action using System.out.println()
            // To debug: System.err.println("Debug messages...");

            // You have to output the target position
            // followed by the power (0 <= thrust <= 100)
            // i.e.: "x y thrust"

            final Point nextCheckpoint = new Point(nextCheckpointX, nextCheckpointY);
            final Point currentPosition = new Point(x, y);
            final Point enemyPosition = new Point(opponentX, opponentY);

            if (visitedCheckPoints.size() > 1 && enemyInRange(currentPosition, enemyPosition)) {
                ramEnemyShip(currentPosition, enemyPosition);
            } else {
                cruise(currentPosition, nextCheckpoint, nextCheckpointAngle);
            }

            if (!nextCheckpoint.equals(lastCheckpoint)) {
                from = lastCheckpoint;
            }
            lastCheckpoint = nextCheckpoint;
        }
    }

    private static void ramEnemyShip(final Point currentPosition, final Point enemyPosition) {
        sailToDestination((enemyPosition.x), enemyPosition.y, "100");
    }

    private static boolean enemyInRange(final Point currentPosition, final Point enemyPosition) {
        return getDistant(currentPosition, enemyPosition) <= 1000;
    }

    private static void cruise(
            final Point currentPosition,
            final Point nextCheckpoint,
            final int nextCheckpointAngle) {

        if (initialPoint == null) {
            initialPoint = currentPosition;
        }

        int thrust = isWithinAngle(nextCheckpointAngle) ? 100 : 0;
        String power = String.valueOf(thrust);

        visitedCheckPoints.add(nextCheckpoint);
        System.err.println(
                "Checkpoint added:" + " nextCheckpointX=" + nextCheckpoint.x + ", nextCheckpointY=" + nextCheckpoint.y);

        for (final Point visitedCheckPoint : visitedCheckPoints) {
            System.err.println("Visited checkpoint: (" + visitedCheckPoint.x + ", " + visitedCheckPoint.y + ")");
        }

        if (shouldSlowDown(currentPosition, nextCheckpoint)) {
            power = String.valueOf(35);
        }

        if (hasFinishedOneLap(nextCheckpoint) &&
                isLongestDistant(from, nextCheckpoint) &&
                isWithinSharpAngle(nextCheckpointAngle) &&
                !hasBoosted) {
            power = "BOOST";
            hasBoosted = true;
            System.err.println("Boosted!!!");
        }

        sailToDestination(nextCheckpoint.x, nextCheckpoint.y, power);
    }

    private static boolean shouldSlowDown(
            final Point currentPosition,
            final Point nextCheckpoint) {
        return getDistant(currentPosition, nextCheckpoint) < 1000;
    }

    private static void sailToDestination(final int nextCheckpointX, final int nextCheckpointY, final String power) {
        System.out.println(nextCheckpointX + " " + nextCheckpointY + " " + power);

        System.err.println("Thrust:" + power);
    }

    private static boolean isWithinAngle(final int nextCheckpointAngle) {
        return -90 < nextCheckpointAngle && nextCheckpointAngle < 90;
    }

    private static boolean isWithinSharpAngle(final int nextCheckpointAngle) {
        return -15 < nextCheckpointAngle && nextCheckpointAngle < 15;
    }

    private static boolean hasFinishedOneLap(final Point point) {
        if (hasFinishedOneLap) {
            return true;
        }

        if (initialPoint == null) { return false; }

        hasFinishedOneLap = getDistant(initialPoint, point) <= 600;
        return hasFinishedOneLap;
    }

    private static boolean isLongestDistant(final Point from, final Point endPoint) {
        if (from == null) {
            return false;
        }
        System.err.println("Start Point: (" + from.x + ", " + from.y + "); End Point: ("
                + endPoint.x + ", " + endPoint.y + ") ");

        double dist = getDistant(from, endPoint);

        System.err.println("dist=" + dist + ", longestDist=" + longestDist);
        if (dist >= longestDist) {
            longestDist = dist;
            return true;
        }
        return false;
    }

    private static double getDistant(final Point from, final Point endPoint) {
        return Math.sqrt(Math.pow(from.x - endPoint.x, 2) + Math.pow(from.y - endPoint.y, 2));
    }

    private static class Point {

        final int x;
        final int y;

        private Point(final int t1, final int t2) {
            this.x = t1;
            this.y = t2;
        }

        @Override
        public boolean equals(final Object o) {
            if (this == o) { return true; }
            if (!(o instanceof Point)) { return false; }
            final Point point = (Point) o;
            return x == point.x &&
                    y == point.y;
        }

        @Override
        public int hashCode() {
            return Objects.hash(x, y);
        }
    }
}
