Category Archives: F#

F# Xunit with .NET Core 2.0, VsCode and Ionide – Run all tests with keyboard shortcut

A while back I wrote a post about F# unit testing in vscode with ionide

With the release of .NET Core 2.0 this week, I was keen to explore it and, in the process, I found a really nice work flow for running Xunit tests in VsCode. Using a VsCode task and the .NET core CLI, I can simply run all Xunit tests with one simple keyboard shortcut. There’s a few steps to get it set up but really its very quick to set up and, once you do it once, its quicker for any subsequent solutions that you use it on.

To show this in action, I went through a set up of a new solution using .NET Core 2.0 today and documented all my steps below. Hopefully this helps others to get a nice work flow set up for their F# .NET Core 2.0 solutions.

This was done on a Windows 10 OS but the steps should be easily transferable to other platforms.

Firstly, my solution is called XunitTestDemo and the root directory that I am working from is also called XunitTestDemo.

So, create a new directory called XunitTestDemo and go to that directory in the command line.
Run the following commands.

dotnet new classlib -lang f# -o TestDemo.Core
dotnet new xunit -lang f# -o TestDemo.Tests
cd TestDemo.Tests
dotnet add reference ..\TestDemo.Core\TestDemo.Core.fsproj
code ..\

These set up a test project called TestDemo.Tests and a project for housing production code called TestDemo.Core. We also have now set up a reference from TestDemo.Tests to TestDemo.Core and opened VsCode in our XunitTestDemo directory.

In Vs Code, follow the steps below to create a new directory called .vscode

Next go into TestDemo.Core.fsproj. I found a slight issue with .NET Core 2.0 classlib projects in F# which means that the FsAutoComplete doesn’t work properly.This isn’t an issue with Ionide but, rather, other upstream services that it uses.
You can get more information about this here
To work around this, I had to change the TargetFramework in TestDemo.Core.fsproj to be netcoreapp2.0 as in the steps below.


With this done, lets add an F# module that we can later write a test for. Go into Library.fs and replace its contents with:

module TestDemo.Core.Calculator

let add x y = x + y

Now run the following in the command line from the XunitTestDemo\TestDemo.Core directory.

\TestDemo.Core>dotnet restore
dotnet build

And the same from the XunitTestDemo\TestDemo.Tests directory.

\TestDemo.Tests>dotnet restore
dotnet build

Back in VsCode reload the window


Now lets write a test that will fail. Go into Tests.fs in the TestDemo.Tests project and replace its contents with below:

module TestDemo.Tests.CalculatorTest
open System
open Xunit
open TestDemo.Core

[]
let ``test add`` () =
    Assert.Equal(5, Calculator.add 3 10)

Now we need to set up our VsCode test task. So, create a file called tasks.json in the .vscode folder that you created earlier.

Add the below content to it:

{
    "version": "2.0.0",
    "tasks": [
        {
            "taskName": "Tests",
            "command": "dotnet",
            "type": "shell",
            "args": [
                "test"
            ],
            "presentation": {
                "reveal": "silent"
            },
            "problemMatcher": "$msCompile",
            "group": {
                "kind": "test",
                "isDefault": true
            }
        }
    ]
}

This task calls out to .NET Core 2.0 CLI to run our tests. The above configuration also makes it the default testing task for our solution. (“isDefault”: true)

To make things easier, lets create a keyboard shortcut to run the default testing task. So go into Keyboard Shortcuts preferences:

Click into keybindings.json and add the following custom key binding.

.....
{   "key": "ctrl+shift+r",              
    "command": "workbench.action.tasks.test" 
}
...

Save everything and now ctrl+shift+r will run the default testing task which we have configured to be our testing task earlier which will run all tests in our solution.

In order for the .NET CORE 2.0 CLI to look for and run all our xunit tests including future ones that you may add, we need to create a Solution and add our two projects to it. This is done with the following commands, again from the XunitTestDemo directory on the command line.

XunitTestDemo>dotnet new sln
XunitTestDemo>dotnet sln XunitTestDemo.sln add TestDemo.Core\TestDemo.Core.fsproj
XunitTestDemo>dotnet sln XunitTestDemo.sln add TestDemo.Tests\TestDemo.Tests.fsproj

Back in VsCode, reload the window again as before from the command palette, ctrl+shift+p


Open up the integrated terminal that will show our test results.

Now go back into Tests.fs and hit ctrl+shift+r to run all our tests. This command can actually be run from anywhere within the VsCode instance that is open for our solution.

Our test will be discovered and run and we can see the results in the integrated terminal.

Lets fix our broken failing test so it is asserting the correct result – not the correct TDD approach but it serves as an example.

 Assert.Equal(13, Calculator.add 3 10)

Then without doing any building our reloading of the window or anything, we can hit ctrl+shift+r again and see our successful test run in the integrated terminal.

We are now set up for a nice work flow to run our tests with ease as we make changes.

Two Tetromino Tetris with Fable and F#

In my last post, I talked about my early adventures Fable and building a memory tiles game.

Recently I have been exploring Fable further and, in particular, using it to interact with the Javascript canvas API. I’ve been wanting to try out building a version of Tetris for a while now. I used to love playing it on the Gameboy many years ago. Fable afforded me the perfect tool to build this game in the beautiful language of F#.

There is a video snippet above of my implemented game in action. This blog won’t go into every detail of the code as it is available here but I wanted to go through a few code snippets here that may help other people looking to build a game involving game animation frames and using the canvas API with Fable and F#.

What’s a tetromino and why two tetrominoes and not the full thing?

A tetromino is the name given to each of the shapes in the Tetris game. Each tetromino also has a number or rotations that it can go through. There are more details about Tetris tetrominoes here.

I think of this version as a version 1. I wanted to get as much of a fully featured game implemented as I could in a pretty short time frame – while I had some summer vacation time. I hope to return to this at some point and add more shapes and also improve the rotation algorithm – unlike the original game, my rotation algorithm simply prevents rotations when blocks are in the way although it does handle wall kicks. I chose the I-Block along with its rotations and the T-Block along with its rotations as the two tetrominoes that I would use in this initial Tetris implementation.

