måndag 23 mars 2009

Matchgame implementation #8: Exposing to C#

The game to implement is
Given four rows of matchsticks:
|||||||
|||||
|||
|

Two players take turns removing any number of sticks from ONE single row. The one to remove the last stick loses.

Complete source code with a C# console UI can be downloaded here.
Executable can be dowloaded here.

Since I'm a C# programmer, I wanted to turn the F# implemntation of the matchgame to something easily usable from C#.

Some requirements came to mind
  • Object-oriented
  • Exposing events when something happens
Uhm... that would be it. This would make the class somewhat a Presenter in the MVP pattern. So the Silverlight UI i've been talking about will easily use the presenter. But I don't want the added complexity of Silverlight quite yet (never used it), so the UI will be a console app for now.

I solved the requirements by wrapping the state of the game in a class called MatchStickGame.
It exposes the state as an array property.
It exposes two methods: Begin and MakePlayerMove
It exposes three events: Moved, InputRequested and GameEnded.

Here's the complete F# code:

#light
open System

let ValidMove state (removeAtIndex, removeNumber) =
removeAtIndex %gt;= 0 &&
removeAtIndex %lt; List.length state &&
removeNumber %gt; 0 &&
removeNumber %lt;= List.nth state removeAtIndex

let MakeMove state (removeAtIndex, removeNumber) =
if ValidMove state (removeAtIndex, removeNumber) = false then failwith (sprintf "%A is not a valid move on %A" (removeAtIndex, removeNumber) state)
List.mapi (fun i numberOfMatches -%gt; if removeAtIndex = i then numberOfMatches - removeNumber else numberOfMatches) state

let GenerateValidMoves state =
let mutable validMoves = []
let validIndices = [0 .. List.length state - 1]
for i in validIndices do
let validNumberOfPicks = [1 .. (List.nth state i)]
for n in validNumberOfPicks do
validMoves %lt;- (i, n)::validMoves
validMoves

// Checks if a leave is winning by complete search. Since it can take extreme time
// to calculate, the parameter maxDepth is used to limit how many look-aheads are
// valid to do (recursion depth).
let rec IsWinnerLeaveRec maxDepth state =
match maxDepth with
| 0 -%gt; false
| _ -%gt;
(state |%gt; List.map abs |%gt; List.sum = 1)
||
(
let rec HasWinningMove state moves maxDepth =
match moves with
| [] -%gt; false
| a::b -%gt; IsWinnerLeaveRec (maxDepth - 1) (MakeMove state a) || HasWinningMove state b maxDepth
let moves =
GenerateValidMoves state
|%gt; List.sort (fun (_, toRemove1) (_,toRemove2) -%gt; toRemove2 - toRemove1)
HasWinningMove state moves maxDepth
) = false

// checks if a leave is winning
let IsWinnerLeave state = IsWinnerLeaveRec (List.sum state) state

let rec PickWinnerMove state moves =
match moves with
|[] -%gt; failwith "No valid moves"
|[a]-%gt; a
|a::b when (IsWinnerLeave (MakeMove state a)) -%gt; a
|a::b when not (IsWinnerLeave (MakeMove state a)) -%gt; PickWinnerMove state b
|_ -%gt;failwith "unknown state"

let GenerateWinnerMove state =
let possibleMoves = GenerateValidMoves state
PickWinnerMove state possibleMoves

type MatchGameEndedEventArgs(playerWins) =
inherit EventArgs()
member this.PlayerWins : bool = playerWins

type MatchStickGame ()=
let mutable state = [7;5;3;1]

let movedEvent = new Event%lt;EventHandler%lt;EventArgs%gt;,_%gt;()
let requestInputEvent = new Event%lt;EventHandler%lt;EventArgs%gt;,_%gt;()
let gameEndedEvent = new Event%lt;EventHandler%lt;MatchGameEndedEventArgs%gt;,_%gt;()
// let fireMoved, movedEvent = Event.create_
let TriggerMoved this = movedEvent.Trigger (this, new EventArgs())

let RequestPlayerMove this state =
requestInputEvent.Trigger (this, new EventArgs())

let rec RequestComputerMove this state =
// Ask the computer how to move
let computerMove = GenerateWinnerMove state
// do the move and make it the player's turn
ActOnChosenMove this computerMove RequestComputerMove RequestPlayerMove

and ActOnChosenMove this (index, number) currentPlayerRequester nextPlayerRequester =
if not (ValidMove state (index, number)) then
currentPlayerRequester this state
else
// Move, trigger that a move was made and ask the next player for input
state %lt;- MakeMove state (index, number)
TriggerMoved this

if (List.sum state) %lt; 2 then
gameEndedEvent.Trigger(this, new MatchGameEndedEventArgs((currentPlayerRequester = RequestPlayerMove)))
else
nextPlayerRequester this state

// Events
member this.Moved = movedEvent.Publish
member this.InputRequested = requestInputEvent.Publish
member this.GameEnded = gameEndedEvent.Publish
// State property
member this.State = state |%gt; List.to_array

// Methods
member this.Begin() =
TriggerMoved this
RequestPlayerMove this state

member this.MakePlayerMove (index, number) =
ActOnChosenMove this (index, number) RequestPlayerMove RequestComputerMove


