Problem:
Problem H： Puzzle and Hexagons

Backgorund

超大人気ゲーム「パズル&ヘキサゴンズ」がついにリリースされた。このゲームは超面白すぎてドハマりする人が続出。あまりの熱中度に医師から中毒認定を受ける者も続出した。世界各国の有志達はこのゲームの中毒者達を助けるために「パズル&ヘキサゴンズ」のシミュレータを作り、危険な実機でのプレイを避けるよう促そうとした。あなたにはシミュレータ作りに協力して欲しい。

Problem

正六角形のマスを縦にH個、横にW個敷き詰めた盤面が与えられる。
Fig.1はH=4,W=7の時の盤面とそれに対応するマスの座標(x,y)を示す。

Fig.1

初期状態で各マスには色のついたブロックが存在する。
ブロックの色は以下のようにアルファベット一文字で表現される。

'R' ・・・赤

'G' ・・・緑

'B' ・・・青

'P' ・・・紫

'Y' ・・・黄

'E' ・・・水

次に操作の数Qが与えられる。

各操作では回転の中心座標(x,y)が与えられ、そのマスの周囲にある6つのブロックを時計回りに一つ回転させることを示す。(Fig.2 参照)。
このとき、ブロックが存在しないマスも空のブロックが存在すると考えて時計回りに一つ回転させる。
ただし、指定された座標とその周辺の６つのマスの内いずれか一つでもH×Wの盤面の中に存在していない場合は回転を行わない。

Fig.2

次に以下の処理ができなくなるまで繰り返す。

Fig.3において、ブロックAの位置からB, C, Dの位置のいずれのマスにもブロックが存在しないとき、ブロックAはCの位置に落下する。マスB, Dが存在しない場合はブロックも存在しないと考え、マスCが存在しない場合は落下の処理を行わない。

1の処理が可能なブロックが存在する場合は1に戻る。

同じ色のブロックが3つ以上繋がっている場合、そのブロックは全て消滅する。
2つのブロックが繋がるとはマスの一辺を共有することである。

注意：この一連の処理は、操作が一つも与えられていない状態（初期状態）でも行われる。

Fig.3

全ての操作を実行した後の最終的な盤面を出力せよ。

Input

入力は以下の形式で与えられる。

H W
F0,H−1 F1,H−1 … FW−1,H−1
F0,H−2 F1,H−2 … FW−1,H−2
.
.
.
F0,0 F1,0 … FW−1,0
Q
x0 y0
x1 y1
.
.
.
xQ−1 yQ−1

1行目に、盤面の縦と横のサイズを表す2つの整数HとWが与えられる。
2行目からH+1行目に、各添字に対応する盤面の色を表す文字列が与えられる。
H+2行目に、操作の数Qが与えられる。
続くQ行に回転の中心のマスの座標を表すxとyが与えられる。

Constraints

3 ≤ H ≤ 50

3 ≤ W ≤ 50

0 ≤ x < W

0 ≤ y < H

1 ≤ Q ≤ 100

Fi,j ( 0 ≤ i < W , 0 ≤ j < H ) は'R','G','B','P','Y','E'のいずれかである。

Output

全ての操作を行った後の盤面をH行で出力せよ。
ただし、ブロックが無いマスは'.'で表すこと。

Sample Input1

3 3
RGR
RBP
YEB
1
1 1

Sample Output1

…
YBG
EBP

Fig.4はSample Input1における状態の遷移を表したものである。

Fig.4

Sample Input2

4 5
BYYGG
RRRRR
RRBRR
YYGGB
2
3 1
3 1

Sample Output2

.....
.....
.....
B.BGB

Sample Input3

4 4
BEEP
ERYY
BBRP
RBYP
1
1 2

Sample Output3

....
....
....
.B..

盤面の初期状態ですでに消えるブロックがあること注意。
両端にあるブロックの落下処理に注意。