The domain modelling

I modeled the gameboard as a map of row indexes to rows with each row itself being a map of the block left X position indexes to blocks. Blocks are the primitives that tetrominoes are built from. I wanted to capture the states that a gameboard can be in using the F# type system. A gameboard that is in a resting state has no moving tetromino and a gameboard in motion has a moving tetromino. The main game engine processes these gameboard states so I made them distinct using a Discriminated Union – a DU.

60   type LeftBlockPosition = float 
61    
.......
65   and RowData = Map<LeftBlockPosition,Block> 
66    
67   type RowBottomPosition = float 
68    
69   type GameboardInMotion = { 
70       Height : float 
71       Width : float 
72       BlockSize : float 
73       MovingTetromino : Tetromino 
74       Rows : Map<RowBottomPosition, RowData> 
75   } 
76    
77   type RestingGameboard = { 
78       Height : float 
79       Width : float 
80       BlockSize : float 
81       PlacedTetromino : Tetromino 
82       Rows : Map<RowBottomPosition, RowData> 
83   } 
84    
85   type Gameboard =  
86   | GameboardInMotion of GameboardInMotion 
87   | RestingGameboard of RestingGameboard 
88    

A block is modeled as a an F# record.

3    type Block = { 
4        BottomX : float 
5        BottomY : float 
6        Color : string 
7    } 

The tetrominoes are modelled as a DU also with each case representing a tetromino rotated in a particular direction. Each tetromino also has tetromino detail about the rows of blocks that it comprises of.

19   type TetrominoRow = { Blocks : Block list } 
...........
36   type TetrominoDetail = { TetrominoRows : TetrominoRow list } 
37    
38   type Tetromino =  
39   | StraightUp of TetrominoDetail 
40   | StraightRight of TetrominoDetail 
41   | StraightDown of TetrominoDetail 
42   | StraightLeft of TetrominoDetail 
43   | TShapeUp of TetrominoDetail 
44   | TShapeRight of TetrominoDetail 
45   | TShapeDown of TetrominoDetail 
46   | TShapeLeft of TetrominoDetail 

Valid key presses are also modeled using a DU and using designing with capabilities to prevent the creation of an invalid key press. I learned about designing with capabilities from Scott Wlaschin – Designing with Capabilities and from reading Scott’s new book:
Domain Modeling Made Functional

89   type KeyCode = float 
90    
91   type GameControl =  
92       | Up 
93       | Left 
94       | Right 
95    
96   type ValidKeyPress = private ValidKeyPress of GameControl * KeyCode  
97    
98   let (|ValidKeyPress|) validKeyPress =  
99       match validKeyPress with  
100      | ValidKeyPress(control,keyCode) -> ValidKeyPress (control, keyCode) 
101   
102  module ValidKeyPress =  
103       
104      let toValidKeyPress keyCode = 
105          match keyCode with 
106          | 37. -> Some <| ValidKeyPress (Left, 37.) 
107          | 38. -> Some <| ValidKeyPress (Up, 38.) 
108          | 39. -> Some <| ValidKeyPress (Right, 39.) 
109          | _ -> None

Working with the canvas API

The Fable.Import namespace provides a thin wrapper over the Javascript DOM API.

I get a reference to my actual canvas div with the following:

9    let tetrisView = Browser.document.getElementById("tetris-view") :?> Browser.HTMLCanvasElement 
10   let ctx = tetrisView.getContext_2d() 

To render rows of blocks, I used fillRect as follows:

27       let renderRow blockSize (blocks:Map<LeftBlockPosition,Block>) =  
28           blocks |> Map.toSeq |> Seq.map snd |> Seq.iter (fun block ->  
29               ctx.fillStyle <- U3.Case1 block.Color 
30               ctx.fillRect(block.BottomX, block.BottomY - blockSize, blockSize, blockSize)) 

To clear the canvas area before each re-render of the gameboard, I used clearRect:

 ctx.clearRect(0., 0., tetrisView.width, tetrisView.height) 

Getting the game in motion!

Using .Net events and also the Javascript interval API (wrapped nicely by Fable), I was able to set up a repeating game frame clock. So, each time the time interval passes, an event is triggered causing a new gameboard to be evaluated from the current gameboard and from any user game control input and this new game board is then rendered.

46   let frameChangeEvent =  new Event<Gameboard>() 
47    
48   let mutable private frameClockId = 0. 
49    
50   let startFrameClock() =  
51       frameClockId <- Browser.window.setInterval((fun() ->  
52               match lastRenderedGameBoard with  
53               | GameboardInMotion _ 
54               | RestingGameboard _ -> frameChangeEvent.Trigger lastRenderedGameBoard 
55               )  
56           , 150.) 

I handle user input in a separate UserGameController module using the wrapper that Fable gives over DOM event handling:

1    module Tetris.UserGameController 
2     
3    open Fable.Core 
4    open Fable.Import 
5    open Tetris.Definitions 
6     
7    Node.require.Invoke("core-js") |> ignore 
8     
9    let private keyPressed= ref (None:ValidKeyPress option) 
10    
11   let private handleKeyDown keyCode =  
12       match ValidKeyPress.toValidKeyPress keyCode with 
13       | Some (ValidKeyPress _ as vkp) -> 
14           keyPressed := Some vkp 
15       | None -> () 
16    
17   let private handleKeyUp keyCode =  
18       match !keyPressed with 
19       | Some (ValidKeyPress(_, currentlyPressed)) when keyCode = currentlyPressed ->  
20           keyPressed := None 
21       | _ -> () 
22     
23     
24   Browser.window.addEventListener_keydown (fun e -> handleKeyDown e.keyCode :> obj) 
25   Browser.window.addEventListener_keyup (fun e -> handleKeyUp e.keyCode :> obj) 
26    
27   let getKeyPressed() = !keyPressed 
28           

