Skip to content

Commit

Permalink
Poker hand recognition example
Browse files Browse the repository at this point in the history
  • Loading branch information
Mikhail Shilkov committed Feb 1, 2016
1 parent bc31273 commit ad9697b
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 2 deletions.
43 changes: 41 additions & 2 deletions Either{TL,TR}.cs
@@ -1,7 +1,13 @@
namespace MikhailIo
namespace Library.Functional
{
using System;

/// <summary>
/// Functional data data to represent a discriminated
/// union of two possible types.
/// </summary>
/// <typeparam name="TL">Type of "Left" item.</typeparam>
/// <typeparam name="TR">Type of "Right" item.</typeparam>
public class Either<TL, TR>
{
private readonly TL left;
Expand All @@ -21,7 +27,40 @@ public Either(TR right)
}

public T Match<T>(Func<TL, T> leftFunc, Func<TR, T> rightFunc)
=> this.isLeft ? leftFunc(this.left) : rightFunc(this.right);
{
if (leftFunc == null)
{
throw new ArgumentNullException(nameof(leftFunc));
}

if (rightFunc == null)
{
throw new ArgumentNullException(nameof(rightFunc));
}

return this.isLeft ? leftFunc(this.left) : rightFunc(this.right);
}

/// <summary>
/// If right value is assigned, execute an action on it.
/// </summary>
/// <param name="rightAction">Action to execute.</param>
public void DoRight(Action<TR> rightAction)
{
if (rightAction == null)
{
throw new ArgumentNullException(nameof(rightAction));
}

if (!this.isLeft)
{
rightAction(this.right);
}
}

public TL LeftOrDefault() => this.Match(l => l, r => default(TL));

public TR RightOrDefault() => this.Match(l => default(TR), r => r);

public static implicit operator Either<TL, TR>(TL left) => new Either<TL, TR>(left);

Expand Down
73 changes: 73 additions & 0 deletions HandRecognition.fs
@@ -0,0 +1,73 @@
open System.Drawing

module HandRecognition =
type BW = B | W
type CardPattern = {
Card: string
Pattern: BW array
}

let patterns = [|
{ Card = "2"; Pattern = [|W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;B;B;B;W;W;W;W;W;W;B;B;B;W;W;W;W;B;B;B;B;W;W;W;W;W;B;B;B;B;W;W;W;B;B;B;B;W;W;W;W;B;B;B;B;B;B;W;W;W;B;B;W;W;W;W;W;W;B;B;W;W;B;B;W;W;W;B;B;W;W;W;W;W;B;B;W;W;W;B;B;W;W;W;B;B;B;W;W;B;B;B;B;W;W;W;B;B;W;W;W;W;B;B;B;B;B;B;B;W;W;W;W;B;B;W;W;W;W;W;B;B;B;B;W;W;W;W;W;W;B;B;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W|] }
{ Card = "3"; Pattern = [|W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;B;B;W;W;W;W;W;W;W;B;B;B;W;W;W;W;W;B;B;B;B;W;W;W;W;B;B;B;B;W;W;W;W;W;W;B;B;B;B;W;W;W;B;B;W;W;W;W;W;W;W;W;W;W;B;B;W;W;W;B;B;W;W;W;W;B;B;W;W;W;W;B;B;W;W;W;B;B;W;W;W;B;B;B;W;W;W;W;B;B;W;W;W;B;B;B;B;B;B;B;B;B;B;B;B;B;B;W;W;W;W;B;B;B;B;B;W;B;B;B;B;B;B;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W|] }
{ Card = "4"; Pattern = [|W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;B;B;W;W;W;W;W;W;W;W;W;W;W;W;W;B;B;B;B;B;W;W;W;W;W;W;W;W;W;W;B;B;B;W;B;B;B;W;W;W;W;W;W;W;W;W;B;B;B;W;W;W;B;B;W;W;W;W;W;W;W;B;B;B;W;W;W;W;B;B;B;W;W;W;W;W;W;B;B;B;B;B;B;B;B;B;B;B;B;B;B;W;W;W;B;B;B;B;B;B;B;B;B;B;B;B;B;B;W;W;W;W;W;W;W;W;W;W;W;B;B;B;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;B;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W|] }
{ Card = "5"; Pattern = [|W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;B;W;W;W;W;W;W;W;W;B;B;B;B;B;B;W;W;B;B;B;W;W;W;W;B;B;B;B;B;B;B;W;W;W;B;B;B;B;W;W;W;B;B;W;W;W;B;B;W;W;W;W;W;B;B;W;W;W;B;B;W;W;W;B;B;W;W;W;W;W;B;B;W;W;W;B;B;W;W;W;B;B;W;W;W;W;B;B;B;W;W;W;B;B;W;W;W;B;B;B;B;B;B;B;B;W;W;W;W;B;B;W;W;W;W;B;B;B;B;B;B;W;W;W;W;W;W;W;W;W;W;W;W;W;W;B;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W|] }
{ Card = "6"; Pattern = [|W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;B;B;B;W;W;W;W;W;W;W;W;W;W;W;B;B;B;B;B;B;B;B;B;W;W;W;W;W;W;B;B;B;W;B;B;B;B;B;B;B;B;B;W;W;W;B;B;W;W;W;B;B;W;W;W;W;W;B;B;W;W;W;B;W;W;W;W;B;W;W;W;W;W;W;B;B;W;W;W;B;B;W;W;W;B;B;W;W;W;W;W;B;B;W;W;W;B;B;B;W;W;B;B;B;B;B;B;B;B;B;W;W;W;W;W;B;W;W;W;B;B;B;B;B;B;B;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W|] }
{ Card = "7"; Pattern = [|W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;B;B;B;W;W;W;W;W;W;W;W;W;W;W;W;W;W;B;B;B;W;W;W;W;W;W;W;W;B;B;B;W;W;W;B;B;B;W;W;W;W;B;B;B;B;B;B;B;W;W;W;B;B;B;W;W;B;B;B;B;B;B;B;B;W;W;W;W;B;B;B;B;B;B;B;W;W;W;W;W;W;W;W;W;W;B;B;B;B;B;W;W;W;W;W;W;W;W;W;W;W;W;B;B;B;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W|] }
{ Card = "8"; Pattern = [|W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;B;W;W;W;W;B;B;B;B;W;W;W;W;W;W;B;B;B;B;B;W;B;B;B;B;B;B;W;W;W;W;B;B;W;W;W;B;B;B;W;W;W;W;B;B;W;W;W;B;W;W;W;W;W;B;W;W;W;W;W;B;B;W;W;W;B;W;W;W;W;W;B;W;W;W;W;W;B;B;W;W;W;B;B;W;W;W;B;B;B;W;W;W;B;B;B;W;W;W;W;B;B;B;B;B;W;B;B;B;B;B;B;W;W;W;W;W;W;W;W;W;W;W;W;B;B;B;B;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W|] }
{ Card = "9"; Pattern = [|W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;B;B;B;B;W;W;W;W;B;W;W;W;W;W;W;B;B;B;B;B;B;B;B;W;B;B;B;W;W;W;W;B;B;W;W;W;W;W;B;B;W;W;W;B;B;W;W;W;B;B;W;W;W;W;W;B;B;W;W;W;B;B;W;W;W;B;B;W;W;W;W;W;B;B;W;W;W;B;B;W;W;W;B;B;B;W;W;W;B;B;W;W;B;B;B;B;W;W;W;W;B;B;B;B;B;B;B;B;B;B;B;B;W;W;W;W;W;W;W;W;B;B;B;B;B;B;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W|] }
{ Card = "T"; Pattern = [|W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;B;B;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;B;B;W;W;W;W;W;W;W;W;W;W;W;W;W;W;B;B;B;W;W;W;W;W;W;W;W;W;W;W;W;B;B;B;B;B;B;B;B;B;B;B;B;B;B;W;W;W;B;B;B;B;B;B;B;B;B;B;B;B;B;B;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;B;B;B;B;W;W;W;W;W;W;W;W;W;B;B;B;B;B;B;B;B;B;B;B;B;W;W;W;W;B;B;B;B;B;B;W;W;B;B;B;B;B;B;W;W;W;B;B;W;W;W;W;W;W;W;W;W;W;B;B;W;W;W;B;B;W;W;W;W;W;W;W;W;W;W;B;B;W;W;W;B;B;B;W;W;W;W;W;W;W;W;B;B;B;W|] }
{ Card = "J"; Pattern = [|W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;B;B;B;B;W;W;W;W;W;W;W;W;W;W;W;W;W;B;B;B;B;B;W;W;W;W;W;W;W;W;W;W;W;W;W;W;B;B;B;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;B;B;W;W;W;W;W;W;W;W;W;W;W;W;W;W;B;B;B;W;W;W;B;B;B;B;B;B;B;B;B;B;B;B;B;B;W;W;W;B;B;B;B;B;B;B;B;B;B;B;B;B;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W|] }
{ Card = "Q"; Pattern = [|W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;B;B;B;B;B;B;W;W;W;W;W;W;W;W;W;B;B;B;B;B;B;B;B;B;B;W;W;W;W;W;W;B;B;B;W;W;W;W;W;B;B;B;B;W;W;W;W;B;B;W;W;W;W;W;W;W;W;W;B;B;B;W;W;W;B;B;W;W;W;W;W;W;W;W;W;W;B;B;W;W;W;B;B;W;W;W;W;W;W;W;W;W;W;B;B;W;W;W;B;B;W;W;W;W;W;W;W;B;B;B;B;B;W;W;W;B;B;B;W;W;W;W;W;W;W;B;B;B;B;W;W;W;W;B;B;B;B;W;W;W;B;B;B;B;B;B;W;W;W;W;W;B;B;B;B;B;B;B;B;B;B;B;B;B;W;W;W;W;W;W;W;B;B;B;B;W;W;W;W;W;W|] }
{ Card = "K"; Pattern = [|W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;B;B;B;B;B;B;B;B;B;B;B;B;B;B;W;W;W;B;B;B;B;B;B;B;B;B;B;B;B;B;B;W;W;W;W;W;W;W;W;B;B;B;B;W;W;W;W;W;W;W;W;W;W;W;W;B;B;B;B;W;W;W;W;W;W;W;W;W;W;W;W;B;B;B;B;B;B;W;W;W;W;W;W;W;W;W;W;B;B;B;B;B;B;B;B;B;W;W;W;W;W;W;B;B;B;B;W;W;W;B;B;B;B;B;B;W;W;W;W;B;B;B;W;W;W;W;W;W;B;B;B;B;B;W;W;W;B;W;W;W;W;W;W;W;W;W;W;B;B;B;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;B;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W|] }
{ Card = "A"; Pattern = [|W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;B;B;B;W;W;W;W;W;W;W;W;W;W;B;B;B;B;B;B;B;W;W;W;W;W;W;W;B;B;B;B;B;B;B;B;W;W;W;W;W;W;B;B;B;B;B;B;B;B;B;B;W;W;W;W;W;W;B;B;B;B;B;W;W;W;B;B;B;W;W;W;W;W;W;B;B;B;B;W;W;W;W;B;B;B;W;W;W;W;W;W;B;B;B;B;B;B;B;B;B;B;B;W;W;W;W;W;W;W;W;W;W;B;B;B;B;B;B;B;B;W;W;W;W;W;W;W;W;W;W;W;W;B;B;B;B;B;B;B;W;W;W;W;W;W;W;W;W;W;W;W;W;B;B;B;B;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W;W|] }
|]

let getCardPattern getPixel width height =
let isWhite (c : Color) =
if c.B > 127uy && c.G > 127uy && c.R > 127uy then W
else B

seq { for x in 0 .. width - 1 do
for y in 0 .. height - 1 do
yield isWhite (getPixel x y)}

let getCardSuit getPixel width height =
let getSuit (c : Color) =
match c with
| _ when c.B < 127uy && c.G < 127uy && c.R > 127uy -> Some "h"
| _ when c.B > 127uy && c.G < 127uy && c.R < 127uy -> Some "d"
| _ when c.B < 127uy && c.G > 127uy && c.R < 127uy -> Some "c"
| _ when c.B < 127uy && c.G < 127uy && c.R < 127uy -> Some "s"
| _ -> None
seq { for x in 0 .. width - 1 do
for y in 0 .. height - 1 do
yield getSuit (getPixel x y)}
|> Seq.choose id
|> Seq.countBy id
|> Seq.maxBy (fun (v, c) -> c)
|> fst

let getCardValue patterns bws =
let matchCount h p =
Seq.zip h p
|> Seq.map (fun (v1, v2) -> if v1 = v2 then 1 else 0)
|> Seq.sum
|> decimal
let maxPattern = patterns |> Array.maxBy (fun p -> matchCount bws p.Pattern)
maxPattern.Card

let getCardString getCardPattern getCardSuit =
let value = getCardPattern |> getCardValue patterns
let suit = getCardSuit
value + suit

let recognizeCard getPixel width height =
let value = getCardPattern getPixel width height |> getCardValue patterns
let suit = getCardSuit getPixel width height
value + suit

let parsePattern getPixel width height =
getCardPattern getPixel width height
|> Seq.map (fun x -> if x = B then "B" else "W")
|> String.concat ";"

0 comments on commit ad9697b

Please sign in to comment.