Go: package main

import (
	"bufio"
	"os"
	"strconv"
	"strings"
	"fmt"
)

var scanner = bufio.NewScanner(os.Stdin)

type Point struct {
	x, y int
}

func main() {
	dx := []int{1, 0, -1, 0}
	dy := []int{0, -1, 0, 1}
	maze := make([][]rune, 30)
	for i := range maze {
		maze[i] = make([]rune, 30)
	}
	next := make([][]rune, 30)
	for i := range next {
		next[i] = make([]rune, 30)
	}
	check := make([][]int, 30)
	for i := range check {
		check[i] = make([]int, 30)
	}
	for scanner.Scan() {
		buf := strings.Split(scanner.Text(), " ")
		W, _ := strconv.Atoi(buf[0])
		H, _ := strconv.Atoi(buf[1])
		if W == 0 && H == 0 {
			break
		}
		for i := 0; i < H; i++ {
			scanner.Scan()
			buf_ := scanner.Text()
			for j, v := range buf_ {
				maze[i][j] = v
			}
		}
		man := 0
		for i := 0; i < H; i++ {
			for j := 0; j < H; j++ {
				if maze[i][j] != '.' && maze[i][j] != 'X' && maze[i][j] != '#' {
					switch maze[i][j] {
					case 'E':
						maze[i][j] = 0
						man++
					case 'N':
						maze[i][j] = 1
						man++
					case 'W':
						maze[i][j] = 2
						man++
					case 'S':
						maze[i][j] = 3
						man++
					}
				}
			}
		}
		ans := -1
		for t := 0; t <= 180; t++ {
			if man == 0 {
				ans = t
				break
			}
			for i := 0; i < H; i++ {
				for j := 0; j < W; j++ {
					check[i][j] = 0x7FFFFFFF
				}
			}
			for i := 0; i < H; i++ {
				for j := 0; j < W; j++ {
					if maze[i][j] > 3 {
						continue
					}
					l := (maze[i][j] + 3) % 4
					for k := 0; k < 4; k++ {
						y := i + dy[l]
						x := j + dx[l]
						if 0 <= y && y < H && 0 <= x && x < W && (maze[y][x] == '.' || maze[y][x] == 'X') {
							maze[i][j] = l
							check[y][x] = min(check[y][x], int((l+2)%4))
							break
						}
						l = (l + 1) % 4
					}
				}
			}
			for i := 0; i < H; i++ {
				for j := 0; j < W; j++ {
					next[i][j] = maze[i][j]
				}
			}
			for i := 0; i < H; i++ {
				for j := 0; j < W; j++ {
					if maze[i][j] > 3 {
						continue
					}
					y := i + dy[maze[i][j]]
					x := j + dx[maze[i][j]]
					if 0 <= y && y < H && 0 <= x && x < W && check[y][x] == int((maze[i][j]+2)%4) {
						if maze[y][x] == '.' {
							next[y][x] = maze[i][j]
						} else if maze[y][x] == 'X' {
							man--
						}
						next[i][j] = '.'
					}
				}
			}
			for i := 0; i < H; i++ {
				for j := 0; j < W; j++ {
					maze[i][j]=next[i][j]
				}
			}
		}
		if ^ans != 0 {
			fmt.Println(ans)
		} else {
			fmt.Println("NA")
		}
	}
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

Python: def print_map(maze):
    for i in range(len(maze)):
        row = ''.join(str(s) for s in maze[i])
        print(row.translate(str.maketrans('0123459', '.ENWSX#')))


def mapper(map_mapper):
    people_list = {1: [], 2: [], 3: [], 4: []}
    for i in range(len(map_mapper)):
        row = map_mapper[i].translate(str.maketrans('.ENWSX#', '0123459'))
        map_mapper[i] = list(map(int, list(row)))
        for j in range(len(map_mapper[i])):
            if 1 <= map_mapper[i][j] <= 4:
                people_list.get(map_mapper[i][j]).append((i, j))

    return map_mapper, people_list


def algorithm(maze, people):
    # 1: E, 2: N, 3: W, 4: S
    direct = {1: (0, 1), 2: (-1, 0), 3: (0, -1), 4: (1, 0)}
    move = {1: [4, 1, 2, 3],
            2: [1, 2, 3, 4],
            3: [2, 3, 4, 1],
            4: [3, 4, 1, 2]}

    people_bye = []
    people_enter = {1: [], 2: [], 3: [], 4: []}
    people_out = {1: [], 2: [], 3: [], 4: []}
    count = 0

    while (len(people.get(1)) > 0 or len(people.get(2)) > 0 or len(people.get(3)) > 0 or len(people.get(4)) > 0) and count < 180:
        for face in range(1, 5):
            for i in range(len(people.get(face))):
                x, y = people.get(face)[i]

                goes = move.get(maze[x][y])
                for way in goes:
                    m_x, m_y = direct.get(way)
                    if maze[x + m_x][y + m_y] == 0:
                        print('people', i, way)
                        people_out.get(face).append((x, y))
                        people_enter.get(way).append((x + m_x, y + m_y))
                        maze[x + m_x][y + m_y] = way
                        # leave the position
                        maze[x][y] = 0
                        break
                    elif maze[x + m_x][y + m_y] == 5:
                        people_bye.append(people.get(face)[i])
                        people_out.get(face).append((x, y))
                        # leave the position
                        maze[x][y] = 0
                        break

        # remove and add.
        for face in range(1, 5):
            for i in people_enter.get(face):
                people.get(face).append(i)
            for i in people_out.get(face):
                people.get(face).remove(i)
            people_enter.get(face).clear()
            people_out.get(face).clear()
        people_bye.clear()

        # print maze
        print_map(maze)
        count += 1
        print('??????:', count)
        print('-----------------------------')

    if count == 180 and len(people) > 0:
        return 'NA'
    return count


def input_case():
    while True:
        w, h = map(int, input().split())
        if w == 0 and h == 0:
            break
        input_map = [input() for _ in range(h)]

        input_map, people_list = mapper(input_map)
        print(algorithm(input_map, people_list))


if __name__ == '__main__':
    input_case()