The game engine

The game engine is essentially a state machine. From the gameboard it is given and the current user input (if any), it works out what the next gameboard should be. There is a fair bit of logic in there around things like:
– whether a rotation is allowed,
– what the next rotation is for the current tetromino,
– whether the tetromino can move left or right,
– whether the tetromino should rest on blocks below
etc.

With the domain modeled using the F# type system and immutable DUs and records, these transitions became simpler to reason about. As an example, after it is determined if a rotation is possible (if the up arrow is currently pressed), the engine works out which way the tetromino can move. I created what I called a TransitionReferee for this. This is somewhat verbose but I wanted the logic and rules to be self documenting as much as possible. The snippet from the TransitionReferee is below to give an example of what I mean.

21   module TransitionReferee =  
22    
23       type RefereeDecision =  
24           | MoveHorizontallyAndVertically of GameboardInMotion 
25           | MoveVerticallyOnly of GameboardInMotion 
26           | MoveVerticallyOnlyAndRestOnBottom of GameboardInMotion 
27           | MoveVerticallyOnlyAndRestOnBlockBelow of GameboardInMotion 
28           | MoveAndRestOnBlockBelow of GameboardInMotion 
29           | MoveAndRestOnBottom of GameboardInMotion 
30           | CheckForCompletedRowsAndReleaseAnotherBlock of RestingGameboard 
31            
32       let blocksOverlapHorizontally block1XPos block2XPos blockSize = 
33           block1XPos > block2XPos - blockSize && block1XPos < block2XPos + blockSize 
34        
35       let tetrominoRowOverlapsWithExistingBlocks (horizontalTransitionDirection:HorizontalTransitionDirection) blockSize (tetrominoRow:TetrominoRow) row =  
36            
37           tetrominoRow.Blocks 
38           |> List.exists (fun tetrominoBlock -> 
39               row  
40               |> Map.exists (fun existingX  _ ->  
41                   blocksOverlapHorizontally existingX (tetrominoBlock |> nextXPosition horizontalTransitionDirection) blockSize)) 
42    
43       let otherRowsInRangeContainingBlocksInTheWay direction (gameboard:GameboardInMotion)  =  
44           //compare gameboard rows when all tetromino blocks have been removed 
45           gameboard.MovingTetromino.TetrominoRows 
46           |> List.fold (fun gameboardRows tetrominoRow -> 
47                gameboardRows 
48                |> Map.tryFind tetrominoRow.BottomY  
49                |> Option.map (fun gameboardRow ->  
50                   tetrominoRow.Blocks 
51                   |> List.fold (fun row b -> row |> Map.remove b.BottomX) gameboardRow) 
52                |> function | Some gameboardRowWithTetrominoBlocksRemoved -> gameboardRows |> Map.add tetrominoRow.BottomY gameboardRowWithTetrominoBlocksRemoved | None -> gameboardRows 
53           ) gameboard.Rows 
54           |> fun gameboardRows -> 
55               gameboardRows 
56               |> Map.toSeq 
57               |> Seq.exists (fun (rowY, gameboardRow) -> 
58                   gameboard.MovingTetromino.TetrominoRows  
59                   |> Seq.exists (fun tetrominoRow ->  
60                       (rowY > ((tetrominoRow.TopY gameboard.BlockSize) + transitionDistance) &&  
61                        rowY < (tetrominoRow.BottomY + transitionDistance) + (tetrominoRow.Height gameboard.BlockSize) && 
62                        tetrominoRowOverlapsWithExistingBlocks direction gameboard.BlockSize tetrominoRow gameboardRow))) 
63    
64       let decideTransition (direction:HorizontalTransitionDirection) (gameboard:Gameboard) =  
65           match gameboard with 
66           | GameboardInMotion gameboard -> 
67               let otherRowsInRangeContainingBlocksInTheWay direction  = otherRowsInRangeContainingBlocksInTheWay direction gameboard                     
68                
69               let tetrominoShouldMoveToRestOnBlocksBelow direction (gameboard:GameboardInMotion) =  
70                   gameboard.MovingTetromino.TetrominoRows 
71                   |> Seq.exists (fun tetrominoRow -> 
72                       gameboard.Rows 
73                       |> Map.tryFind (tetrominoRow.BottomY + transitionDistance + gameboard.BlockSize)  
74                       |> Option.map (fun row ->  
75                           tetrominoRowOverlapsWithExistingBlocks direction gameboard.BlockSize tetrominoRow row)  
76                       |> function | Some b -> b | None -> false 
77                   ) 
78                    
79               if otherRowsInRangeContainingBlocksInTheWay direction then 
80                   if (gameboard.MovingTetromino.TetrominoRows.[0].BottomY + transitionDistance) = gameboard.Height then  
81                       MoveVerticallyOnlyAndRestOnBottom gameboard 
82                   elif tetrominoShouldMoveToRestOnBlocksBelow NoHorizontalTransition gameboard then 
83                           MoveVerticallyOnlyAndRestOnBlockBelow gameboard 
84                   else MoveVerticallyOnly gameboard 
85               else  
86                   if (gameboard.MovingTetromino.TetrominoRows.[0].BottomY + transitionDistance) = gameboard.Height then  
87                       MoveAndRestOnBottom gameboard 
88                   elif tetrominoShouldMoveToRestOnBlocksBelow direction gameboard then     
89                       MoveAndRestOnBlockBelow gameboard 
90                   else MoveHorizontallyAndVertically gameboard 
91                    
92           | RestingGameboard gameboard -> CheckForCompletedRowsAndReleaseAnotherBlock gameboard 

Conclusion

I hope the code snippets that I have shown here can be of some help to others who are exploring Fable. The full source code is available here:
Also, the current version of this Two Tetromino Tetris game can be played here.

Early Fable Adventures – Building A Memory Tiles Game

Getting aquianted with fable

