LoginSignup
0
0

More than 5 years have passed since last update.

テトラミノビンゴ

Last updated at Posted at 2013-11-18

CodeIQのテトラミノビンゴの解答
解答に1.5H程度かかったらしい。
実行時間は0.35秒程度。

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

namespace CodeIQ524
{
    class Program
    {
        const int Size = 5;

        static int[] hitNumbers;

        class Island : List<Point>
        {
            private int minX = int.MaxValue, minY = int.MaxValue, maxX = int.MinValue, maxY = int.MinValue;

            // 範囲を指定する追加のオーバーロード
            public new void Add(Point p)
            {
                base.Add(p);

                minX = Math.Min(minX, p.X);
                minY = Math.Min(minY, p.Y);
                maxX = Math.Max(maxX, p.X);
                maxY = Math.Max(maxY, p.Y);
            }

            // 包括矩形を取得
            public Rectangle BoundingRect
            {
                get
                {
                    return new Rectangle(minX, minY, maxX - minX + 1, maxY - minY + 1);
                }
            }

            // 範囲の幅と高さ
            public int Width { get { return BoundingRect.Width; } }
            public int Height { get { return BoundingRect.Height; } }

            // テトラミノであるかどうかのフラグ
            public bool IsTetramino { get { return this.Count == 4; } }

            // コーナーの座標
            private List<Point> Corners 
            {
                get {
                    return new List<Point> {
                        new Point(minX, minY),
                        new Point(minX, maxY),
                        new Point(maxX, minY),
                        new Point(maxX, maxY)
                    };
                }
            }

            // 指定したリストがいくつヒットしているかどうかを返す関数
            private int getHitCount(List<Point> points) 
            {
                return points.Where(x => this.Exists(y => y == x)).Count();
            }

            // コーナーを占有している数
            private int CornerCount
            {
                get
                {
                    return getHitCount(Corners);
                }
            }

            // 対角コーナーを占有しているかどうかを示す
            private bool IsDiagonal
            {
                get
                {
                    return getHitCount(new List<Point> { Corners[0], Corners[3] }) == 2 || getHitCount(new List<Point> { Corners[1], Corners[2] }) == 2;
                }
            }

            // テトラミノの様式を返す
            public String Judge
            {
                get
                {
                    // 数が4でなければエラー
                    if (!IsTetramino)
                        return null;

                    // 幅か高さが4ならI
                    if (Width == 4 || Height == 4)
                        return "I";

                    // 幅も高さも2ならO
                    if (Width == 2 && Height == 2)
                        return "O";

                    // 3コーナーを占有していたらL
                    if (CornerCount == 3)
                        return "L";

                    // 対角コーナーを占有していたらS
                    if (IsDiagonal)
                        return "S";

                    // いずれでもなければT
                    return "T";
                }
            }
        }

        class Board
        {
            // 盤面の実態
            bool[,] hitMap = new bool[Size, Size];

            // 数字とのマッピング
            Dictionary<int, Point> mapping = new Dictionary<int, Point>();

            // コンストラクタ
            public Board(int[,] pattern)
            {
                for (int x = 0; x < Size; x++)
                {
                    for (int y = 0; y < Size; y++)
                    {
                        mapping[pattern[x, y]] = new Point(x, y);
                    }
                }
            }

            public void setPattern(int[] pattern) 
            {
                for (int x = 0; x < Size; x++)
                {
                    for (int y = 0; y < Size; y++)
                    {
                        mapping[pattern[x + y * Size]] = new Point(x, y);
                    }
                }
            }

            // 問題様式のコンストラクタ
            public Board(String pattern)
            {
                List<int> numbers = new List<int>();

                foreach (var row in pattern.Split('/')) 
                {
                    numbers.AddRange(row.Split(',').Select(x => int.Parse(x)));
                }

                setPattern(numbers.ToArray());
            }

            // 数字を指定して座標を得る
            public Point? tryHit(int num)
            {
                if (mapping.ContainsKey(num))
                {
                    hitMap[mapping[num].X, mapping[num].Y] = true;
                    return mapping[num];
                }

                return null;
            }

            // 位置が盤面内かどうかの判断
            private bool inRange(Point p)
            {
                return p.X >= 0 && p.Y >= 0 && p.X < Size && p.Y < Size;
            }

            // 位置がヒットしているかどうかの判断
            private bool isHit(Point p)
            {
                return hitMap[p.X, p.Y];
            }

            public Island getIsland(Point p) 
            {
                Queue<Point> task = new Queue<Point>();
                List<Point> visited = new List<Point>();

                Island result = new Island();

                if (!isHit(p))
                    return result;

                task.Enqueue(p);
                visited.Add(p);
                result.Add(p);

                while (task.Count > 0)
                {
                    var chk = task.Dequeue();

                    // 上下左右について、未チェックで範囲内か調べる
                    for (int i = 0; i < 4; i++)
                    {
                        int dx = new int[] { 1, 0, -1, 0 }[i];
                        int dy = new int[] { 0, 1, 0, -1 }[i];

                        Point newPoint = new Point(chk.X + dx, chk.Y + dy);
                        if (inRange(newPoint) && !visited.Exists(x => x == newPoint))
                        {
                            // チェックリストに追加
                            visited.Add(newPoint);

                            // ヒットしていれば、結果に保存
                            if (isHit(newPoint))
                            {
                                result.Add(newPoint);
                                task.Enqueue(newPoint);
                            }
                        }
                    }
                }

                return result;
            }

            public String getResult(IEnumerable<int> numberList)
            {
                foreach (var number in numberList)
                {
                    var p = tryHit(number);
                    if (p != null)
                    {
                        // ヒットしたら、島を取得
                        var island = getIsland(p.Value);
                        var result = island.Judge;
                        if (result != null)
                            return result;
                    }
                }

                return null;
            }
        }

        static void Main(string[] args)
        {
            //Test();
            int[] result = new int[5];
            String resultType = "ILOST";
            DateTime start = DateTime.Now;

            hitNumbers = System.Console.ReadLine().Split(',').Select(x => int.Parse(x)).ToArray();
            String line;
            while ((line = System.Console.ReadLine()) != null)
            {
                Board board = new Board(line);
                String r = board.getResult(hitNumbers);
                if (r != null)
                {
                    result[resultType.IndexOf(r)]++;
                }
            }

            System.Diagnostics.Debug.WriteLine(String.Join(",", Enumerable.Range(0, resultType.Length).Select(x => resultType[x] + ":" + result[x])));
            System.Diagnostics.Debug.WriteLine(DateTime.Now - start);
        }
    }
}

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0