 # Fernando-Soto's solution

## to Minesweeper in the F# Track

Published at Mar 15 2019 · 0 comments
Instructions
Test suite
Solution

Add the numbers to a minesweeper board.

Minesweeper is a popular game where the user has to find the mines using numeric hints that indicate how many mines are directly adjacent (horizontally, vertically, diagonally) to a square.

In this exercise you have to create some code that counts the number of mines adjacent to a square and transforms boards like this (where `*` indicates a mine):

``````+-----+
| * * |
|  *  |
|  *  |
|     |
+-----+
``````

into this:

``````+-----+
|1*3*1|
|13*31|
| 2*2 |
| 111 |
+-----+
``````

## Running the tests

To run the tests, run the command `dotnet test` from within the exercise directory.

## Further information

For more detailed information about the F# track, including how to get help if you're having trouble, please visit the exercism.io F# language page.

## Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

### MinesweeperTest.fs

``````// This file was auto-generated based on version 1.1.0 of the canonical data.

module MinesweeperTest

open FsUnit.Xunit
open Xunit

open Minesweeper

[<Fact>]
let ``No rows`` () =
let minefield: string list = []
let expected: string list = []
annotate minefield |> should equal expected

[<Fact(Skip = "Remove to run test")>]
let ``No columns`` () =
let minefield = [""]
let expected = [""]
annotate minefield |> should equal expected

[<Fact(Skip = "Remove to run test")>]
let ``No mines`` () =
let minefield =
[ "   ";
"   ";
"   " ]
let expected =
[ "   ";
"   ";
"   " ]
annotate minefield |> should equal expected

[<Fact(Skip = "Remove to run test")>]
let ``Minefield with only mines`` () =
let minefield =
[ "***";
"***";
"***" ]
let expected =
[ "***";
"***";
"***" ]
annotate minefield |> should equal expected

[<Fact(Skip = "Remove to run test")>]
let ``Mine surrounded by spaces`` () =
let minefield =
[ "   ";
" * ";
"   " ]
let expected =
[ "111";
"1*1";
"111" ]
annotate minefield |> should equal expected

[<Fact(Skip = "Remove to run test")>]
let ``Space surrounded by mines`` () =
let minefield =
[ "***";
"* *";
"***" ]
let expected =
[ "***";
"*8*";
"***" ]
annotate minefield |> should equal expected

[<Fact(Skip = "Remove to run test")>]
let ``Horizontal line`` () =
let minefield = [" * * "]
let expected = ["1*2*1"]
annotate minefield |> should equal expected

[<Fact(Skip = "Remove to run test")>]
let ``Horizontal line, mines at edges`` () =
let minefield = ["*   *"]
let expected = ["*1 1*"]
annotate minefield |> should equal expected

[<Fact(Skip = "Remove to run test")>]
let ``Vertical line`` () =
let minefield =
[ " ";
"*";
" ";
"*";
" " ]
let expected =
[ "1";
"*";
"2";
"*";
"1" ]
annotate minefield |> should equal expected

[<Fact(Skip = "Remove to run test")>]
let ``Vertical line, mines at edges`` () =
let minefield =
[ "*";
" ";
" ";
" ";
"*" ]
let expected =
[ "*";
"1";
" ";
"1";
"*" ]
annotate minefield |> should equal expected

[<Fact(Skip = "Remove to run test")>]
let ``Cross`` () =
let minefield =
[ "  *  ";
"  *  ";
"*****";
"  *  ";
"  *  " ]
let expected =
[ " 2*2 ";
"25*52";
"*****";
"25*52";
" 2*2 " ]
annotate minefield |> should equal expected

[<Fact(Skip = "Remove to run test")>]
let ``Large minefield`` () =
let minefield =
[ " *  * ";
"  *   ";
"    * ";
"   * *";
" *  * ";
"      " ]
let expected =
[ "1*22*1";
"12*322";
" 123*2";
"112*4*";
"1*22*2";
"111111" ]
annotate minefield |> should equal expected``````
``````﻿module Minesweeper

open System

// Transform List of String into an array of arrays
let private listElementsToArray input =
input |> Seq.map (fun l -> l |> Seq.toArray) |> Seq.toArray

// Return a List of tuples (row, column) index where no * is in and is on the board
let updateCells (board : char [][]) (rows : int) (cols : int) (tr: int, tc: int) =
let neighborCells = [-1, -1; -1, 0; -1, 1; 0, -1; 0, 1; 1, -1; 1, 0; 1, 1]

neighborCells
|> List.fold (fun acc (nr, nc) ->
if (nr + tr > -1 && nr + tr < rows) && (nc + tc > -1 && nc + tc < cols) then
[(nr + tr, nc + tc)] @ acc
else
acc
) ([] : (int*int) list)

let annotate (input : string list) =
match input with
| [] -> []
| _  ->
// Setup board and get row and column count and create a muteable to hold
// locations of mines
let board = listElementsToArray input
let rows = board.Length
let cols = board..Length
let mutable targets = []

// update location of mines
for row in [0 .. rows - 1] do
for col in [0 .. cols - 1] do
if board.[row].[col] = '*' then targets <- [row, col] @ targets

// Update board to indicate number of adjacent mines
targets
|> List.map (fun cell -> updateCells board rows cols cell)
|> List.concat
|> List.filter (fun (r, c) -> board.[r].[c] <> '*')
|> List.iter (fun (r, c) ->
if board.[r].[c] = ' ' then
board.[r].[c] <- '1'
else
board.[r].[c] <- char ((int board.[r].[c]) + 1)
)

// Transform array of arrays to a List of Strings
board
|> Array.map (fun (bd: char[]) -> String.Concat(bd))
|> Array.toList``````