Just about a month ago, I had the great pleasure of attending F# eXchange 2017 in London. It was 2 days of wonderful F# indulgence with fantastic talks and workshops. It was also a great experience meeting some of the people who have pretty much been virtual mentors to me on my F# journey like Kit Eason and Scott Wlaschin. I did Kit’s pluralsight F# courses and Scott’s fsharp for fun and profit site is a constant source of learning for me so to get chatting with these guys in person was really cool.

Among all of these great talks and workshops was a talk by Alfonso García-Caro, about his Fable compiler. This is an F# to javascript compiler that hooks in really well with the javascript ecosystem. I’m lucky that in my job I am coding in F# across the full stack currently using websharper for our F# to javascript needs. So Alfonso’s talk about Fable really caught my attention. I couldn’t wait to get a bit of free time to dive in and try it out.

Getting up and running with Fable was very quick and easy thanks to this extremely helpful blog post by Krzysztof Cieslak. I started by simply trying out simple dom event handling. Out of the box, Fable has an API that appears to be a light F# wrapper around the javascript dom API.
This is accessed simply with

open Fable.Import

From here, the dom is at your finger tips through the eyes of F# through the module Fable.Import.Browser.

A little game to get my teeth into Fable

After playing around with some dom operations through Fable, I wanted something a bit more substantial to get my teeth into. Recently I was playing this common memory game with my 3 year old daughter. Its a game where you have a grid of cards with pictures on them where every picture will appear on exactly 2 cards. You lay them out randomly upside down. Then you take turns turning 2 cards over at a time. If you get matching pictures, you keep the cards but if there is no match, you turn the cards upside down again. At the end, the player with the most mathed cards wins.

I thought this would be a great game to implement with Fable so I could get started properly with this wonderful F# to javascript compiler. I simplified the game for my first version and built just a one player game. You get a grid of blacked out tiles which have hidden colors where every color will exist twice on the grid. Then you click (or tap if on a mobile device) on 2 tiles to uncover their colors. If they match, the tiles stay open permently until you start a fresh game. If they are not a match, the tiles are blacked out again the next time you click a new tile. This first version was enough to get me building something with Fable. In future versions, I plan to make it a bit more interesting by adding time challenges and levels with bigger grids among other ideas.

Dom operations through Fable to get up and running

There are a few basic things that I wanted to do with the dom for my game interaction. The following were enough for the first version of the game.

Creating a dom element with attributes

let tileDiv = Browser.document.createElement("div")
             tileDiv.className <- "col-3"
             let bc = match tile.Status with
                      | UnMatched -> tile.CoverColor
                      | AttemptingMatch -> tile.HiddenColor
                      | Matched -> tile.HiddenColor
             tileDiv.style.backgroundColor <- bc
             tileDiv.style.border <- "white solid 4px"

In the above, the Browser module is coming from the earlier Fable.Import. From this module, there is a wealth of dom related functions closely matching the standard javascript document API. Here I’m creating a div, setting its class name and a couple other properties including its border and also its background color which is a result of a pattern match to check the status of the corresponding tile in the backing model.

Adding a click event

Adding events is straight forward too. I found if I got stuck because of not knowing the function or type to use from Fable.Import.Browser, I could just look up the corresponding javascript dom function/element on the Mozilla Dom API reference and the corresponding Fable module/type/function was named similarly.
For the memory tiles game, I needed a way to add a click event to a, “Start Fresh Game” button to refresh the grid with new randomized tiles. This is shown below:

let startNewGameButton = Browser.document.createElement("button")
      startNewGameButton.addEventListener_click(fun _ -> startNewGameCallback() :> obj)
      startNewGameButton.innerText <- "Start Fresh Game"
      gameContainer.appendChild startNewGameButton |> ignore

Here, I create the button to start a new game of randomized tiles. I then add a click event which can take a regular F# function as a parameter. Here I’m passing a lambda which, when executed, will call a function called startNewGameCallback. The block of code shown here exists inside a render function in my View module and this render function takes the startNewGameCallback function as a parameter. The full source code for this is on my github MemoryTiles.fsx

I use the same Fable addEventListener_click function for handling the click event on each tile as shown below.

let eventHandler r c d = Func<Browser.MouseEvent, obj>(fun _ -> tileClickCallback r c gameBoard :> obj)
        tileDiv.addEventListener_click(eventHandler rowIndex cIndex tileDiv)

This takes a lambda wrapping another callback which has been passed to the render function in my View module. This eventually calls back to the main driver of the game – the tileClick function in my Controller module, but first let me just show the data modelling from the Model module to put this tileClick function in context.

F# typing goodness with Fable

Fable supports the standard F# data modelling constructs bringing us the F# type safety that we love so much!
For the games’ backing model, I used standard F# records and disciminated unions to represent the immutable game board which serves as a point in time state to render a point in time view and also to enable the generation of a another game board depending on user input and the value of its tiles. A tile itself is modelled as a record and the status of a tile along with the the current selection of tiles are modelled as DUs. So even though this is a game running as javascript, I have still been able to use F# types and F# immutability to express the domain and behaviour of the game. This is shown below. I added a GameBoard helper module for the state transistions of updating tiles and the selection. There is some localized mutability within the updateTile function but the function is still pure with an immutable game board going in and another one coming out. The updateSelected is also returning a new immutable game board.

type GameBoard = {
    Selection : Selection
    Board : Tile list list
}
and Tile = {
    Row : int
    Col : int
    HiddenColor : string
    CoverColor : string
    Status : TileStatus
}
and TileStatus = UnMatched | AttemptingMatch | Matched
and Selection = NoneSelected | OneSelected of Tile | TwoSelected of Tile * Tile
 
module GameBoard = 
    let updateTile r c t gb = 
        let updatedRow = gb.Board.[r] |> List.toArray |> (fun arr -> arr.[c] <- t; arr) |> List.ofArray
        {
            gb with
                Board = gb.Board |> List.toArray |> (fun arr -> arr.[r] <- updatedRow; arr) |> List.ofArray
        }
 
    let updateSelected s gb = { gb with Selection = s}

