5 people like it.

Reversi Kata solution

Reversi Kata solution from February 2013 London F# Meetup Coding Kata.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
37: 
38: 
39: 
40: 
41: 
42: 
43: 
44: 
45: 
46: 
47: 
48: 
49: 
50: 
51: 
52: 
53: 
54: 
55: 
56: 
57: 
58: 
59: 
60: 
61: 
62: 
63: 
64: 
65: 
66: 
open System

/// Reversi board
let board = "
....
.OX.
.XO.
...."

/// Board rows
let rows = board.Split([|'\n'|], StringSplitOptions.RemoveEmptyEntries)

/// Board cells
let cells = 
    rows 
    |> Array.map (fun row -> row.ToCharArray())
    |> array2D

/// Returns true if coordinates are inside board
let inside (x,y) = 
    x >=0 && x < rows.[0].Length && y >= 0 && y < rows.Length 

/// Gets vectors from a coordinate
let getVectors (x,y) =
    [-1,-1; 0,-1; 1,-1
     -1, 0;       1, 0
     -1, 1; 0, 1; 1, 1]
    |> List.filter (fun (dx,dy) -> inside(x+dx,y+dy)) 

/// Returns true if board run represents a valid move
let isValidRun (s:string) =
    let color = s.[0]
    let opposite =
        match color with
        | 'O' -> 'X'
        | 'X' -> 'O'
        |  c  -> invalidOp(sprintf "Unexpected char %c" c)
    let mutable i = 1
    while i < s.Length && s.[i] = opposite do i <- i + 1
    i > 1 && i < s.Length && s.[i] = color

/// Gets board run as string
let getRun (x,y) (dx,dy) =
    let px = ref (x+dx)
    let py = ref (y+dy)
    let chars =
        [|while inside(!px,!py) do 
            yield cells.[!py,!px]
            px := !px + dx
            py := !py + dy|]
    String(chars)

/// Prints all valid moves for a color
let validMoves (color:string) =
    cells 
    |> Array2D.iteri (fun y x cell ->
        if cell = '.' then
            getVectors (x,y)
            |> List.exists (fun vector ->
                let s = getRun (x,y) vector
                isValidRun (color+s)
            )
            |> function 
                | true -> printfn "%d %d" x y 
                | false -> ()
    )
namespace System
val board : string

Full name: Script.board


 Reversi board
val rows : string []

Full name: Script.rows


 Board rows
String.Split([<ParamArray>] separator: char []) : string []
String.Split(separator: string [], options: StringSplitOptions) : string []
String.Split(separator: char [], options: StringSplitOptions) : string []
String.Split(separator: char [], count: int) : string []
String.Split(separator: string [], count: int, options: StringSplitOptions) : string []
String.Split(separator: char [], count: int, options: StringSplitOptions) : string []
type StringSplitOptions =
  | None = 0
  | RemoveEmptyEntries = 1

Full name: System.StringSplitOptions
field StringSplitOptions.RemoveEmptyEntries = 1
val cells : char [,]

Full name: Script.cells


 Board cells
type Array =
  member Clone : unit -> obj
  member CopyTo : array:Array * index:int -> unit + 1 overload
  member GetEnumerator : unit -> IEnumerator
  member GetLength : dimension:int -> int
  member GetLongLength : dimension:int -> int64
  member GetLowerBound : dimension:int -> int
  member GetUpperBound : dimension:int -> int
  member GetValue : [<ParamArray>] indices:int[] -> obj + 7 overloads
  member Initialize : unit -> unit
  member IsFixedSize : bool
  ...

Full name: System.Array
val map : mapping:('T -> 'U) -> array:'T [] -> 'U []

Full name: Microsoft.FSharp.Collections.Array.map
val row : string
String.ToCharArray() : char []
String.ToCharArray(startIndex: int, length: int) : char []
val array2D : rows:seq<#seq<'T>> -> 'T [,]

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.array2D
val inside : x:int * y:int -> bool

Full name: Script.inside


 Returns true if coordinates are inside board
val x : int
val y : int
property Array.Length: int
val getVectors : x:int * y:int -> (int * int) list

Full name: Script.getVectors


 Gets vectors from a coordinate
Multiple items
module List

from Microsoft.FSharp.Collections

--------------------
type List<'T> =
  | ( [] )
  | ( :: ) of Head: 'T * Tail: 'T list
  interface IEnumerable
  interface IEnumerable<'T>
  member Head : 'T
  member IsEmpty : bool
  member Item : index:int -> 'T with get
  member Length : int
  member Tail : 'T list
  static member Cons : head:'T * tail:'T list -> 'T list
  static member Empty : 'T list

Full name: Microsoft.FSharp.Collections.List<_>
val filter : predicate:('T -> bool) -> list:'T list -> 'T list

Full name: Microsoft.FSharp.Collections.List.filter
val dx : int
val dy : int
val isValidRun : s:string -> bool

Full name: Script.isValidRun


 Returns true if board run represents a valid move
val s : string
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = String

Full name: Microsoft.FSharp.Core.string
val color : char
val opposite : char
val c : char
val invalidOp : message:string -> 'T

Full name: Microsoft.FSharp.Core.Operators.invalidOp
val sprintf : format:Printf.StringFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
val mutable i : int
property String.Length: int
val getRun : x:int * y:int -> dx:int * dy:int -> String

Full name: Script.getRun


 Gets board run as string
val px : int ref
Multiple items
val ref : value:'T -> 'T ref

Full name: Microsoft.FSharp.Core.Operators.ref

--------------------
type 'T ref = Ref<'T>

Full name: Microsoft.FSharp.Core.ref<_>
val py : int ref
val chars : char []
Multiple items
type String =
  new : value:char -> string + 7 overloads
  member Chars : int -> char
  member Clone : unit -> obj
  member CompareTo : value:obj -> int + 1 overload
  member Contains : value:string -> bool
  member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit
  member EndsWith : value:string -> bool + 2 overloads
  member Equals : obj:obj -> bool + 2 overloads
  member GetEnumerator : unit -> CharEnumerator
  member GetHashCode : unit -> int
  ...

Full name: System.String

--------------------
String(value: nativeptr<char>) : unit
String(value: nativeptr<sbyte>) : unit
String(value: char []) : unit
String(c: char, count: int) : unit
String(value: nativeptr<char>, startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int) : unit
String(value: char [], startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int, enc: Text.Encoding) : unit
val validMoves : color:string -> unit

Full name: Script.validMoves


 Prints all valid moves for a color
val color : string
module Array2D

from Microsoft.FSharp.Collections
val iteri : action:(int -> int -> 'T -> unit) -> array:'T [,] -> unit

Full name: Microsoft.FSharp.Collections.Array2D.iteri
val cell : char
val exists : predicate:('T -> bool) -> list:'T list -> bool

Full name: Microsoft.FSharp.Collections.List.exists
val vector : int * int
val s : String
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
Raw view Test code New version

More information

Link:http://fssnip.net/gY
Posted:11 years ago
Author:Phillip Trelford
Tags: reversi , kata , board , game