Here's the complete C# code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GameAsCSharpConsole
{
class Program
{
static void Main(string[] args)
{
MatchGame.MatchStickGame game = new MatchGame.MatchStickGame();
game.Moved += new EventHandler(game_Moved);
game.InputRequested += new EventHandler(game_InputRequested);
game.GameEnded += new EventHandler(game_GameEnded);
game.Begin();
Console.ReadKey();
}

static void game_GameEnded(object sender, MatchGame.MatchGameEndedEventArgs e)
{
Console.WriteLine();
Console.WriteLine("Game ended");
if (e.PlayerWins)
{
Console.WriteLine("you win!");
}
else
{
Console.WriteLine("You lose!");
}
}

static void game_InputRequested(object sender, EventArgs e)
{
Console.Write("Enter a move>");
string input = Console.ReadLine();
string[] parts = input.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

int index = int.Parse(parts[0]);
int number = int.Parse(parts[1]);

((MatchGame.MatchStickGame)sender).MakePlayerMove(index, number);
}

static void game_Moved(object sender, EventArgs e)
{
Console.WriteLine();
Console.WriteLine("New state:");
DisplayState((MatchGame.MatchStickGame)sender);
}

static void DisplayState(MatchGame.MatchStickGame game)
{
int[] state = game.State;
for (int i = 0; i < j =" 0;">


After the previous GUI implementation directly with F# compared to this one in C#, I'm starting to think C# is actually quite cumbersome. F# becomes more and more appealing!

Ok, what happens in this code?

Let's take a look at the public members first:

member this.Moved = movedEvent.Publish
member this.InputRequested = requestInputEvent.Publish
member this.GameEnded = gameEndedEvent.Publish

member this.State = state |> List.to_array

member this.Begin() =
TriggerMoved this
RequestPlayerMove this state

member this.MakePlayerMove (index, number) =
ActOnChosenMove this (index, number) RequestPlayerMove RequestComputerMove


First comes the three events that the UI should subscribe to.
Moved means that the game state has changed and needs to be redrawn.

InputRequested means that it is the player's turn, so the UI has to ask the player for input and then tell the game what the input was, through MakePlayerMove.

GameEnded means that the game has ended. It uses MatchGameEndedEventArgs, which contains a property telling is the player won or lost the game.

Then comes the property State, which the GUI should use to draw the game. I realize that the array elements are not read only. Not a good thing, but such matters are not the subject of this post, so let's just ignore that!

Begin is a method to get things going. It triggers events so the GUI knows it's time to draw the state and get user input.

MakePlayerMove is the method the GUI should call when the user has entered his/her move.
It propagates the call to its "private" counterpart ActOnChosenMove.

So let's have a look at what that one does.


let rec RequestComputerMove this state =
// Ask the computer how to move
let computerMove = GenerateWinnerMove state
// do the move and make it the player's turn
ActOnChosenMove this computerMove RequestComputerMove RequestPlayerMove

and ActOnChosenMove this (index, number) currentPlayerRequester nextPlayerRequester =
if not (ValidMove state (index, number)) then
currentPlayerRequester this state
else
// Move, trigger that a move was made and ask the next player for input
state <- MakeMove state (index, number)
TriggerMoved this

if (List.sum state) < 2 then
gameEndedEvent.Trigger(this, new MatchGameEndedEventArgs((currentPlayerRequester = RequestPlayerMove)))
else
nextPlayerRequester this state



It is shown along with the function RequestComputerMove. Look at the declaration, it uses and instead of let. Why?
Well, they are mutually recursive and then they obviously need to be declared in that way, or the program won't compile.

So what does ActOnChosenMove do?
It takes the instance of the MatchStickGame to be able to use that in the events (object sender). It takes the desired move.
And it takes two "delegates" to be able to ask for input. The first thing it does is to check if it is a valid move, and if not it immediately asks the current user for new input.
If the move is valid, it is used to put the game in a new state. It then triggers the event which tells that the state has changed, allowing GUI update.

It then checks if the game is pointless to continue (less than two sticks left).
if it is pointless, it trigger the GameEnded event, checking if the current player is the winner.

If the game should continue, it asks the next player for input.

The RequestComputerMove simply generates the computer's move, and Acts on it.

The code actually contains a bug, which will very rarely show. Can you find it, and tell why it probably won't show?

To the "instance variables"

let mutable state = [7;5;3;1]

let movedEvent = new Event<EventHandler<EventArgs>,_>()
let requestInputEvent = new Event<EventHandler<EventArgs>,_>()
let gameEndedEvent = new Event<EventHandler<MatchGameEndedEventArgs>,_>()


The state simply is the state. Mutable, since it can change.

Then comes three event helper variables. I haven't quite gotten the F# event model figured out, but it doesn't use the standard EventHandler signature pattern, so those three lines create "regular .Net"-compatible event thingies. The actual events are exposed as members further down the class.

RequestPlayerMove triggers the InputRequested event, but also matches RequestComputerMove in signature. That is so that the game "engine" ActOnChosenMove doesn't have to have different code for the player's turn or the computer's turn.

Matchgame implementation. Making it usable from C#

I mentioned it would be nice to make a GUI in silverlight for the matchgame. The language will be C#. So first I have to come up with a useful way of exposing the f# functions to C#.

That will be the next post.

söndag 22 mars 2009

Matchgame implementation #7: Further optimization?

The game to implement is
Given four rows of matchsticks:
|||||||
|||||
|||
|

Two players take turns removing any number of sticks from ONE single row. The one to remove the last stick loses.

In the last post the implementation was sped up by about 200 times, making the original game layout (7, 5, 3, 1) playable.

How can this be optimized further. First let's take a non-scientific approach of the math involved. Non-scientific because I don't have it fresh in my head.
We must first realize that this algorithm does a complete search of all the states. If n denotes the number of sticks in play, then the running time would be proportional to n^c (c= some number > 2), or even worse; e^n. I think the latter is closer to the truth. By realizing this there is also another fact that must be faced. Even if the run time can be cut by a factor of 200, just increase n with a few sticks and run-time still blows up in your face! Try plotting the graph for e^n for various n, and you'll see.

How to approach this?
The best way would be to take a completely different approach on the algorithm. For example exploit the patterns that can be found for winning moves. I will not do that however, how fun would it be to reveal thos patterns? It would render the game completely meaningless.

The second best way would be to give up and lie down. Much money could probably have been better spent if more programmers came to this realization early.

In this post I'm going to do something in between those two ways; try to improve on the already doomed algorithm and perhaps make it better by a constant factor. I really hope that no one getting paid to do this optimization would chose that way!!!

I have two different thoughts on how it could be improved.
  1. 1. When doing a complete search, try out the moves that removes the most number of sticks first, since that should quickly bring us to a losing or winning state.
  2. 2. Save all states that we already have computed if they are winning or losing, so we don't have to do that over and over again.


Here's the code to test the performace prior to optimization:


#light

let ValidMove state (removeAtIndex, removeNumber) =
removeAtIndex >= 0 &&
removeAtIndex < List.length state &&
removeNumber > 0 &&
removeNumber <= List.nth state removeAtIndex

let MakeMove state (removeAtIndex, removeNumber) =
if ValidMove state (removeAtIndex, removeNumber) = false then failwith (sprintf "%A is not a valid move on %A" (removeAtIndex, removeNumber) state)
List.mapi (fun i numberOfMatches -> if removeAtIndex = i then numberOfMatches - removeNumber else numberOfMatches) state

let GenerateValidMoves state =
let mutable validMoves = []
let validIndices = [0 .. List.length state - 1]
for i in validIndices do
let validNumberOfPicks = [1 .. List.nth state i]
for n in validNumberOfPicks do
validMoves <- (i, n)::validMoves
validMoves

let run_time_func (func: unit -> 'a) =
let time0 = System.DateTime.Now
let res = func ()
let diff0 = System.DateTime.Now - time0
(diff0, res)

// Checks if a leave is winning by complete search. Since it can take extreme time
// to calculate, the parameter maxDepth is used to limit how many look-aheads are
// valid to do (recursion depth).
let rec IsWinnerLeaveRec maxDepth state =
match maxDepth with
| 0 -> false
| _ ->
(state |> List.map abs |> List.sum = 1)
||
(
let rec HasWinningMove state moves maxDepth =
match moves with
| [] -> false
| a::b -> IsWinnerLeaveRec (maxDepth - 1) (MakeMove state a) || HasWinningMove state b maxDepth
let moves = GenerateValidMoves state
HasWinningMove state moves maxDepth
) = false

let startState = [7;5;3;1]
let (time, result) = run_time_func (fun() -> IsWinnerLeaveRec (List.sum startState) startState)
printfn "%A" time


The results seem to average about 3.5 seconds.


Now let's implement the first approach:

// Checks if a leave is winning by complete search. Since it can take extreme time
// to calculate, the parameter maxDepth is used to limit how many look-aheads are
// valid to do (recursion depth).
let rec IsWinnerLeaveRec maxDepth state =
match maxDepth with
| 0 -> false
| _ ->
(state |> List.map abs |> List.sum = 1)
||
(
let rec HasWinningMove state moves maxDepth =
match moves with
| [] -> false
| a::b -> IsWinnerLeaveRec (maxDepth - 1) (MakeMove state a) || HasWinningMove state b maxDepth
let moves =
GenerateValidMoves state
|> List.sort (fun (_, toRemove1) (_,toRemove2) -> toRemove2 - toRemove1)
HasWinningMove state moves maxDepth
) = false

let startState = [7;5;3;1]
let (time, result) = run_time_func (fun() -> IsWinnerLeaveRec (List.sum startState) startState)
printfn "%A" time


Note now how the list of moves is sorted, so the moves removing the most matches are tested first.
The result is promising, run time seems to average 2.5 seconds now. And that despite the additional step of sorting a list every state that is tested (which is really really unnecessary).
Just for "fun" I changed the sort order and re-ran the test. It took nearly 3 minutes!

So how to avoid the sorting? Change the function "GenerateValidMoves" of course, so it generates the moves in that order from the start!

...
Time passes
...

Ok, Didn't manage to do this in any working way. Making a list in descending order wan't as easy as writing [10 .. 1]. Anybody got a clue there?
So now it's time to follow my own advice. Give up. I mean, who would want to play this game with 100 matches anyway???
Maybe I'll try to make the saving of calculated states in the next post. Wrapping the matchgame in a silverlight UI might be another fun thing to do.

måndag 16 mars 2009

Matchgame implementation #6: Optimization

The game to implement is
Given four rows of matchsticks:
|||||||
|||||
|||
|

Two players take turns removing any number of sticks from ONE single row. The one to remove the last stick loses.

The previous post held a working implementation of this game. But it was extremely ineficcient, and I had to limit recursion depth for the algorithm to complete in a reasonable time. Which lead to that the computer did not make the right decision until very few sticks remained.

So let's take a look at the bad function along with the complete code to compute the time it takes to run:

#light

let ValidMove state (removeAtIndex, removeNumber) =
removeAtIndex >= 0 &&
removeAtIndex < List.length state &&
removeNumber > 0 &&
removeNumber <= List.nth state removeAtIndex

let MakeMove state (removeAtIndex, removeNumber) =
if ValidMove state (removeAtIndex, removeNumber) = false then failwith (sprintf "%A is not a valid move on %A" (removeAtIndex, removeNumber) state)
List.mapi (fun i numberOfMatches -> if removeAtIndex = i then numberOfMatches - removeNumber else numberOfMatches) state

let GenerateValidMoves state =
let mutable validMoves = []
let validIndices = [0 .. List.length state - 1]
for i in validIndices do
let validNumberOfPicks = [1 .. List.nth state i]
for n in validNumberOfPicks do
validMoves <- (i, n)::validMoves
validMoves

// Checks if a leave is winning by complete search. Since it can take extreme time
// to calculate, the parameter maxDepth is used to limit how many look-aheads are
// valid to do (recursion depth).
let rec IsWinnerLeaveRec maxDepth list =
match maxDepth with
| 0 -> false
| _ ->
(list |> List.map abs |> List.sum = 1)
||
(
let moves = GenerateValidMoves list
moves
|> List.map (MakeMove list)
|> List.map (IsWinnerLeaveRec (maxDepth - 1))
|> List.fold_left (fun x acc-> x || acc) false
) = false

let run_time_func (func: unit -> 'a) =
let time0 = System.DateTime.Now
let res = func ()
let diff0 = System.DateTime.Now - time0
(diff0, res)

let startState = [2;5;3;1]
let (time, result) = run_time_func (fun() -> IsWinnerLeaveRec (List.sum startState) startState)
printfn "%A" time


The bad function is "IsWinnerLeaveRec".
Here I also introduced a function which calculates the run time of another: "run_time_func". I "stole" it right away from F# for game development, I hope that's ok

Note in the last row that actually does the execution, the argument maxDepth is set to "(List.sum startState)". Since one move in the game always removes at least one stick, the maximum possible recursion depth is the number of sticks. And here I want to allow that depth to be able to measure properly.

The results on my system averages to 4 seconds.

So what to do?
Let's focus on the following:

(
let moves = GenerateValidMoves list
moves
|> List.map (MakeMove list)
|> List.map (IsWinnerLeaveRec (maxDepth - 1))
|> List.fold_left (fun x acc-> x || acc) false
) = false


The purpose of those lines is to verify that none of the valid moves may lead to a winning state.
What strikes me here is that the number of possible moves may be very large, but ALL of them are ALWAYS checked. That's quite unnecessary to do. Once we fint ONE move that's winning, we can stop. No need to evaluate all the rest!

So I introduce a new function which does just that; Check for ANY winning move, and if found then stop:


let rec HasWinningMove state moves maxDepth =
match moves with
| [] -> false
| a::b -> IsWinnerLeaveRec (maxDepth - 1) (MakeMove state a) || HasWinningMove state b maxDepth


It takes the state, a list of possible moves, and the maxDepth.
It performs a match on moves.
If there are no moves, then obviously there are no winning moves, so it evaluates to false;
If there is at least one move, then the list contains a winning move if the first move generates a winning state
OR if the remaining moves has a winning move.

Simple, right?
the original bad function the becomes:


let rec IsWinnerLeaveRec maxDepth state =
match maxDepth with
| 0 -> false
| _ ->
(state |> List.map abs |> List.sum = 1)
||
(
let moves = GenerateValidMoves state
HasWinningMove state moves maxDepth
) = false


Should be understandable?

Now the test runs in about 0.02 seconds, which is 200 times faster than the original!

The bad thing is that the code won't compile. It doesn't seem like you can have two functions calling each other. I solved that by defining "HasWinningMove" within "IsWinnerLeave"
Here's working code:


#light

let ValidMove state (removeAtIndex, removeNumber) =
removeAtIndex >= 0 &&
removeAtIndex < List.length state &&
removeNumber > 0 &&
removeNumber <= List.nth state removeAtIndex

let MakeMove state (removeAtIndex, removeNumber) =
if ValidMove state (removeAtIndex, removeNumber) = false then failwith (sprintf "%A is not a valid move on %A" (removeAtIndex, removeNumber) state)
List.mapi (fun i numberOfMatches -> if removeAtIndex = i then numberOfMatches - removeNumber else numberOfMatches) state

let GenerateValidMoves state =
let mutable validMoves = []
let validIndices = [0 .. List.length state - 1]
for i in validIndices do
let validNumberOfPicks = [1 .. List.nth state i]
for n in validNumberOfPicks do
validMoves <- (i, n)::validMoves
validMoves

let run_time_func (func: unit -> 'a) =
let time0 = System.DateTime.Now
let res = func ()
let diff0 = System.DateTime.Now - time0
(diff0, res)

// Checks if a leave is winning by complete search. Since it can take extreme time
// to calculate, the parameter maxDepth is used to limit how many look-aheads are
// valid to do (recursion depth).
let rec IsWinnerLeaveRec maxDepth state =
match maxDepth with
| 0 -> false
| _ ->
(state |> List.map abs |> List.sum = 1)
||
(
let rec HasWinningMove state moves maxDepth =
match moves with
| [] -> false
| a::b -> IsWinnerLeaveRec (maxDepth - 1) (MakeMove state a) || HasWinningMove state b maxDepth
let moves = GenerateValidMoves state
HasWinningMove state moves maxDepth
) = false

let startState = [2;5;3;1]
let (time, result) = run_time_func (fun() -> IsWinnerLeaveRec (List.sum startState) startState)
printfn "%A" time

// Time with this one about 0.02s
// Original: about 4s

// checks if a leave is winning
let IsWinnerLeave list = IsWinnerLeaveRec (List.sum list) list

let rec PickWinnerMove state moves =
match moves with
|[] -> failwith "No valid moves"
|[a]-> a
|a::b when (IsWinnerLeave (MakeMove state a)) -> a
|a::b when not (IsWinnerLeave (MakeMove state a)) -> PickWinnerMove state b
|_ ->failwith "unknown state"

let GenerateWinnerMove state =
let possibleMoves = GenerateValidMoves state
PickWinnerMove state possibleMoves

open System

let GetMoveFromUser state =
printfn "enter a move (row numberToRemove)>"
let input = Console.ReadLine()
let parts = input.Split([|' '|], StringSplitOptions.RemoveEmptyEntries)
let row = int parts.[0]
let numberToRemove = int parts.[1]
(row, numberToRemove)

let GetMoveFromComputer state =
let move = GenerateWinnerMove state
printfn "The computer moves %A" move
move

let StatePrinter state =
printfn "State:"
List.mapi (
fun i x ->
printf "%i: " i
for n in [1..x] do
printf "|"
printfn ""
) state
|> ignore

let rec main (activePlayerName, activePlayerInputRequest) (otherPlayerName,otherPlayerInputRequest) state=
StatePrinter state
let move = activePlayerInputRequest state
let newState = MakeMove state move
if (List.sum newState) < 2 then
if IsWinnerLeave newState then
StatePrinter newState
printfn "The game was won by %A" activePlayerName
else printfn "The game was lost by %A" activePlayerName
else
main (otherPlayerName, otherPlayerInputRequest) (activePlayerName, activePlayerInputRequest) newState

main ("Player", GetMoveFromUser) ("Computer", GetMoveFromComputer) [7;5;3;1]

ignore (Console.ReadKey())


Can you beat the computer? Can you beat the computer in different ways? Good luck ;)

Matchgame implementation #5: Making a playable game

The game to implement is
Given four rows of matchsticks:
|||||||
|||||
|||
|

Two players take turns removing any number of sticks from ONE single row. The one to remove the last stick loses.

In the previous post, everything for the game was provided, except for control flow wrapping all the pieces together in a playable game.

After some fiddling I managed to put it togather, so here comes the code for a complete playable game:


#light

let ValidMove state (removeAtIndex, removeNumber) =
removeAtIndex >= 0 &&
removeAtIndex < List.length state &&
removeNumber > 0 &&
removeNumber <= List.nth state removeAtIndex

let MakeMove state (removeAtIndex, removeNumber) =
if ValidMove state (removeAtIndex, removeNumber) = false then failwith (sprintf "%A is not a valid move on %A" (removeAtIndex, removeNumber) state)
List.mapi (fun i numberOfMatches -> if removeAtIndex = i then numberOfMatches - removeNumber else numberOfMatches) state

let GenerateValidMoves state =
let mutable validMoves = []
let validIndices = [0 .. List.length state - 1]
for i in validIndices do
let validNumberOfPicks = [1 .. List.nth state i]
for n in validNumberOfPicks do
validMoves <- (i, n)::validMoves
validMoves

// Checks if a leave is winning by complete search. Since it can take extreme time
// to calculate, the parameter maxDepth is used to limit how many look-aheads are
// valid to do (recursion depth).
let rec IsWinnerLeaveRec maxDepth list =
match maxDepth with
| 0 -> false
| _ ->
(list |> List.map abs |> List.sum = 1)
||
(GenerateValidMoves list
|> List.map (MakeMove list)
|> List.map (IsWinnerLeaveRec (maxDepth - 1))
|> List.fold_left (fun x acc-> x || acc) false) = false

// checks if a leave is winning
let IsWinnerLeave list = IsWinnerLeaveRec 5 list

let rec PickWinnerMove state moves =
match moves with
|[] -> failwith "No valid moves"
|[a]-> a
|a::b when (IsWinnerLeave (MakeMove state a)) -> a
|a::b when not (IsWinnerLeave (MakeMove state a)) -> PickWinnerMove state b
|_ ->failwith "unknown state"

let GenerateWinnerMove state =
let possibleMoves = GenerateValidMoves state
PickWinnerMove state possibleMoves

open System

let GetMoveFromUser state =
printfn "enter a move (row numberToRemove)>"
let input = Console.ReadLine()
let parts = input.Split([|' '|], StringSplitOptions.RemoveEmptyEntries)
let row = int parts.[0]
let numberToRemove = int parts.[1]
(row, numberToRemove)

let GetMoveFromComputer state =
let move = GenerateWinnerMove state
printfn "The computer moves %A" move
move

let StatePrinter state =
printfn "State:"
List.mapi (
fun i x ->
printf "%i: " i
for n in [1..x] do
printf "|"
printfn ""
) state
|> ignore

let rec main (activePlayerName, activePlayerInputRequest) (otherPlayerName,otherPlayerInputRequest) state=
StatePrinter state
let move = activePlayerInputRequest state
let newState = MakeMove state move
if (List.sum newState) < 2 then
if IsWinnerLeave newState then
StatePrinter newState
printfn "The game was won by %A" activePlayerName
else printfn "The game was lost by %A" activePlayerName
else
main (otherPlayerName, otherPlayerInputRequest) (activePlayerName, activePlayerInputRequest) newState

let startState = [7;5;3;1]

main ("Player", GetMoveFromUser) ("Computer", GetMoveFromComputer) startState

ignore (Console.ReadKey())


Now let's take a look at what was added. We'll jump right into main and look at the other functions later.

let rec main (activePlayerName, activePlayerInputRequest) (otherPlayerName,otherPlayerInputRequest) state=
StatePrinter state
let move = activePlayerInputRequest state
let newState = MakeMove state move
if (List.sum newState) < 2 then
if IsWinnerLeave newState then
StatePrinter newState
printfn "The game was won by %A" activePlayerName
else printfn "The game was lost by %A" activePlayerName
else
main (otherPlayerName, otherPlayerInputRequest) (activePlayerName, activePlayerInputRequest) newState


It's a function that takes two tuples and the current state of the game.
Each tuple represents a player; the name of the player, and the function to call to get a move from that player.


StatePrinter state

Just displays the state in a way resembling the original game of matches. It might as well just have said "print_any state", but how ugly is that? (it originally looket like that :)



let move = activePlayerInputRequest state

The next step asks the user for which move he/she/it wants to make on the given state. Explanation about those functions later, let's just accept that the function returns a move the player wants to make.


let newState = MakeMove state move

Nothing arcane about the state transition either. We have a state, the user wants to perform a move on it. Well, make the move and we get a new state!


if (List.sum newState) < 2 then
if IsWinnerLeave newState then
StatePrinter newState
printfn "The game was won by %A" activePlayerName
else printfn "The game was lost by %A" activePlayerName

This is to check if the user has won the game. To be honest, the game is so deterministic that even before it has started it is already decided who will win, assuming the winner knows the pattern.
But wouldn't it be boring to just say: You begin therefore you lose.? That gives no room for the "winner-to-be" to make a mistake and let the other player win.

But once we get down to only one or zero sticks left, it might be ok to reveal the winner.
So that's what the outer "if" does, it checks if there are less than two sticks left in the game.
If so it checks if the state is a winning or a losing state, and writes out whether the current player won or lost.


else
main (otherPlayerName, otherPlayerInputRequest) (activePlayerName, activePlayerInputRequest) newState

The outer else runs if there are at least 2 sticks left, that is enough sticks to still allow for mistakes.
What happens is that the main function is called again, but now switching between who is the active and passive player, and providing the new state.

I'll not bother to go throught the "StatePrinter" function unless someone asks.

So lets look at:


let GetMoveFromUser state =
printfn "enter a move (row numberToRemove)>"
let input = Console.ReadLine()
let parts = input.Split([|' '|], StringSplitOptions.RemoveEmptyEntries)
let row = int parts.[0]
let numberToRemove = int parts.[1]
(row, numberToRemove)

The function uses an ordinary Console.ReadLine() to get the user input. It assumes that one number is input for the row index to remove at, and one number for the number of sticks to remove from that row.
It then splits the string and picks out the first part as index, and the second part as number to remove.
It returns a tuple with those two numbers, which happens to be the representation of a move.
What about the parameter "state" which is never used? Well, I needed it to give this function the same signature as the one that asks the computer for a move:


let GetMoveFromComputer state =
let move = GenerateWinnerMove state
printfn "The computer moves %A" move
move

This one is simply just a wrapper for "GenerateWinnerMove", printing out the move that the computer chooses.

Because of the really crappy algorithm limited in recursion depth you should be able to beat the game 10 times out of 10!

Hmm, look where that statement got me when playing in order to be able to get a screen dump:


State:
0: |||||
1: |||
2: |
enter a move (row numberToRemove)>
0 3
State:
0: ||
1: |||
2: |
The computer moves (0, 1)
State:
0: |
1: |||
2: |
enter a move (row numberToRemove)>
1 3
State:
0: |
1:
2: |
The computer moves (2, 1)
State:
0: |
1:
2:
The game was won by "Computer"


And that with a simplified starting state!!! shame on me!
Can you do better?

Ps. The code was a tiny bit modified from the previous post, Thanks for the comment!

Matchgame implementation #4: Making the computer decide

The game to implement is
Given four rows of matchsticks:
|||||||
|||||
|||
|
Two players take turns removing any number of sticks from ONE single row. The one to remove the last stick loses.

In the previous post there were functions to:
  • Verify that a move is valid (ValidMove)
  • Apply a given move (MakeMove)
  • Generate all possible moves for a given state (GenerateValidMoves)
  • Verify that a given state is winning when your move is complete (IsWinnerLeaveNaive)
The next step would be to make the computer "think" out a winning move to make, given a state.

Also, the function IsWinnerLeaveNaive is so extremely poor-performing that I have made a new one with a "safety valve" so it does not blow up in your face.

The code so far looks lie:


#light

let ValidMove state (removeAtIndex, removeNumber) =
removeAtIndex >= 0 &&
removeAtIndex < List.length state &&
removeNumber > 0 &&
removeNumber <= List.nth state removeAtIndex

let MakeMove state (removeAtIndex, removeNumber) =
if ValidMove state (removeAtIndex, removeNumber) = false then failwith (sprintf "%A is not a valid move on %A" (removeAtIndex, removeNumber) state)
List.mapi (fun i numberOfMatches -> if removeAtIndex = i then numberOfMatches - removeNumber else numberOfMatches) state

let GenerateValidMoves state =
let mutable validMoves = []
let validIndices = [0 .. List.length state - 1]
for i in validIndices do
let validNumberOfPicks = [1 .. List.nth state i]
for n in validNumberOfPicks do
validMoves <- (i, n)::validMoves
validMoves

// Checks if a leave is winning by complete search. Since it can take extreme time
// to calculate, the parameter maxDepth is used to limit how many look-aheads are
// valid to do (recursion depth).
let rec IsWinnerLeaveRec maxDepth list =
match maxDepth with
| 0 -> false
| _ ->
(list |> List.map abs |> List.sum = 1)
||
(GenerateValidMoves list
|> List.map (MakeMove list)
|> List.map (IsWinnerLeaveRec (maxDepth - 1))
|> List.fold_left (fun x acc-> x || acc) false) = false

// checks if a leave is winning
let IsWinnerLeave list = IsWinnerLeaveRec 6 list

let rec PickWinnerMove state moves =
match moves with
|[] -> failwith "No valid moves"
|a::b when b = []-> a
|a::b when (IsWinnerLeave (MakeMove state a)) -> a
|a::b when not (IsWinnerLeave (MakeMove state a)) -> PickWinnerMove state b
|_ ->failwith "unknown state"

let GenerateWinnerMove state =
let possibleMoves = GenerateValidMoves state
PickWinnerMove state possibleMoves

let state = [3;5;2;1]
let move = GenerateWinnerMove state
printfn "A winning move on the state %A is %A, which brings it to %A" state move (MakeMove state move)


The new function GenerateWinnerMove is very simple. It generates all possible moves in the given state, and lets the function PickWinnerMove select a winning move from those.

So let's look further at PickWinnerMove:

let rec PickWinnerMove state moves =
match moves with
|[] -> failwith "No valid moves"
|a::b when b = []-> a
|a::b when (IsWinnerLeave (MakeMove state a)) -> a
|a::b when not (IsWinnerLeave (MakeMove state a)) -> PickWinnerMove state b
|_ ->failwith "unknown state"


It does a match on the list of supplied moves. If no moves were provided (empty list) it fails.

The following matches are conditional, that is they only match if the "when" is evaluated to true.
the first match of those is:
|a::b when b = []-> a

It will only match if it is a list with elements, but with the condition that the tail is empty i.e. a one-element list. Then there's not much to choose from, is it? We have to pick that move no matter if it is winning or not.

|a::b when (IsWinnerLeave (MakeMove state a)) -> a

This one says that if a is a move which takes us to a state which is winning, then pick a. Should be obvious, we have found our winning move!

|a::b when not (IsWinnerLeave (MakeMove state a)) -> PickWinnerMove state b

This one is the opposite of the previous; if a is not a winning move, keep looking for winning moves among the remaining possible moves

|_ ->failwith "unknown state"

This last one is a bit nasty. It should never be able to happen, since the two previous matches cover up all the cases except the empty list. But the F# compiler obviously has a difficulty figuring that out when using "when".

So now the computer is "smart" and can decide on a move to make. But it is limited by the depth of recursion, so it is really not that smart. Try changing the depth to 5 instead of 6 in the example above, and you will get a different answer, which indeed is not a winning move!
And still the "IsWinnerLeave" function may blow up in your face with enough matchsticks in the state. Jsut not as hard as before. But who gets happier from waiting 1 year for an answer instead of 1000?

But I'm still a novice, and the time for optimization has yet to come!

Matchgame implementation #3: determine if a move is winning

The game to implement is
Given four rows of matches:
|||||||
|||||
|||
|
Two players take turns removing any number of matches from ONE single row. The one to remove the last match looses.

A step toward "intelligence"


In the end I want the computer to act as a player of the game. Therefore I must provide a function to evaluate if a move is a good one or a bad one.
Also, for that one to work, there must be a function to generate all moves that are possible / legal to make on a given state.

The very naive code I came up with was this:


let GenerateValidMoves state =
let mutable validMoves = []
let validIndices = [0 .. List.length state - 1]
for i in validIndices do
let validNumberOfPicks = [1 .. List.nth state i]
for n in validNumberOfPicks do
validMoves <- (i, n)::validMoves
validMoves

let rec IsWinnerLeaveNaive list =
let filtered = List.filter (fun x -> x <> 0) list
match filtered with
| [] -> false
| head::tail -> (list |> List.map abs |> List.sum = 1)
||
(GenerateValidMoves list
|> List.map (MakeMove list)
|> List.map IsWinnerLeaveNaive
|> List.fold_left (fun x acc-> x || acc) false) = false

let losingState = [2;2;1]
let winningState = [2;2;0]

printfn "All possible moves on %A are: %A" losingState (GenerateValidMoves losingState)

printfn "If you leave the state %A, you may win=%A" losingState (IsWinnerLeaveNaive losingState)
printfn "If you leave the state %A, you may win=%A" winningState (IsWinnerLeaveNaive winningState)


So what does it do?
Let's skip the first function for now, and dive right into IsWinnerLeaveNaive.

The first row
let filtered = List.filter (fun x -> x <> 0) list
filters out all elements that are zero from the state, as they make no difference. That might not actually do anything meaningful to this function, but makes the problem a little simpler to think of.

Then it's time for a little match on the filtered list.
The first match is quite straightforward.
| [] -> false

The game is lost when you had to pick the last match, so obviously if you leave no matches after your move, you lose.

The next match simply matches a state which still contains sticks. How to tell if you will win leaving that state after your move?
Well, say that you give your opponent no single way to leave a winning state after him. Then you are on your way to victory.
Also, the case where you leave one single stick is also quite simple. You win, that's it.

So you win either if you leave one single match, or you leave no opportunity for your opponent to make a winning move.

Expressed in F# that becomes:

(list |> List.map abs |> List.sum = 1)
||
(GenerateValidMoves list
|> List.map (MakeMove list)
|> List.map IsWinnerLeaveNaive
|> List.fold_left (fun x acc-> x || acc) false) = false


The first row simply sums the list to find out if only one match remains. The abs is probably overkill, since a valid state cannot contain negative number of matches anyway.

The last four lines generates all possible moves your opponent may take, performs all those moves, and checks that none of the new states reached is a winning state.
The last row List.fold_left is a bit cryptic. It takes a list of booleans like this:
[false true true false] and applies the or-operator to all elements and returns true if all those elements were false.

Why did I call the function "Naive"? Well because it is, and turns out extremely unefficient. Don't try to run it with a longer list containing more matches, or you'll have to kill the fsi.exe process!!!

After writing this post, as mentioned, there were some unnecessary lines of code. I removed them, so the complete example now looks like

#light

let ValidMove state (removeAtIndex, removeNumber) =
removeAtIndex >= 0 &&
removeAtIndex < List.length state &&
removeNumber > 0 &&
removeNumber <= List.nth state removeAtIndex

let MakeMove state (removeAtIndex, removeNumber) =
if ValidMove state (removeAtIndex, removeNumber) = false then failwith (sprintf "%A is not a valid move on %A" (removeAtIndex, removeNumber) state)
List.mapi (fun i numberOfMatches -> if removeAtIndex = i then numberOfMatches - removeNumber else numberOfMatches) state

let GenerateValidMoves state =
let mutable validMoves = []
let validIndices = [0 .. List.length state - 1]
for i in validIndices do
let validNumberOfPicks = [1 .. List.nth state i]
for n in validNumberOfPicks do
validMoves <- (i, n)::validMoves
validMoves

let rec IsWinnerLeaveNaive list =
List.sum list = 1
||
(
GenerateValidMoves list
|> List.map (MakeMove list)
|> List.map IsWinnerLeaveNaive
|> List.fold_left (fun x acc-> x || acc) false
) = false

let losingState = [2;2;1]
let winningState = [2;2;0]

printfn "All possible moves on %A are: %A" losingState (GenerateValidMoves losingState)

printfn "If you leave the state %A, you may win=%A" losingState (IsWinnerLeaveNaive losingState)
printfn "If you leave the state %A, you may win=%A" winningState (IsWinnerLeaveNaive winningState)

söndag 15 mars 2009

Matchgame implementation #2: make a move

The game to implement is
Given four rows of matches:
|||||||
|||||
|||
|
Two players take turns removing any number of matches from ONE single row. The one to remove the last match looses.

Ok, so the next easy step in learning F#, focused on this game, was to define how to represent a move, and how to apply it on the state of the game.

I decided for a tuple to represent a move the first member the index to the row to remove matches from, the second member the number of matches to remove.
So the move "remove three matches from the first row" becomes:
let move=(0,3)


So how to turn this into action?
The code I came up with along with some lines to test it:


let ValidMove state (removeAtIndex, removeNumber) =
removeAtIndex >= 0 &&
removeAtIndex < List.length state &&
removeNumber > 0 &&
removeNumber <= List.nth state removeAtIndex

let MakeMove state (removeAtIndex, removeNumber) =
if ValidMove state (removeAtIndex, removeNumber) = false then failwith (sprintf "%A is not a valid move on %A" (removeAtIndex, removeNumber) state)
List.mapi (fun i numberOfMatches -> if removeAtIndex = i then numberOfMatches - removeNumber else numberOfMatches) state

let state = [7;5;3;1]

let validMove=(1,4)
let invalidMove = (0,8)

printf "The move %A applied to %A becomes %A\n" validMove state (MakeMove state validMove)
printf "The move %A applied to %A becomes %A\n" invalidMove state (MakeMove state invalidMove)


So what does it do?

The first function

let ValidMove state (removeAtIndex, removeNumber) =
removeAtIndex >= 0 &&
removeAtIndex < List.length state &&
removeNumber > 0 &&
removeNumber <= List.nth state removeAtIndex

simply verifies that the move is valid to perform on the state. It verifies that the row (index) is within the list, and that the number of matches to remove is at least one, but no more than the number of available matches in the given row.

The second function

let MakeMove state (removeAtIndex, removeNumber) =
if ValidMove state (removeAtIndex, removeNumber) = false then failwith (sprintf "%A is not a valid move on %A" (removeAtIndex, removeNumber) state)
List.mapi (fun i numberOfMatches -> if removeAtIndex = i then numberOfMatches - removeNumber else numberOfMatches) state

first calls ValidMove to verify that it is a valid move (really?), and fails (throws exception) if not.
It then performs a function on all elements in the state to generate the new state. List.mapi, in addition to List.map, also provides the index the function is called on. So the function takes the row number (index), and the number of matches in that row. If it is the row to remove at, it returns the number minus the number to remove. Otherwise it just returns the original number of matches.

Executing the provided code should not give any surprises. Except perhaps that last row seems to execute before the next last, because the exception printout comes before the valid printout.

Matchgame implementation step #1

Step 1 in implementing the matchstick game described in a previous post was to decide how to represent the game state.
Well, F# seems to work well with lists, so a list it is.
The index in the list represents the row, the value represents the number of matches in the row.

So a representation of the starting state
|||||||
|||||
|||
|

is the list defined as
let startState = [7;5;3;1]


Note that with this representation the game is not limited to just 4 row, but can be any number of rows with any number of matches in them.

The first thing I wanted to do was a basic function which verifies that takes two states and verifies that the second can be reached from the first in one single move.

The function along with some testing code became:

#light

let startState = [7;5;3;1]

let rec ValidStateChange beforeState afterState =
match (beforeState, afterState) with
| ([],[]) -> false
| (bh::bt, ah::at) -> (bh > ah && bt = at) or (bh = ah && ValidStateChange bt at)
| (bh::_,[]) -> false
| ([],ah::_) -> false

let validNewState = [3;5;3;1]
let invalidNewState = [3;3;3;1]

printf "%A to %A : valid=%A\n" startState validNewState (ValidStateChange startState validNewState)
printf "%A to %A : valid=%A\n" startState invalidNewState (ValidStateChange startState invalidNewState)


So I dove right into pattern matching. Seemed neat
The first pattern | ([],[]) -> false

says that it is not a valid move to go from zero matches to zero matches. At least one match needs to be removed, remember?

The second pattern does the major work here. It matches when both states are lists (which they always should be from the start)
It says that
If the number of matches in the first row in the before-state are greater than the number of matches in the first row in the after-state, and all remaining rows being equal, then it is a valid state change.
Either that, OR:
If the number of matches in the first row are equal before and after, and the remaining rows as states themselves are a valid state change, then it is a valid state change.

The compiler now told me that I didn't match all patterns. Eh ok... Yes, of course. What if the states contain different nomber of rows. Then you can't get from on to the other.

As it turned out, this first function had no use in the game implementation in the end. But I got a better feel for F# writing it.

I realize now that a game of matches was not the best choice for explaining things, since the word match takes two meanings in this context... duh.

The first steps

The first "hello world" steps have already been made, I didn't think of starting the blog until after maybe a week of learning.

But here it is:

printf "Hello World"

The best sources for learning which I have found so far are:

http://sharp-gamedev.blogspot.com/ (borrowed a bit of looks, hope that's ok!)

http://blogs.msdn.com/chrsmith/archive/2008/05/02/f-in-20-minutes-part-i.aspx
http://blogs.msdn.com/chrsmith/archive/2008/05/09/f-in-20-minutes-part-ii.aspx

The first steps was of course to test the code in those places, and make minor modifications to make it feel like "I made this".

What's the next step? I want to make some program that actually does something. And I thought of a little game with matches my mom taught me long ago. It would be a perfect project to start with.

The game
The game is for two. You start by laying out 16 matches in four rows like this:
||||||| (first row)
|||||
(secondrow)
||| (thirdrow)
| (fourth row)

Then player one chooses to remove any number (at least one) of matches from ONE row he chooses.
The next player then removes any number of matches from ONE row he chooses.
It keeps on like that, until only one match remains. The player who has to remove the last match looses the game.

The decision

Having used .Net with primarily C# for a couple of years, I decided it is time to take a look at F# and what it has to offer.

Many years ago, at university, I was briefly introduced to Scheme, Prolog and Haskell. the latter two were quite neat as I recall. Alas, a long time has passed and memory and knowledge fades away.

But I do remember the expressive and straightforward way those languages could be used to code. Until now functional programming has not been an option when working professionally (for me at least). But with the introduction of F# I think that will change in a near future.

So, I have decided to learn it. From scratch. And I will blog about it all, from my first staggering steps up until I become an expert (if ever).