Using standard .Net events for to trigger view rendering

.Net event handling is one of my favourite features of the .Net platform and, in particular, the way it is implemented in F#. Fable allows us to use standard .Net event triggering and handling. I designed the game using a version of the model, view, controller pattern. I wanted to keep my view decoupled from the model but I still needed a way for it to be rendered whenever the game board changed. I also wanted it to remain as decoupled as possible from the controller module. The controller module passes the main engine of the game, its tileClick function, as a function parameter to the view but the view doesn’t know anything about its implementation. This is similar for the callback to start a fresh game. In order for the view to be rendered and re-rendered, I set up a an event in the in the Model module as follows.

let modelChangeEvent = (new Event<GameBoard>())

In the Controller module, there is a an initialise function which starts everything off. It publishs an observation to the above event and adds a listener, which takes a game board as a parameter and which will call render on the View whenever the a modelChangeEvent is triggered.
A startGame() function, called by initialise, simply triggers a modelChangeEvent to trigger the initial rendering of the game.

let startGame() = modelChangeEvent.Trigger (Model.generateRandomModel 4)
 
let initialise() = 
    Model.modelChangeEvent.Publish.Add(fun gameBoard -> View.render tileClick startGame gameBoard)
    startGame()

Main game logic with F# pattern matching

The main game logic is in the tileClick function of the Controller module. It receives a game board and a row and column for the clicked tile and, based on these, it determines a new game board to be created and triggers the modelChangeEvent so that the View.render function is called to re-render with the new game state.For some cases, no event is triggered and the view is not re-rendered e.g. if the same tile is clicked multiple times in succession. Standard F# pattern matching can be used here and the full function is below.

let tileClick tileRow tileCol (gameBoard: GameBoard) = 
    let board = gameBoard.Board
    let tile = board.[tileRow].[tileCol] 
    let lastSelection = gameBoard.Selection
    if tile.Status = Matched then ()
    else
        match lastSelection with
        | TwoSelected(t1, t2) when t1.Status = Matched && t2.Status = Matched && tile <> t1 && tile <> t2->
            gameBoard
            |> GameBoard.updateTile tile.Row tile.Col { tile with Status = AttemptingMatch }
            |> GameBoard.updateSelected (OneSelected { tile with Status = AttemptingMatch })
            |> modelChangeEvent.Trigger
        | TwoSelected(t1, t2) when t1.Status = Matched && tile <> t1 && tile <> t2 -> 
            gameBoard
            |> GameBoard.updateTile tile.Row tile.Col { tile with Status = AttemptingMatch }
            |> GameBoard.updateTile t2.Row t2.Col { t2 with Status = UnMatched }
            |> GameBoard.updateSelected (OneSelected { tile with Status = AttemptingMatch })
            |> modelChangeEvent.Trigger
        | TwoSelected(t1, t2) when t2.Status = Matched && tile <> t1 && tile <> t2 -> 
            gameBoard
            |> GameBoard.updateTile tile.Row tile.Col { tile with Status = AttemptingMatch }
            |> GameBoard.updateTile t1.Row t1.Col { t1 with Status = UnMatched }
            |> GameBoard.updateSelected (OneSelected ({ tile with Status = AttemptingMatch }))
            |> modelChangeEvent.Trigger
        | TwoSelected(t1, t2) when tile <> t1 && tile <> t2 -> 
            gameBoard 
            |> GameBoard.updateTile t1.Row t1.Col { t1 with Status = UnMatched }
            |> GameBoard.updateTile t2.Row t2.Col { t2 with Status = UnMatched }
            |> GameBoard.updateTile tile.Row tile.Col { tile with Status = AttemptingMatch }
            |> GameBoard.updateSelected (OneSelected ({ tile with Status = AttemptingMatch }))
            |> modelChangeEvent.Trigger           
        | OneSelected t1 when t1.HiddenColor = tile.HiddenColor && tile <> t1 -> 
            gameBoard
            |> GameBoard.updateTile t1.Row t1.Col { t1 with Status = Matched }
            |> GameBoard.updateTile tile.Row tile.Col { tile with Status = Matched }              
            |> GameBoard.updateSelected (TwoSelected ({ t1 with Status = Matched },{ tile with Status = Matched }))
            |> modelChangeEvent.Trigger
        | OneSelected t1 when tile <> t1 -> 
            gameBoard
            |> GameBoard.updateTile tile.Row tile.Col { tile with Status = AttemptingMatch }              
            |> GameBoard.updateSelected (TwoSelected (t1, { tile with Status = AttemptingMatch }))
            |> modelChangeEvent.Trigger 
        | NoneSelected when tile.Status <> Matched -> 
            gameBoard
            |> GameBoard.updateTile tile.Row tile.Col { tile with Status = AttemptingMatch }              
            |> GameBoard.updateSelected (OneSelected ({ tile with Status = AttemptingMatch }))
            |> modelChangeEvent.Trigger
        | _ -> ()

Conclusion

I had loads of fun making this game and definitely want to add more to it. My daughter has been playing away with it and having great fun!
I’ll definitely be continuing on my Fable journey.
The full source code for this game is on my github:
MemoryTiles.fsx
Also the current version of the game can be played here

F# Unit Testing Simplified – Expecto with Visual Studio Code

This post is a slightly shorter follow on post to my last one, F# Has Won Me Over: Coming to .Net World from Outside .Net

In that post, I showed how to set up a basic F# development workflow using Visual Studio Code. It probably seemed a little overkill just to get simple tests up and running.I’m glad I took this longer approach though as, coming into .NET world, it made me aware of how the tools and F# projects fit together under the hood – something that wouldn’t be as clear if I went the all out IDE approach.

Since publishing that blog, I have gotten a lot of really helpful feedback from others in the F# community and I have taken a look at an F# testing tool called Expecto

