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);
}
}
}