anchor.diff:                 {Px+1, Py-1}, {Px+1, Py}, {Px+1, Py+1}], Dim).
   
   
  -neighbour_mines(#field{neighbours = Nbs}, Fields) ->
  +nbr_fun(mines) -> fun(#field{has_mine = true}) -> true; (_) -> false end;
  +nbr_fun(covers) -> fun(#field{status = covered}) -> true; (_) -> false end;
  +nbr_fun(uncovers) -> fun(#field{status = uncovered}) -> true; (_) -> false end;
  +nbr_fun(flags) -> fun(#field{status = flagged}) -> true; (_) -> false end.
  +
  +nbr(Attr, #field{neighbours = Nbs}, Fields) ->
  +    AttrFun = nbr_fun(Attr),
       NbFs = [array:get(Seq, Fields) || Seq <- Nbs],
  -    lists:foldl(fun(#field{is_mine = true}, Cnt) -> Cnt+1;
  -                   (#field{}, Cnt) -> Cnt
  +    lists:foldl(fun(F, Cnt) ->
  +                        case AttrFun(F) of
  +                            true -> Cnt+1;
  +                            false -> Cnt
  +                        end
                   end, 0, NbFs).
   
   
  
positive.code:     #board{dims = {3, 4}, n_mines = 5, fields = Fields} = Board,
      F5 = array:get(5, Fields),
      F6 = array:get(6, Fields),
      ?assertEqual(true, F5#field.is_mine),
      ?assertEqual(false, F6#field.is_mine),
      ?assertEqual(2, neighbour_mines(F5, Fields)),
      ?assertEqual(5, neighbour_mines(F6, Fields)).
  
  
  neighbours_test() ->
      %% Field seq numbers:
  
negative.code: new_game(Rows, Cols, Mines, MineSeqList) ->
      Dims = {Rows, Cols},
      Fields0 = array:new([{size, Rows*Cols}, {default, #field{}}]),
      Fields = array:map(fun(Seq, Field) ->
                                 Pos = seq2pos(Seq, Dims),
                                 HasMine = lists:member(Seq, MineSeqList),
                                 Field#field{has_mine = HasMine,
                                             neighbours = neighbours(Pos, Dims)}
                         end, Fields0),
      #board{dims = Dims, n_mines = Mines, n_hidden = Rows*Cols, fields = Fields}.
  
  %% step on a field, and thus expose it.
  %% - if it has a mine, you are dead and the game is over.
  %% - if it is empty, the number of surrounding mines will appear.
  %% - if there are no mines around you, this will recurse on the neighbours.
  %%
  %% return value: {Events, NewBoard} where
  %% - Events is a list of game events triggered by your move;
  %% - NewBoard is the updated board (in its eventual state).
  %%
  %% The idea is that the board display can be kept up-to-date based on
  %% the event stream alone.
  step(Pos, #board{dims = Dims} = Board) ->
      Seq = pos2seq(Pos, Dims),
      board_event(step, Seq, Board, []).
  
  %% toggle the flag on a covered field
  %% - if it is covered or questioned, it will become flagged.
  %% - if it is flagged, it will become covered.
  %% - if it is uncovered, nothing happens.
  flag({Px, Py}, Board) ->
      {[], Board}.
  
  %% toggle the question mark on a covered field
  %% - if it is covered or flagged, it will become questioned.
  %% - if it is questioned, it will become covered.
  %% - if it is uncovered, nothing happens.
  question({Px, Py}, Board) ->
      {[], Board}.
  
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %% Internal functions
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  board_event(step, Seq, #board{fields = Fields} = Board, Events) ->
      case array:get(Seq, Fields) of
          #field{has_mine = true, status = St} when St /= uncovered ->
              board_event(explode, Seq, Board, Events);
          #field{status = St} when St /= uncovered ->
              board_event(uncover, Seq, Board, Events)
      end;
  %% stepped on an empty field -- handle uncovering it (possibly recursive)
  board_event(uncover, Seq, #board{n_hidden = NH, fields = Fields} = Board,
              Events) ->
      F = array:get(Seq, Fields),
      case F#field.status of
          St when St == uncovered; St == exploded ->
              {Events, Board}; % break recursion
          _ ->
              NbrMines = nbr(mines, F, Fields),
              Fields1 = array:set(Seq, F#field{status=uncovered}, Fields),
              Events1 = [{uncover, Seq, {empty, NbrMines}} | Events],
              Board1 = Board#board{n_hidden = NH-1, fields = Fields1},
              case NbrMines of
                  0 -> % no mines nearby -- recursively uncover neighbours:
                      lists:foldl(fun(Nbr, {EvA,BoA}) ->
                                          board_event(uncover, Nbr, BoA, EvA)
                                  end, {Events1, Board1}, F#field.neighbours);
                  _ -> {Events1, Board1}
              end
      end;
  %% stepped on a field with a mine -- handle explosion and game over
  board_event(explode, Seq, #board{fields = Fields} = Board, Events) ->
      F = array:get(Seq, Fields),
      Fields1 = array:set(Seq, F#field{status=exploded}, Fields),
      Board1 = Board#board{fields = Fields1},
      Events1 = [{exploded, Seq} | Events],
      board_event(game_over, Seq, Board1, Events1);
  board_event(game_over, _Seq, #board{fields = Fields} = Board, Events) ->
      %% generate uncover event for all fields still covered
      %% {uncover, Seq, Type} where Type :: {empty, N} | mine
      UncoverEvents =
          array:foldl(fun(I, #field{status=St, has_mine=HasMine} = F, UEs)
                            when St == covered; St == flagged; St == questioned ->
                              Type = if HasMine -> mine;
                                        true -> {empty, nbr(mines, F, Fields)}
                                     end,
                              [{uncover, I, Type} | UEs];
                         (_I, #field{}, UEs) -> UEs
                      end, Events, Fields),
  
      %% TODO update fields' status to uncovered (not really needed
      %% since display will be driven by event stream)
  
      %% mark end of game with game_over event
      Events1 = [game_over | UncoverEvents],
      {Events1, Board#board{n_hidden = 0}}.
  
  
  generate_mines(Fields, N) when N >= Fields -> throw(badarg);
  