The Ionide plugin for Visual Studio Code has a really nice integration for running tests using Expecto – it’s a whole lot simpler then the workflow I showed in my last post!

Following from my last post, lets add a different test project to test the MusicLibrary project and we’ll use Expecto this time to run our test.
Again, I’m running Visual Studio Code on Mac OSX in this example but the steps should be more or less the same for other operating systems.

So, back in Visual Studio Code, type cmd-shift-p to open the command palette
Type F# and select F#:New Project

Choose a console as this will give us a main entry point for Expecto to run tests.

You will be prompted for the name of the project directory.

Lets just call it MusicLibraryExpectoTests

You will then be prompted for the name of the project.

Again, MusicLibraryExpectoTests will be grand.

Now we need to add our Expecto dependencies with Paket.

So open up the newly creted MusicLibraryExpectoTests directory and open MusicLibraryExpectoTests.fsproj

Open the command palette again, cmd-shift-p
Type Paket and select Paket:Add NuGet Package (to current project)

Then type Expecto and Enter.

You will see, info in the Paket output terminal.

Afterwards, you should be able to search Expecto in the MusicLibraryExpectoTests.fsproj file and find something like

   
 ..\..\packages\Expecto\lib\net40\Expecto.dll
               

Repeat for
Expecto.BenchmarkDotNet
Expecto.FsCheck

After all this, our paket.references file within the MusicLibraryExpectoTests project should contain

FSharp.Core
Expecto
Expecto.BenchmarkDotNet
Expecto.FsCheck

Lets try out a hello world expecto test. So, open up MusicLibraryExpectoTests.fs which will have automatically been created for us when we created our MusicLibraryExpectoTests project.

Replace the contents of that file with the following:

module MusicLibraryExpectoTests

open Expecto

[<Tests>]
let tests =
  testCase "yes" <| fun () ->
    let subject = "Hello World"
    Expect.equal subject "Hello world"
                 "The strings should equal"


[<EntryPoint>]
let main args =
  runTestsInAssembly defaultConfig args

and save.
Here we have added one test case and a main function as an entry point for expecto to run our tests.
We can easily run our test simply as follows:
Open command palette, cmd-shift-p
Type Ex and choose Expecto:Run

In the expecto output terminal, we can see our failing test!

We can fix our failing test by changing that ‘w’ to upper case so our MusicLibraryExpectoTests.fs becomes:

module MusicLibraryExpectoTests

open Expecto

[<Tests>]
let tests =
  testCase "yes" <| fun () ->
    let subject = "Hello World"
    Expect.equal subject "Hello World"
                 "The strings should equal"

[<EntryPoint>]
let main args =
  runTestsInAssembly defaultConfig args

This time to run the tests, lets just use a shortcut, ctrl-f6
Now, our test passes and you should see this along with other output in the Expecto terminal output in Visual Studio Code:

[21:28:12 INF] EXPECTO?! Summary...
Passed:  1
	yes 
Ignored: 0
	Failed:  0
	Errored: 0

Now, we can use Expecto to test our addSongToLibrary function from the MusicLibrary project that I went through in my last post.
We need to link our MusicLibraryExpectoTests project to this library first. So, open the MusicLibraryExpectoTests.fsproj file again.

Then we can use the command palette, cmd-shift-p to add a project reference.

Choose MusicLibraryExpectoTests for the project to edit

and MusicLibrary as the project to reference

Your MusicLibraryExpectoTests.fsproj should now contain something like

    
ProjectReference Include="../../MusicLibrary/MusicLibrary/MusicLibrary.fsproj"

We can add our test for addSongToLibrary to MusicLibraryExpectoTests.fs as follows:

module MusicLibraryExpectoTests

open Expecto
open MusicLibrary

[<Tests>]
let tests =
  testList "test group" [
    testCase "yes" <| fun _ ->
        let subject = "Hello World"
        Expect.equal subject "Hello World"
                    "The strings should equal"

    testCase "addSongToLibrary adds song to library" <| fun _ ->
        let expected = ["Sir Duke";"Superstition"]   
        Expect.equal expected (addSongToLibrary ["Superstition"] "Sir Duke")
                    "The library list should contain the new song"
    ]

[<EntryPoint>]
let main args =
  runTestsInAssembly defaultConfig args

Now, we can run the tests with ctrl-F6

And in the Expecto terminal output in Visual Studio code,
you should see something like this along with other output

