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
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
open Core
open Placed_tile

type square_type =
  | Normal
  | Double_letter
  | Triple_letter
  | Double_word
  | Triple_word

type direction = Horizontal | Vertical

module IntPair = struct
  type t = int * int [@@deriving compare, sexp]
end

module BoardMap = Map.Make (IntPair)

type t = Tile.t BoardMap.t

let to_yojson board =
  `Assoc
    (Map.to_alist board
    |> List.map ~f:(fun ((row, col), tile) ->
           (Printf.sprintf "%d,%d" row col, Tile.to_yojson tile)))

let of_placed_tile_list_exn (placed_tiles : Placed_tile.t list) : t =
  BoardMap.of_alist_exn
  @@ List.map placed_tiles ~f:(fun pt -> ((pt.pos.row, pt.pos.col), pt.tile))

let board_size = 15

let triple_word_squares =
  [
    { row = 0; col = 0 };
    { row = 0; col = 7 };
    { row = 0; col = 14 };
    { row = 7; col = 0 };
    { row = 7; col = 14 };
    { row = 14; col = 0 };
    { row = 14; col = 7 };
    { row = 14; col = 14 };
  ]

let double_word_squares =
  [
    { row = 1; col = 1 };
    { row = 2; col = 2 };
    { row = 3; col = 3 };
    { row = 4; col = 4 };
    { row = 1; col = 13 };
    { row = 2; col = 12 };
    { row = 3; col = 11 };
    { row = 4; col = 10 };
    { row = 13; col = 1 };
    { row = 12; col = 2 };
    { row = 11; col = 3 };
    { row = 10; col = 4 };
    { row = 13; col = 13 };
    { row = 12; col = 12 };
    { row = 11; col = 11 };
    { row = 10; col = 10 };
    { row = 7; col = 7 };
  ]

let triple_letter_squares =
  [
    { row = 1; col = 5 };
    { row = 1; col = 9 };
    { row = 5; col = 1 };
    { row = 5; col = 5 };
    { row = 5; col = 9 };
    { row = 5; col = 13 };
    { row = 9; col = 1 };
    { row = 9; col = 5 };
    { row = 9; col = 9 };
    { row = 9; col = 13 };
    { row = 13; col = 5 };
    { row = 13; col = 9 };
  ]

let double_letter_squares =
  [
    { row = 0; col = 3 };
    { row = 0; col = 11 };
    { row = 2; col = 6 };
    { row = 2; col = 8 };
    { row = 3; col = 0 };
    { row = 3; col = 7 };
    { row = 3; col = 14 };
    { row = 6; col = 2 };
    { row = 6; col = 6 };
    { row = 6; col = 8 };
    { row = 6; col = 12 };
    { row = 7; col = 3 };
    { row = 7; col = 11 };
    { row = 8; col = 2 };
    { row = 8; col = 6 };
    { row = 8; col = 8 };
    { row = 8; col = 12 };
    { row = 11; col = 0 };
    { row = 11; col = 7 };
    { row = 11; col = 14 };
    { row = 12; col = 6 };
    { row = 12; col = 8 };
    { row = 14; col = 3 };
    { row = 14; col = 11 };
  ]

let get_square_type pos =
  let matches l =
    List.exists l ~f:(fun p -> p.row = pos.row && p.col = pos.col)
  in
  if matches triple_word_squares then Triple_word
  else if matches double_word_squares then Double_word
  else if matches triple_letter_squares then Triple_letter
  else if matches double_letter_squares then Double_letter
  else Normal

let is_valid_position { row; col } =
  row >= 0 && row < board_size && col >= 0 && col < board_size

let get_tile_at board pos = Map.find board (pos.row, pos.col)
let is_board_empty board = Map.is_empty board
let create_empty_board () = BoardMap.empty

let place_tile_on_board board pos tile =
  Map.set board ~key:(pos.row, pos.col) ~data:tile