Problem:
ザ・スクエアーズ

この度、有名なテーマパークに、巨大迷路ザ・スクエアーズが新しく完成しました。 消防署の指導により避難訓練をしなければなりませんが、巨大迷路なだけに訓練にかかる時間を予測することができません。そこで、あなたは以下の仕様をもとに避難訓練シミュレータを開発することになりました。

巨大迷路は図 1 に示すように、横 W 、縦 H の W × H 個のマス目で表わされます。各マス目は、通路(白いマス目)、壁(茶色いマス目) 、非常口(緑のマス目)のいずれかです。図中の○は人を表し、その中の英小文字(E、W、S、N)はその人が向いている方角(東西南北)を表しています。図は上方向が北になるように描かれています。

図1

巨大迷路内にいる人は最初、東西南北のいずれかの方向を向いて立っています。各人は 1 秒単位で同時に次に示す手順で移動を試みます。

現在向いている方向の、右、前、左、後のマス目を順番に調べ、最初に見つけた、空いている通路または非常口の方向に向きを変えます。そのようなマス目が無い場合は向きを変えません。

目の前のマス目が空いていて、他の人の目の前のマス目になっていない場合は移動します。同じマス目を目の前のマスとする人が複数いる場合は、そのマス目の、東、北、西、南のマス目にいる人の順で選択された 1 人が移動します。

移動後に非常口に到着した人は、無事避難し迷路内から消えます。

与えられた巨大迷路と人の位置情報を入力とし、全ての人が避難し終える時間を出力するプログラムを作成してください。 脱出に 180 秒より長い時間を要する場合は NA と出力して下さい。 迷路と人の位置情報は、 H 行 W 列の文字によって与えられます。各文字の意味は以下のとおりです。

# : 壁

. : 床

X : 非常口

E : 東を向いている人

N : 北を向いている人

W : 西を向いている人

S : 南を向いている人

なお、迷路と外部との境界は壁 # または非常口 X のいずれかです。また、巨大迷路の中には、人が必ず１人以上います。

Input

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

W H
str1
str2
:
strH

1 行目に迷路の横方向の大きさ W、縦方向の大きさ H (1 ≤ W, H ≤ 30) が与えられます。続く H 行に迷路の i 行目を表す文字列 stri (長さ W) が与えられます。

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

Output

入力データセットごとに、全ての人が避難し終える時間を１行に出力します。

Sample Input

10 3
##########
#E.......X
##########
4 4
####
#N.#
#..X
####
5 5
#####
#N..#
###.X
#S..#
#####
6 6
######
#..#X#
#.EE.#
####N#
#....#
######
8 8
##X#####
#....E.#
#####.##
#.#...##
#.W.#..#
#.#.N#.X
#X##.#.#
########
0 0

Output for the Sample Input

8
NA
9
16
10

Solution in C# (judge verdict: Accepted)



using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

namespace AOJ
{
    public class Player
    {
        public int x;
        public int y;
        public bool move;
        //public bool goal;
        public Player(int x, int y) { 
            this.x = x;
            this.y = y;
        }
    }
    public  class Program
    {

        static char[] DIREC = { 'N', 'E', 'S', 'W' };

        private char[][] map;
        private int w, h;
        private Char rotate(char x,int n)
        {
            int d_i=0;
            for (int i = 0; i < DIREC.Length; i++)
            {
                if (DIREC[i] == x)
                {
                    d_i = i;
                    break;
                }
            }
            int[] a = {1,0,3,2};

            return DIREC[(d_i + a[n]) % 4];
        }

        private int nextX(int x, char d)
        {
            switch (d)
            {
                case 'E':
                    return x + 1;
                case 'W':
                    return x - 1;
            }
            return x;
        }
        private int nextY(int y, char d)
        {
            switch (d)
            {
                case 'N':
                    return y-1;
                case 'S':
                    return y+1;
            }
            return y;
        }

        private char nextMasu(int x, int y, char d)
        {
            char n_block = ' ';
            x = nextX(x,d);
            y = nextY(y,d);
            if(x < w && x>= 0 && y<h && y>= 0) n_block = map[y][x];

            return n_block;
        }

        private  bool canMove(int x, int y, char d)
        {
            x = nextX(x, d);
            y = nextY(y, d);

            //if (!(map[y][x] == '.') && !(map[y][x] == 'X')) return false;
            
            //優先順
            char tmp;
            if(d == 'W')return true;
            if (x < w-1) { 
                tmp = map[y][ x + 1];
                if (tmp == 'W') return false;
            }

            if (d == 'S') return true;
            if (y > 0)
            {
                tmp = map[y - 1][ x];
                if (tmp == 'S') return false;
            }

            if (d == 'E') return true;
            if (x > 0) { 
                tmp = map[y][ x - 1];
                if (tmp == 'E') return false;
            }
            return true;
        }
        private string solve(int n,int m)
        {
            map = new char[m][];
            h = m;
            w = n;

            List<Player> plist = new List<Player>();
            for (int i = 0; i < h; i++)
            {
                string s = Console.ReadLine();
                map[i] = s.ToCharArray();

                for (int j = 0; j < w; j++)
                {
                    if (map[i][j] != '.' && map[i][j] != '#' && map[i][j] != 'X')
                    {
                        Player p = new Player(j, i);
                        plist.Add(p);
                    }
                }
            }

            int hoge=0 ;
            for (int time= 0; time < 180; time++)
            {
                //向き変更
                foreach (Player p in plist)
                {
                    p.move = false;
                    for (int j = 0; j <= 3; j++)
                    {
                        char d = rotate(map[p.y][p.x], j);

                        char next = nextMasu(p.x, p.y, d);
                        if (next == '.' || next == 'X')
                        {
                            p.move = true;
                            map[p.y][p.x] = d;
                            break;
                        }
                    }
                }
                foreach(Player p in plist){
                    if (!canMove(p.x, p.y, map[p.y][p.x]))
                    {
                        p.move = false;
                    }
                }
                //移動
                for (int j = plist.Count - 1; j >= 0; j--)
                {
                    Player p = plist[j];
                    if(p.move == false)continue;

                    char d = map[p.y][p.x];
                    int nx = nextX(p.x, d);
                    int ny = nextY(p.y, d);
                    char next = map[ny][nx];

                    map[p.y][p.x] = '.';
                    
                    if (next == 'X')
                    {//goal
                        plist.RemoveAt(j);
                    }
                    else
                    {
                        map[ny][nx] = d;
                        p.x = nx;
                        p.y = ny;
                    }
                }
                ////goalした人排除
                //for (int j = plist.Count - 1; j >= 0; j--)
                //{
                //    if (plist[j].goal)
                //    {
                //        map[plist[j].y][plist[j].x] = 'X';
                //        plist.RemoveAt(j);
                //    }
                //}
                hoge++;
// print();
                if (plist.Count == 0) break;
            }
            if (plist.Count > 0) return "NA";
            return (hoge).ToString();

        }

        private void print()
        {
            for (int i = 0; i < h; i++)
            {
                for (int j = 0; j < w; j++) Console.Write(map[i][j]);
                Console.WriteLine();
            }
        }
        static void Main(string[] args)
        {
            while (true)
            {
                string[] hoge = Console.ReadLine().Split(new char[] { ' ' });
                int n = int.Parse(hoge[0]);
                int m = int.Parse(hoge[1]);
                if (n == 0 && m== 0) break;

                Console.WriteLine(new Program().solve(n,m));
            }
        }
    }
}