Passed:  2
	test group/yes ....
       ....
	test group/addSongToLibrary adds song to library [/Users/tom/Dropbox/software-
Ignored: 0
	Failed:  0
	Errored: 0

Conclusion

There is a lot more you can do with Expecto. I have just scratched the surface here but, even with the basics here, you can very quickly create and run test cases from within Visual Studio Code. It’s definitely a tool that I will be using a lot!

F# Has Won Me Over: Coming to .Net World from Outside .Net

F# is a language that was sitting in the corner calling to me for a long time tempting me to go take a look at it. I watched Scott Wlaschin’s fantastic talk on Functional Programming Design Patterns some time ago. This talk is a walk through of common FP design patterns with the example code being in F#. Scott put together this talk so well that it is not a blocker to getting the most from the talk if you don’t have any previous knowledge of F#. At the same time, coming from mostly programming in Scala professionally, I couldn’t help but admire the beauty of the F# code in his examples. So I had a quick look further at some F# code out there. Things like a simple syntax using whitespace, automatic currying, nice concise representations of Algebraic Data Types caught my eye immediately.

Over the Christmas holidays I dived into F# by taking courses on FSharp TV and by going through content from Scott’s wonderful blog Fsharp For Fun And Profit.

F# has quickly become my favourite language to code in along with Haskell. Along the way though, there were some stumbling blocks getting used to the .Net world. Most of these could have been avoided if I just used the Xamarin Studio IDE. However, I’m glad I didn’t and took a little pain along the way as it made be explore the .Net and F# ecosystem. I did start to use Visual Studio Code which is really a text editor with a load of great plugins out there for different languages. Its lightweight enough that you still have to find out what’s happening under the hood a bit with your F#  .Net projects but, at the same, it does make things like creating projects with common templates, building and adding references to existing projects a lot less painful. Incidentally, there is now a Haskell plugin for Visual Studio Code which uses Intero. This is very exciting indeed and I can’t wait to try it out!

How do I code in F# on a mac?!

Yep this is a question I had for a while too. That is until I discovered Mono, an open source .Net framework which is cross platform.
I found the best way to get F# set up on OSX was to install Mono but to actually use the installer that can be downloaded here. I tried installing the homebrew way first but this seems to be missing some .Net libraries. For example, one that is needed for System.Drawing. I uninstalled my homebrew mono installation and installed from the Mono download that I linked to above, and I was then able to build and draw lovely spirographs from the FSharp TV, Introduction to F# course.

How do I create an F# project?

This was a question I had too. I wanted to simply create a project with a common folder structure. I was looking for something similar to lein new in Clojure or stack new in Haskell. A great tool for this is Forge. The Visual Studio Code ionide plugin integrates with Forge to make it really easy to create new projects through the command palette in Visual Studio Code. I demo this further down.

How do I manage dependencies?

The tool for this is Paket which uses the Nuget package manager under the hood. Again, Visual Studio Code has a plugin to integrate with Paket, Ionide-Paket

How do I build an F# project

FAKE is a very popular build tool for F# and allows you to specify your build tasks through a build.fsx file using and F# DSL. Visual Studio Code has a plugin to integrate with this too as part of its ionide suite, Ionide FAKE This is demoed further down in this blog too.

How do I run a .exe on Mac!

Some of these tools I have mentioned along with the nunit testing tool (which I demo further down) require the running of a .exe to perform tasks. If the .exe is one that doesn’t run directly on Mac OS or Linux, usually it can be run using

mono name-of-your-executable.exe

once mono is installed and on your path and once name-or-your-executable.exe is actually a file that can be executed. It may seem like a simple thing but it is important to know as there are resources out there that describe how to use .Net tools assuming you are on a Windows machine.

Demo Time: TDD with F#

As there are resources out there about setting up F# with Mono and Visual Studio Code, there’s no need to re-iterate them here so I will assume that you managed to get those set up. If you have questions, feel free to comment on this blog.
My main stumbling block coming from outside the .Net world was simply setting up a unit test project and linking this to a production code project (by production code, I mean implementation code).
Lets go through that here:

So in Visual Studio Code, from an empty directory, open command palette with shift-command-p and type F#.

Then select New Project.

You will be prompted to select the type of project.

Choose classlib for our production code.
You will then be prompted to choose the project directory.

Lets specify a directory called MusicLibrary. So type in MusicLibrary, hit enter and you will be prompted to provide a project name. Lets call this MusicLibrary too.

After a second or so, you should eventually see that the ionide plugin has created three directories, .packet, MusicLibrary and packages. It will have also created a build.fsx file and a build.sh file so that we can build our new MusicLibrary project with FAKE.

In the MusicLibrary directory, you will find a newly created MusicLibrary.fs file.

This is where we are going to put our production code after we write a test for it.
For now, delete everything from there and we are going to add a function to test called addSongToLibrary which will eventually take a list of existing song titles and a new song title and return a list of song titles containing our the existing ones and our new title. For now, it just returns an empty list until we have our test ready. The contents of the MusicLibrary.fs file can be replaced with:

module MusicLibrary

let addSongToLibrary existingSongs newSong = []

Now, we should be able to build this right?. Lets give it ago.

Open the Visual Studio command palette again and type FAKE.

Select Build

You will be prompted for a FAKE build task to run.

Select build.

Now we get an error:

If you look down at the output window in Visual Studio Code, you will see something like
build.sh: line 34: syntax error: unexpected end of file

We need to convert the dos .sh file to into unix format. There is a tool for this on the Mac App Store dos2unix.

Install that.
In the terminal go into the parent directory of your MusicLibrary directory where build.sh exists and run dos2unix on the build.sh file.

dos2unix build.sh
dos2unix: converting file build.sh to Unix format...

Now follow the steps earlier to try and do a FAKE build in visual studio code.
In the output in visual studio code, you should see output about using paket to get any needed dependencies and also about the creation of dlls.
From my understanding Dlls in .Net are like jar files in the jvm world and they are the binaries created as a result of compiling F# code. The FAKE build will now have created a build directory and put the dlls in there.

You will see a MusicLibrary.dll in there.

Back in the MusicLibrary directory there is also a MusicLibrary.fsproj file which FAKE uses to find out things it needs for the build. When we write our test, we will see how we can add a reference to the MusicLibrary.dll into our .fsproj file for our unit test project. If you look in build.fsx, you will see a reference to these .fsproj files for FAKE.

let appReferences  =
    !! "/**/*.csproj"
    ++ "/**/*.fsproj"

Lets set up our test project so we can test our addSongToLibrary function!

To test our addSongToLibrary function we can set up a MusicLibraryTest project. Follow the same steps as we did for creating the MusicLibrary project in visual studio code except for the prompt to choose library type, choose fsunit

After, you should see a newly created MusicLibraryTest directory.

If you go into that directory, you will see that there has been a MusicLibraryTest.fs file created for us containing:

module MusicLibraryTest

open NUnit.Framework
open FsUnit

[<Test>]
let ``Example Test`` () =
    1 |> should equal 1

There are 2 libraries imported here for unit testing, NUnit.Framework and FsUnit.
This is where paket comes in for our test dependencies. If you go into the paket.references file within the MusicLibraryTest directory you will see

FSharp.Core
FsUnit

So, we need to link our MusicLibraryTest project to our MusicLibrary.fsproj so that we can test our addSongToLibrary function. This is taken care of by add a reference to the MusicLibrary.fsproj in the MusicLibraryTest.fsproj.

Open up the MusicLibraryTest.fsproj file.
Now, open visual studio command palette again.

Select Add Project Reference.
Then choose MusicLibraryTest as the project that you want to edit

Then choose MusicLibrary as the reference

Now, somewhere in the MusicLibraryTest.fsproj, there will be a newly created reference to the MusicLibray.fsproj. Search the MusicLibraryTest.fsproj for MusicLibrary.fsproj.

Now we can reference our MusicLibrary module and call the addSongToLibrary function.
Back in the MusicLibraryTest.fs file, we can import the MusicLibrary module which contains our addSongToLibrary function and lets write a test to test adding a song title.

Replace the contents of MusicLibraryTest.fs with:

module MusicLibraryTest

open NUnit.Framework
open FsUnit

open MusicLibrary

[<Test>]
let shouldAddASong () =
    ["Sir Duke";"Superstition"] 
    |> should equal (addSongToLibrary ["Superstition"] "Sir Duke")

How do I run my test!

First of all lets create our MusicLibraryTest.dll. This is done the same way that we created MusicLibrary.dll before by running the FAKE build in visual studio code. After running the build, there should be a MusicLibraryTest.dll in your build directory.


Actually getting tests to run was a stumbling block for me. To run tests, a FAKE task can be created in build.fsx. I will show how to do that in a little bit. First I will show how to run more manually using an nunit test runner.
The NUnit3 test runner can be downloaded as a zip file here.
To make this work with a FAKE task a bit later, first create a directory tools/Nunit in the root folder in visual studio code that you have your MusicLibrary and MusicLibraryTest projects in.
Then download NUnit.Console-3.5.0.zip into there.


Then unzip it.

Now we can use the nunit3-console.exe to run our test.
In the terminal, go into the tools/NUnit folder.
Make the nunit3-console.exe executable:

chmod 755 nunit3-console.exe

We can run our test with the command:

mono nunit3-console.exe ../../build/MusicLibraryTest.dll

This should output our failing test result:

NUnit Console Runner 3.5.0
Copyright (C) 2016 Charlie Poole

Runtime Environment
   OS Version: MacOSX 16.1.0.0
  CLR Version: 4.0.30319.42000

Test Files
    ../../build/MusicLibraryTest.dll


Errors and Failures

1) Failed : MusicLibraryTest.shouldAddASong
  Expected is <Microsoft.FSharp.Collections.FSharpList`1[System.Object]>, actual is <Microsoft.FSharp.Collections.FSharpList`1[System.String]>
  Values differ at index [0]
