Problem:
宇宙船 UAZ アドバンス号

恒星歴 2005.11.5。あなたは宇宙船 UAZ アドバンス号の艦長として敵の宇宙船と交戦しようとしています。 幸い敵の宇宙船はまだこちらに気付かずに静止しています。また、すでに敵の宇宙座標は判明しており強力な直線のビームを放つ「フェザー砲」は発射準備を完了しています。あとは、発射命令を出すばかりです。

ところが、宇宙空間には、敵の設置したエネルギーバリアが存在しています。バリアは三角形をしており「フェザー砲」のビームをはね返してしまいます。また、ビームがバリアに当たれば敵に気付かれて逃げられてしまいます。事前に命中すると判定できなければ、発射命令は出せません。

そこで、UAZ アドバンス号、敵、バリアの位置の宇宙座標(3次元座標 x, y, z) を入力して、ビームがバリアをさけて敵に命中する場合は "HIT"、バリアに当たってしまう場合"MISS"と出力するプログラムを作成してください。

ただし、バリアはアドバンス号から 3 角形に見えるものだけが対象であり、線分につぶれて見えるものはないものとします。また、バリアは 3 角形の頂点を含む境界でも有効であり、ビームをはね返すものとします。また、敵がバリア内にいる場合は"MISS"と出力して下さい。

Input

入力データの形式は以下のとおりです：

1 行目は、UAZ アドバンス号の座標 (x, y, z) (整数、半角空白区切り)

2 行目は、敵の座標 (x, y, z) (整数、半角空白区切り)

3 行目は、バリアの頂点 1 の座標 (x, y, z) (整数、半角空白区切り)

4 行目は、バリアの頂点 2 の座標 (x, y, z ) (整数、半角空白区切り)

5 行目は、バリアの頂点 3 の座標 (x, y, z ) (整数、半角空白区切り)

Output

HIT または MISS と１行に出力してください。

Constraints

-100 ≤ x, y, z ≤ 100

UAZ アドバンス号と敵が同じ位置にいることはない。

Sample Input 1

-10 0 0
10 0 0
0 10 0
0 10 10
0 0 10

Output for the Sample Input 1

HIT

Sample Input 2

-10 6 6
10 6 6
0 10 0
0 10 10
0 0 10

Output for the Sample Input 2

MISS

Solution in C# (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static readonly double EPS = 1E-10;

        static void Main(string[] args)
        {
            double[] input;

            input = Array.ConvertAll(Console.ReadLine().Split(' '), double.Parse);
            Point3D uaz = new Point3D(input[0], input[1], input[2]);

            input = Array.ConvertAll(Console.ReadLine().Split(' '), double.Parse);
            Point3D enemy = new Point3D(input[0], input[1], input[2]);

            Point3D[] barrier = new Point3D[3];

            for (int i = 0; i < 3; i++)
            {
                input = Array.ConvertAll(Console.ReadLine().Split(' '), double.Parse);
                barrier[i] = new Point3D(input[0], input[1], input[2]);
            }

            Point3D d = (barrier[1] - barrier[0]).Cross(barrier[2] - barrier[0]);

            Point3D ub = uaz - barrier[0];
            Point3D eb = enemy - barrier[0];

            if (d.Dot(ub) * d.Dot(eb) > 0)
            {
                Console.WriteLine("HIT");
            }
            else
            {
                Point3D v = uaz + (enemy - uaz) * Math.Abs(d.Dot(ub)) / (Math.Abs(d.Dot(ub)) + Math.Abs(d.Dot(eb)));

                if ((barrier[1] - barrier[0]).Cross(v - barrier[1]).Dot((barrier[2] - barrier[1]).Cross(v - barrier[2])) > -EPS &&
                    (barrier[1] - barrier[0]).Cross(v - barrier[1]).Dot((barrier[0] - barrier[2]).Cross(v - barrier[0])) > -EPS)
                {
                    Console.WriteLine("MISS");
                }
                else
                {
                    Console.WriteLine("HIT");
                }
            }
        }
    }

    struct Point3D
    {
        internal double x, y, z;

        public Point3D(double x, double y, double z)
        {
            this.x = x;
            this.y = y;
            this.z = z;
        }

        public Point3D Cross(Point3D other)
        {
            Point3D ret;
            ret.x = y * other.z - z * other.y;
            ret.y = z * other.x - x * other.z;
            ret.z = x * other.y - y * other.x;
            return ret;
        }

        public double Dot(Point3D other)
        {
            return x * other.x + y * other.y + z * other.z;
        }

        public static Point3D operator +(Point3D a, Point3D b)
        {
            return new Point3D(a.x + b.x, a.y + b.y, a.z + b.z);
        }

        public static Point3D operator -(Point3D a, Point3D b)
        {
            return new Point3D(a.x - b.x, a.y - b.y, a.z - b.z);
        }

        public static Point3D operator *(Point3D p, double m)
        {
            return new Point3D(p.x * m, p.y * m, p.z * m);
        }

        public static Point3D operator /(Point3D p, double m)
        {
            return new Point3D(p.x / m, p.y / m, p.z / m);
        }
    }
}