Solution in C# (judge verdict: Accepted)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using static System.Math;
public static class P
{
    public static void Main()
    {
        var hw = Console.ReadLine().Split().Select(int.Parse).ToArray();
        var h = hw[0];
        var w = hw[1];
        var board = Enumerable.Repeat(0, hw[0]).Select(_ => Console.ReadLine().ToArray()).ToArray();

        var game = new Game(h, w, board);

        //Console.WriteLine(game.ToDebugString());
        //Console.WriteLine();

        game.Proceed();

        //Console.WriteLine(game.ToDebugString());
        //Console.WriteLine();

        int q = int.Parse(Console.ReadLine());
        for (int i = 0; i < q; i++)
        {
            var xy = Console.ReadLine().Split().Select(int.Parse).ToArray();
            var x = xy[0];
            var y = xy[1];
            y = h - y - 1;
            game.Rotate(x, y);

            //Console.WriteLine(game.ToDebugString());
            //Console.WriteLine();

            game.Proceed();

            //Console.WriteLine(game.ToDebugString());
            //Console.WriteLine();
        }

        Console.WriteLine(game.ToString());
    }
}

class Game
{
    public int Height;
    public int Width;
    public char[][] Board;
    public Game(int h, int w, char[][] board)
    {
        Height = h;
        Width = w;
        Board = board;
    }
    public char this[int y, int x]
    {
        get 
        {
            if (y < 0 || Height <= y || x < 0 || Width <= x) return '.';
            return Board[y][x];
        }
    }

    int[][][] neighborInds = new[]
    {
        new []
        {
            new[] { 0, +1 },
            new[] { +1, 0 },
            new[] { 0, -1 },
            new[] { -1, -1 },
            new[] { -1, 0 },
            new[] { -1, +1 },
        },
        new []
        {
            new[] { +1, +1 },
            new[] { +1, 0 },
            new[] { +1, -1 },
            new[] { 0, -1 },
            new[] { -1, 0 },
            new[] { 0, +1 },
        },
    };

    public void Rotate(int x, int y)
    {
        try
        {
            var inds = neighborInds[x % 2];
            Rotate(
                ref Board[y + inds[5][0]][x + inds[5][1]],
                ref Board[y + inds[4][0]][x + inds[4][1]],
                ref Board[y + inds[3][0]][x + inds[3][1]],
                ref Board[y + inds[2][0]][x + inds[2][1]],
                ref Board[y + inds[1][0]][x + inds[1][1]],
                ref Board[y + inds[0][0]][x + inds[0][1]]
            );
        }
        catch { }
    }
    private void Rotate(ref char a, ref char b, ref char c, ref char d, ref char e, ref char f)
    {
        var tmp = a;
        a = b;
        b = c;
        c = d;
        d = e;
        e = f;
        f = tmp;
    }

    public void Proceed() { while (Cycle()) ; }

    private bool Cycle()
    {
        bool moved = false;

        while (true)
        {
            bool curMoved = false;
            for (int y = Height - 2; y >= 0; y--)
            {
                for (int x = 0; x < Width; x++)
                {
                    if (this[y, x] == '.') continue;
                    if (neighborInds[x % 2].Take(3).All(ind => this[y + ind[0], x + ind[1]] == '.'))
                    {
                        curMoved = true;
                        moved = true;
                        Board[y + 1][x] = Board[y][x];
                        Board[y][x] = '.';
                    }
                }
            }
            if (!curMoved) break;

            //Console.WriteLine(ToDebugString());
            //Console.WriteLine();
        }

        bool[][] flag = Enumerable.Repeat(0, Height).Select(_ => new bool[Width]).ToArray();

        for (int y = 0; y < Height; y++)
        {
            for (int x = 0; x < Width; x++)
            {
                var color = this[y, x];
                if (color == '.') continue;
                var count = neighborInds[x % 2].Count(ind => color == this[y + ind[0], x + ind[1]]);
                if (count < 2) continue;
                flag[y][x] = true;
                foreach (var ind in neighborInds[x % 2])
                {
                    if (color == this[y + ind[0], x + ind[1]])
                    {
                        flag[y + ind[0]][x + ind[1]] = true;
                    }
                }
            }
        }

        for (int y = 0; y < Height; y++)
        {
            for (int x = 0; x < Width; x++)
            {
                if (flag[y][x])
                {
                    moved = true;
                    Board[y][x] = '.';
                }
            }
        }

        return moved;
    }

    public override string ToString()
    {
        return string.Join("\n", Board.Select(x => string.Join("", x)));
    }

    public string ToDebugString()
    {
        return string.Join("\n", Board.Select(x => $" {string.Join("   ", x.Where((_, y) => y % 2 == 0))}\n   {string.Join("   ", x.Where((_, y) => y % 2 == 1))}"));
    }
}