at FsUnit.TopLevelOperators.should[a,a] (Microsoft.FSharp.Core.FSharpFunc`2[T,TResult] f, a x, System.Object y) [0x0004e] in :0
at MusicLibraryTest.shouldAddASong () [0x0003d] in :0

Run Settings
    DisposeRunners: True
    WorkDirectory: /Users/tom/Dropbox/software-development/fsharp/NUnitDemo/tools/Nunit
    ImageRuntimeVersion: 4.0.30319
    ImageRequiresX86: False
    ImageRequiresDefaultAppDomainAssemblyResolver: False
    NumberOfTestWorkers: 8

Test Run Summary
  Overall result: Failed
  Test Count: 1, Passed: 0, Failed: 1, Inconclusive: 0, Skipped: 0
    Failed Tests - Failures: 1, Errors: 0, Invalid: 0
  Start time: 2017-01-08 13:40:33Z
    End time: 2017-01-08 13:40:33Z
    Duration: 0.142 seconds

Now lets integrate this into FAKE.

In the build.fsx file, add the following near the top underneath
open Fake

add

open Fake.Testing

so you now have

open Fake
open Fake.Testing

Add our NUnitTest task underneath the Target “Deploy” block.

let testDlls = !! (buildDir + "*Test.dll")

Target "NUnitTest" (fun _ ->
  testDlls
    |> NUnit3 (fun p -> p)

)

So we have:

Target "Deploy" (fun _ ->
    !! (buildDir + "/**/*.*")
    -- "*.zip"
    |> Zip buildDir (deployDir + "ApplicationName." + version + ".zip")
)

let testDlls = !! (buildDir + "*Test.dll")

Target "NUnitTest" (fun _ ->
  testDlls
    |> NUnit3 (fun p -> p)

)

Also add NUnitTest to the build order so the end of your build.fsx file should be

// Build order
"Clean"
  ==> "Build"
  ==> "NUnitTest"
  ==> "Deploy"

// start build
RunTargetOrDefault "Build"

Open Visual Studio Code command palette and type FAKE as before

Choose FAKE: Build

Now you should see our new NUnitTest task so select that.

This will fail because of our failing test.

The output pane in visual studio code will have the results of the nunit3-console.exe runner

1) Failed : MusicLibraryTest.shouldAddASong
  Expected is <Microsoft.FSharp.Collections.FSharpList`1[System.Object]>, actual is <Microsoft.FSharp.Collections.FSharpList`1[System.String]>
  Values differ at index [0]
at FsUnit.TopLevelOperators.should[a,a] (Microsoft.FSharp.Core.FSharpFunc`2[T,TResult] f, a x, System.Object y) [0x0004e] in :0
at MusicLibraryTest.shouldAddASong () [0x0003d] in :0

Lets make the test pass!!

Go back to the MusicLibrary.fs file and make the test pass by replacing its contents with:

module MusicLibrary

let addSongToLibrary existingSongs newSong = newSong :: existingSongs

In Visual Studio Code, use the command palette to run FAKE: Build selecting build as before and then  FAKE: Build selecting NUnitTest.

Looking through the output in visual studio code we can now see our passing test report:

Test Run Summary
  Overall result: Passed
  Test Count: 1, Passed: 1, Failed: 0, Inconclusive: 0, Skipped: 0
  Start time: 2017-01-08 13:46:29Z
    End time: 2017-01-08 13:46:29Z
    Duration: 0.132 seconds

Conclusion

Hopefully this has helped people to get started with the F# and .Net ecosystem and get up and running quickly in this amazing language.