<commit_before>open Core.Std

let grid size (initial: (int * int) list) =
  List.init size ~f:(fun x ->
    List.init size ~f:(fun y ->
      List.mem initial (x, y)
    )
  )

let get grid x y =
  match List.nth grid y with
  | None -> None
  | Some row -> List.nth row x

let neighbors grid x y : bool list =
  List.map
    (List.filter [
        get grid (x-1) (y-1);
        get grid (x)   (y-1);
        get grid (x+1) (y-1);
        get grid (x-1) (y);
        get grid (x+1) (y);
        get grid (x-1) (y+1);
        get grid (x)   (y+1);
        get grid (x+1) (y+1)
      ] ~f:(fun cell ->
        match cell with
        | None -> false
        | Some _ -> true
      )
    ) ~f:(fun cell ->
      match cell with
      | None -> assert false
      | Some is_alive -> is_alive
    )

let live_neighbors grid x y =
  List.count (neighbors grid x y) ~f:(fun x -> x)

let next grid =
  List.mapi grid ~f:(fun y row ->
    List.mapi row ~f:(fun x is_alive ->
      let neighbors = live_neighbors grid x y in
        match is_alive, neighbors with
        | true, n  when n < 2          -> false
        | true, n  when n = 2 || n = 3 -> true
        | true, n  when n > 3          -> false
        | true, _ -> assert false
        | false, n when n = 3          -> true
        | false, _                     -> false
    )
  )

let print grid =
  List.iteri grid ~f:(fun y row ->
    List.iteri row ~f:(fun x is_alive ->
      let c = if is_alive then 'X' else ' ' in
      Printf.printf "%c" c
    );
    Printf.printf "\n"
  )

let thunk grid =
  let state = ref grid in
  print !state;
  fun () ->
    let next_state = next !state in
    state := next_state;<commit_msg>Add to_string<commit_after>open Core.Std

let grid size (initial: (int * int) list) =
  List.init size ~f:(fun x ->
    List.init size ~f:(fun y ->
      List.mem initial (x, y)
    )
  )

let get grid x y =
  match List.nth grid y with
  | None -> None
  | Some row -> List.nth row x

let neighbors grid x y : bool list =
  List.map
    (List.filter [
        get grid (x-1) (y-1);
        get grid (x)   (y-1);
        get grid (x+1) (y-1);
        get grid (x-1) (y);
        get grid (x+1) (y);
        get grid (x-1) (y+1);
        get grid (x)   (y+1);
        get grid (x+1) (y+1)
      ] ~f:(fun cell ->
        match cell with
        | None -> false
        | Some _ -> true
      )
    ) ~f:(fun cell ->
      match cell with
      | None -> assert false
      | Some is_alive -> is_alive
    )

let live_neighbors grid x y =
  List.count (neighbors grid x y) ~f:(fun x -> x)

let next grid =
  List.mapi grid ~f:(fun y row ->
    List.mapi row ~f:(fun x is_alive ->
      let neighbors = live_neighbors grid x y in
        match is_alive, neighbors with
        | true, n  when n < 2          -> false
        | true, n  when n = 2 || n = 3 -> true
        | true, n  when n > 3          -> false
        | true, _ -> assert false
        | false, n when n = 3          -> true
        | false, _                     -> false
    )
  )

let to_string grid =
  String.concat ~sep:"\n"
    (List.map grid ~f:(fun row ->
      String.concat ~sep:""
        (List.map row ~f:(fun is_alive ->
          if is_alive then "X" else " "
        ))
    ))

let print grid =
  printf "%s" (to_string grid);
  printf "\n%s\n" (String.make (List.length grid) '-')

let thunk grid =
  let state = ref grid in
  print !state;
  fun () ->
    let next_state = next !state in
    state := next_state;
{'fraction_non_alphanumeric': 0.13459879206212252, 'fraction_numerical': 0.009778544722461893, 'mean_word_length': 1.5705838876570584, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2513323', 'n_tokens_mistral': 1281, 'n_tokens_neox': 1243, 'n_words': 428}