Problem:
ブロック

A さんの家に親戚の B 君がやってきました。彼は 3 歳でブロックが大好きです。彼が持っているブロックは図 1 のような形をしています。

図1

B 君はボードの上にブロックを敷き詰めています。彼に「何を作っているの?」と聞くと、彼は「迷路!!」と元気よく答えました。彼の言う迷路とは、スタートからゴールまで側面が接している、同じ色のブロックだけでたどることができるブロックの配置のことだそうです。図 2 は黄色のブロックにより、左上(スタート)から右下(ゴール)へ迷路ができていることを表しています。

図2

無邪気に遊んでいる B 君を横目に、プログラマーであるあなたは、ブロックの並びが迷路となっているかを確かめてみることにしました。

ブロックの情報とスタート、ゴールの座標を入力とし、ブロックが迷路となっていれば OK 、なっていなければ NG を出力するプログラムを作成してください。 ボードは横方向に w 、縦方向に h の大きさをもち、 左上の座標は(1 , 1)、右下の座標は(w, h)とします。ブロックは 2 × 4 の長方形ですべて同じ大きさです。ブロックの色 c は 1 (白)、2 (黄)、3 (緑)、4 (青)、5 (赤) のいずれかです。ブロックのボード上での向き d は 横方向に長い場合 0 、 縦方向に長い場合 1 とします。 ブロックの位置はブロックの左上の座標 (x, y) によって表されます。なお、ブロックの位置は他のブロックと重なることは無く、ボードからはみ出すこともありません。

Input

複数のデータセットの並びが入力として与えられます。 入力の終わりはゼロふたつの行で示されます。
各データセットは以下の形式で与えられます。

w h
xs ys
xg yg
n
c1 d1 x1 y1
c2 d2 x2 y2
:
cn dn xn yn

1 行目にボードの大きさw, h (4 ≤ w, h ≤ 100) が与えられます。2 行目にスタートの座標 xs, ys、3 行目にゴールの座標 xg, yg が与えられます。

4 行目にブロックの個数 n が与えられます。続く n 行に i 番目のブロックの色 ci、向き di、位置 xi, yi が与えられます。

データセットの数は 30 を超えません。

Output

入力データセットごとに、判別結果を１行に出力します。

Sample Input

20 20
1 1
9 9
7
2 0 1 1
5 1 1 3
2 1 3 3
1 1 5 2
5 1 7 3
2 0 2 7
2 0 6 8
20 20
9 9
1 1
6
2 0 1 1
1 0 5 1
2 1 1 3
5 0 1 7
3 1 5 5
4 1 8 5
0 0

Output for the Sample Input

OK
NG

Solution in C# (judge verdict: Accepted)

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

namespace _0207
{
    public class Program
    {

        class Point
        {
            public int X { get; private set; }
            public int Y { get; private set; }
            public Point(int x, int y) { X = x; Y = y; }
            public Point(int[] v) { X = v[0] - 1; Y = v[1] - 1; }
            public static bool operator ==(Point point1, Point point2) { return point1.X == point2.X && point1.Y == point2.Y; }
            public static bool operator !=(Point point1, Point point2) { return !(point1 == point2); }
            public static bool Equals(Point point1, Point point2) { return point1.X.Equals(point2.X) && point1.Y.Equals(point2.Y); }
            public override bool Equals(object o)
            {
                if ((null == o) || !(o is Point)) return false;
                return Equals(this, (Point)o);
            }
            public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); }
        }

        private static int[,] d = new int[,] { { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 } };
        private static int[,] map;
        private static bool[,] visited;
        private static Point start, goal;

        public static void Main(string[] args)
        {
            while (true)
            {
                int[] wh = RIntAr(); if (wh.Sum() == 0) break;
                Init(wh);
                Console.WriteLine(SearchRoute() ? "OK" : "NG");
            }
        }

        private static void Init(int[] wh)
        {
            const int BLOCK_W = 4;
            const int BLOCK_H = 2;

            map = new int[wh[1], wh[0]];
            visited = new bool[wh[1], wh[0]];
            start = new Point(RIntAr());
            goal = new Point(RIntAr());

            int n = RInt();
            for (int k = 0 ; k < n ; k++)
            {
                int[] items = RIntAr();
                int w, h;
                if (items[1] == 0) { w = BLOCK_W; h = BLOCK_H; }
                else { w = BLOCK_H; h = BLOCK_W; }

                for (int i = 0 ; i < h ; i++)
                {
                    for (int j = 0 ; j < w ; j++)
                    {
                        map[i + items[3] - 1, j + items[2] - 1] = items[0];
                    }
                }
            }
        }

        private static bool SearchRoute()
        {
            int color = map[start.Y, start.X];
            Queue<Point> q = new Queue<Point>();
            q.Enqueue(start);
            visited[start.Y, start.X] = true;

            while (q.Count > 0)
            {
                Point p = q.Dequeue();
                visited[p.Y, p.X] = true;

                if (p == goal) return true;

                for (int i = 0 ; i < d.GetLength(0) ; i++)
                {
                    int nextX = p.X + d[i, 0];
                    int nextY = p.Y + d[i, 1];
                    if (IsInArea(nextX, nextY))
                    {
                        if (map[nextY, nextX] == color && !visited[nextY, nextX])
                        {
                            q.Enqueue(new Point(nextX, nextY));
                        }
                    }
                }
            }
            return false;
        }

        private static bool IsInArea(int x, int y)
        {
            return (0 <= x && x < map.GetLength(1) && 0 <= y && y < map.GetLength(0));
        }

        static string RSt() { return Console.ReadLine(); }
        static int RInt() { return int.Parse(Console.ReadLine().Trim()); }
        static long RLong() { return long.Parse(Console.ReadLine().Trim()); }
        static double RDouble() { return double.Parse(Console.ReadLine()); }
        static string[] RStAr(char sep = ' ') { return Console.ReadLine().Trim().Split(sep); }
        static int[] RIntAr(char sep = ' ') { return Array.ConvertAll(Console.ReadLine().Trim().Split(sep), e => int.Parse(e)); }
        static long[] RLongAr(char sep = ' ') { return Array.ConvertAll(Console.ReadLine().Trim().Split(sep), e => long.Parse(e)); }
        static double[] RDoubleAr(char sep = ' ') { return Array.ConvertAll(Console.ReadLine().Trim().Split(sep), e => double.Parse(e)); }
        static string WAr<T>(IEnumerable<T> array, string sep = " ") { return string.Join(sep, array.Select(x => x.ToString()).ToArray()); }
    }

}