1 people like it.

Reversi Kata

Quick & dirty solution to Reversi kata: http://codingdojo.org/cgi-bin/wiki.pl?KataReversi

 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: 
let boardText ="
........
........
........
...BW...
...WB...
........
........
........"
let board = boardText.Split([|'\r';'\n'|]) |> Array.filter (fun line -> line.Length > 0)

let getLegalMoves (board:string[]) color =
    let width, height = board.[0].Length, board.Length
    let opposite =
        match color with
        | 'B' -> 'W'
        | 'W' -> 'B'
        | _ -> invalidOp ""
    let findDisks color =
        board |> Seq.mapi (fun y line ->
            line |> Seq.mapi (fun x item -> if item = color then Some(x,y) else None)
        )                 
        |> Seq.concat
        |> Seq.choose id
    let directions =
        [-1,-1; 0,-1; 1, -1;
         -1, 0;       1, 0;
         -1, 1; 0, 1; 1, 1]
    let isInside (x,y) = x >= 0 && x < width && y >= 0 && y < height
    let itemAt (x,y) = board.[y].[x]
    let findSurroundingPlaces (x,y) =
        directions
        |> List.map (fun (dx,dy) -> x+dx, y+dy)
        |> List.filter isInside        
    let isLegalMove (x,y) =
        directions
        |> List.filter (fun (dx,dy) -> isInside (x+dy,y+dy))
        |> List.filter (fun (dx,dy) -> opposite = itemAt (x+dx,y+dy)) 
        |> List.map (fun (dx,dy) ->           
            let xs = 
                Seq.initInfinite (fun i -> (x+dx*i, y+dy*i))
                |> Seq.skip 1
                |> Seq.takeWhile isInside
                |> Seq.skipWhile (fun (x,y) -> itemAt(x,y) = opposite)
            if Seq.length xs = 0 then false
            else Seq.head xs |> itemAt = color
        )
        |> List.exists id
    let targets = findDisks opposite
    targets |> Seq.map (fun (x,y) ->
        findSurroundingPlaces (x,y)
        |> List.filter (fun (x,y) -> board.[y].[x] = '.')
        |> List.filter isLegalMove
    )
    |> Seq.concat

getLegalMoves board 'B'
val boardText : string

Full name: Script.boardText
val board : string []

Full name: Script.board
System.String.Split([<System.ParamArray>] separator: char []) : string []
System.String.Split(separator: string [], options: System.StringSplitOptions) : string []
System.String.Split(separator: char [], options: System.StringSplitOptions) : string []
System.String.Split(separator: char [], count: int) : string []
System.String.Split(separator: string [], count: int, options: System.StringSplitOptions) : string []
System.String.Split(separator: char [], count: int, options: System.StringSplitOptions) : string []
module Array

from Microsoft.FSharp.Collections
val filter : predicate:('T -> bool) -> array:'T [] -> 'T []

Full name: Microsoft.FSharp.Collections.Array.filter
val line : string
property System.String.Length: int
val getLegalMoves : board:string [] -> color:char -> seq<int * int>

Full name: Script.getLegalMoves
val board : string []
Multiple items
val string : value:'T -> string

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

--------------------
type string = System.String

Full name: Microsoft.FSharp.Core.string
val color : char
val width : int
val height : int
property System.Array.Length: int
val opposite : char
val invalidOp : message:string -> 'T

Full name: Microsoft.FSharp.Core.Operators.invalidOp
val findDisks : (char -> seq<int * int>)
module Seq

from Microsoft.FSharp.Collections
val mapi : mapping:(int -> 'T -> 'U) -> source:seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.mapi
val y : int
val x : int
val item : char
union case Option.Some: Value: 'T -> Option<'T>
union case Option.None: Option<'T>
val concat : sources:seq<#seq<'T>> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.concat
val choose : chooser:('T -> 'U option) -> source:seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.choose
val id : x:'T -> 'T

Full name: Microsoft.FSharp.Core.Operators.id
val directions : (int * int) list
val isInside : (int * int -> bool)
val itemAt : (int * int -> char)
val findSurroundingPlaces : (int * int -> (int * int) list)
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 map : mapping:('T -> 'U) -> list:'T list -> 'U list

Full name: Microsoft.FSharp.Collections.List.map
val dx : int
val dy : int
val filter : predicate:('T -> bool) -> list:'T list -> 'T list

Full name: Microsoft.FSharp.Collections.List.filter
val isLegalMove : (int * int -> bool)
val xs : seq<int * int>
val initInfinite : initializer:(int -> 'T) -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.initInfinite
val i : int
val skip : count:int -> source:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.skip
val takeWhile : predicate:('T -> bool) -> source:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.takeWhile
val skipWhile : predicate:('T -> bool) -> source:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.skipWhile
val length : source:seq<'T> -> int

Full name: Microsoft.FSharp.Collections.Seq.length
val head : source:seq<'T> -> 'T

Full name: Microsoft.FSharp.Collections.Seq.head
val exists : predicate:('T -> bool) -> list:'T list -> bool

Full name: Microsoft.FSharp.Collections.List.exists
val targets : seq<int * int>
val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.map
Raw view New version

More information

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