2 Commits 88f731e416 ... 655366832b

Author SHA1 Message Date
  Zelphir Kaltstahl 655366832b implement basic read of input 2 years ago
  Zelphir Kaltstahl 370cba4d4f add gitignore file 2 years ago
8 changed files with 186 additions and 242 deletions
  1. 1 0
      .gitignore
  2. 40 242
      day-04/01.sml
  3. 11 0
      day-04/build.cm
  4. 33 0
      day-04/lib/bit_extra.sml
  5. 9 0
      day-04/lib/file_extra.sml
  6. 10 0
      day-04/lib/int_extra.sml
  7. 26 0
      day-04/lib/list_extra.sml
  8. 56 0
      day-04/lib/string_extra.sml

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+**/.cm

+ 40 - 242
day-04/01.sml

@@ -1,253 +1,51 @@
 (* open IntInf; *)
 
-fun read file =
-    let
-        val inStream = TextIO.openIn file
-    in
-        (* TextIO.inputAll returns a TextIO.vector, which is a string. *)
-        TextIO.inputAll inStream
-    end;
-
+fun compose a b =
+    (fn input => b (a input));
 
-fun is_list_prefix nil nil = true
-  | is_list_prefix nil lst_elems = true
-  | is_list_prefix prefix_elems nil = false
-  | is_list_prefix prefix_elems lst_elems =
-    if (hd prefix_elems) = (hd lst_elems)
-    then is_list_prefix (tl prefix_elems) (tl lst_elems)
-    else false;
-
-
-fun string_split sep str =
-    let
-        val chars = String.explode str;
-        val sep_chars = String.explode sep;
-        val sep_len = length sep_chars;
-        val prefix_pred = is_list_prefix sep_chars;
+(* fun chain procs = *)
+(*     foldl (fn (proc, composed_procs) => *)
+(*               (fn input => *)
+(*                   proc (composed_procs input))) *)
+(*           (fn any => any) *)
+(*           procs; *)
 
-        fun iter (nil, collected_chars, parts) = String.implode (rev collected_chars) :: parts
-          | iter (remaining_chars as (c::cs), collected_chars, parts) =
-            let
-                val _ = print ("remaining chars: " ^ (String.implode remaining_chars) ^ "\n");
-                val _ = print ("collected chars: " ^ (String.implode collected_chars) ^ "\n");
-                val _ = print ("parts: " ^ (String.concatWith "," parts) ^ "\n");
-            in
-                if prefix_pred remaining_chars
-                then
-                    (* drop the separator, begin anew collecting chars until next separator, *)
-                    iter (List.drop (remaining_chars, sep_len),
-                          [],
-                          String.implode (rev collected_chars) :: parts)
-                else
-                    (* collect characters, which are not part of the prefix *)
-                    iter (cs, c :: collected_chars, parts)
-            end
-    in
-        rev (iter (chars, [], []))
-    end;
 
-val block_tokenizer = String.tokens (fn c => c = #"\n");
+val block_tokenizer = StringExtra.split "\n\n";
 val newline_tokenizer = String.tokens (fn c => c = #"\n");
-
-
-fun sum_lists (nil, nil) = []
-  | sum_lists (nil, l2) = []
-  | sum_lists (l1, nil) = []
-  | sum_lists (alst as (a::arest), blst as (b::brest)) =
-    (a + b) :: sum_lists(arest, brest);
-
-
-fun string_to_bits str =
-    map (fn c =>
-            case c of
-                #"1" => 1
-              | #"0" => 0
-              | _ => raise Fail "unrecognized bit value")
-        (String.explode str);
-
-
-fun invert 0 = 1
-  | invert 1 = 0
-  | invert _ = raise Fail "unrecognized bit value";
-fun invert_list lst = map invert lst;
-
-
-fun make_list (0, _) = []
-  | make_list (len, fill) =
-    fill :: make_list (len - 1, fill);
-
-
-fun int_expt (0, _) = 0
-  | int_expt (1, _) = 1
-  | int_expt (base, 0) = 1
-  | int_expt (base, 1) = base
-  | int_expt (base, exponent) =
-    base * int_expt (base, exponent - 1);
-
-
-fun bit_to_decimal (bit, ind) =
-    bit * int_expt (2, ind);
-
-
-fun bits_to_decimal bit_vector =
-    let
-        val len = Vector.length bit_vector;
-        fun iter (bits, ind, acc) =
-            if ind < len
-            then
-                let
-                    val bit = Vector.sub(bits, ind);
-                    val position = (len - 1) - ind;
-                    val decimal_value = bit_to_decimal (bit, position);
-                in
-                    iter (bits, ind + 1, acc + decimal_value)
-                end
-            else
-                acc;
-    in
-        iter (bit_vector, 0, 0)
-    end;
-
-
-fun sum_bits_at_index (bitss, index) =
-    List.foldli (fn (ind, bits, acc) => acc + Vector.sub (bits, index))
-                0
-                bitss;
-
-fun even num = (num mod 2) = 0;
-fun odd num = (num mod 2) = 1;
-
-fun get_least_common_bit (bitss, index) =
-    let
-        val _ = print "getting least common bit\n";
-        val len = length bitss;
-        val half_len = (len div 2);
-        val sum_of_bits = sum_bits_at_index (bitss, index);
-    in
-        (* CASE 1: all bits are 1 *)
-        (* if there are only 1s then the interpretation is, that 1 is the
-           least common and most common bit, instead of 0 being the least
-           common bit (such as: a hundred 1s, zero 0s, then 1 instead of 0) *)
-        if sum_of_bits = len
-        then 1
-        else
-            if even len
-            then
-                if sum_of_bits >= half_len
-                then 0
-                else 1
-            else
-                if sum_of_bits > half_len
-                then 0
-                else 1
-    end;
-
-
-(* assertions *)
-if 1 = get_least_common_bit ([#[0,0,0], #[1,1,0], #[0,1,1]], 0)
-then true
-else raise Fail "assertion failed - get_least_common_bit - 01";
-
-if 0 = get_least_common_bit ([#[1,0,0], #[1,1,0], #[0,1,1]], 0)
-then true
-else raise Fail "assertion failed - get_least_common_bit - 02";
-
-if 0 = get_least_common_bit ([#[0,0,0], #[1,1,0], #[0,1,1], #[1,1,1]], 0)
-then true
-else raise Fail "assertion failed - get_least_common_bit - 03";
-
-if 1 = get_least_common_bit ([#[1,0,0], #[1,1,0]], 0)
-then true
-else raise Fail "assertion failed - get_least_common_bit - 04";
-
-
-fun get_most_common_bit (bitss, index) =
-    let
-        val _ = print "getting most common bit\n";
-        val len = length bitss;
-        val _ = print ("num of bit vectors: " ^ (Int.toString len) ^ "\n");
-        val half_len = (len div 2);
-        val sum_of_bits = sum_bits_at_index (bitss, index);
-        val _ = print ("sum of bits at index: " ^ (Int.toString sum_of_bits) ^ "\n");
-    in
-        (* if there are only 1s then the interpretation is, that 1 is the
-           least common and most common bit, instead of 0 being the least
-           common bit (such as: a hundred 1s, zero 0s, then 1 instead of 0) *)
-        if even len
-        then
-            if sum_of_bits >= half_len
-            then 1
-            else 0
-        else
-            if sum_of_bits > half_len
-            then 1
-            else 0
-    end;
-
-
-(* assertions *)
-if 0 = get_most_common_bit ([#[0,0,0], #[1,1,0], #[0,1,1]], 0)
-then true
-else raise Fail "assertion failed - get_most_common_bit - 01";
-
-if 1 = get_most_common_bit ([#[1,0,0], #[1,1,0], #[0,1,1]], 0)
-then true
-else raise Fail "assertion failed - get_most_common_bit - 02";
-
-if 1 = get_most_common_bit ([#[0,0,0], #[1,1,0], #[0,1,1], #[1,1,1]], 0)
-then true
-else raise Fail "assertion failed - get_most_common_bit - 03";
-
-if 1 = get_most_common_bit ([#[1,0,0], #[1,1,0]], 0)
-then true
-else raise Fail "assertion failed - get_most_common_bit - 04";
-
-if 0 = get_most_common_bit ([#[0,0,0], #[0,1,0]], 0)
-then true
-else raise Fail "assertion failed - get_most_common_bit - 05";
-
-
-fun calculate_rating (bitss, bit_value_selector) =
+val string_list_to_int_list =
+    map (fn num_as_str =>
+            case Int.fromString num_as_str of
+                SOME number => number
+              | NONE =>
+                raise Fail "encountered a non-int string");
+val cleanup_rows =
+    compose
+        (compose
+             (map (StringExtra.replace "  " " "))
+             (map (StringExtra.trim_left (fn c => c = #" "))))
+        (map (String.tokens (fn c => c = #" ")));
+
+
+fun board_string_to_board board_str =
     let
-        val num_bits = Vector.length (hd bitss);
+        val row_strs = newline_tokenizer board_str;
+        val rows_as_str_vals = cleanup_rows row_strs;
+        val rows = map string_list_to_int_list rows_as_str_vals;
+        val rows_as_vecs = map Vector.fromList rows;
     in
-        let
-            fun iter ((bitss: int vector list), index) =
-                if index < num_bits
-                then
-                    let
-                        val _ = print ("remaining vectors: " ^ Int.toString (length bitss) ^ "\n");
-                        val selected_bit_value = bit_value_selector (bitss, index);
-                        val _ = print ("selected bit value: " ^ Int.toString selected_bit_value ^ "\n\n");
-
-                        val with_selected_bit =
-                            List.filter (fn bits => Vector.sub(bits, index) = selected_bit_value)
-                                        bitss;
-                    in
-                        iter (with_selected_bit, index + 1)
-                    end
-                else
-                    if List.null bitss
-                    then raise Fail "list of bit vectors was empty somehow"
-                    else hd bitss
-        in
-            iter (bitss, 0)
-        end
+        rows_as_vecs
     end;
 
 
-val str = read "input";
-val lines = newline_tokenizer str;
-val lines_as_bits =
-    map (fn line => Vector.fromList (string_to_bits line))
-        lines;
-
-val oxygen_gen_rating_bits: int vector = calculate_rating (lines_as_bits, get_most_common_bit);
-val oxygen_gen_rating = bits_to_decimal oxygen_gen_rating_bits;
-
-val co2_scrubber_rating_bits = calculate_rating (lines_as_bits, get_least_common_bit);
-val co2_scrubber_rating = bits_to_decimal co2_scrubber_rating_bits;
-
-val solution = oxygen_gen_rating * co2_scrubber_rating;
-
-solution;
+val str = FileExtra.read "input";
+val parts = block_tokenizer str;
+val number_sequence =
+    map (fn num_as_str =>
+            case Int.fromString num_as_str of
+                SOME number => number
+              | NONE =>
+                raise Fail "encountered a non-int string")
+        (String.tokens (fn c => c = #",") (hd parts));
+val board_strings = tl parts;
+val boards = map Vector.fromList (map board_string_to_board board_strings);

+ 11 - 0
day-04/build.cm

@@ -0,0 +1,11 @@
+group
+    source (-)
+is
+    $/basis.cm
+    $/smlnj-lib.cm
+    (* custom libs *)
+    lib/file_extra.sml
+    lib/string_extra.sml
+    lib/list_extra.sml
+    lib/int_extra.sml
+    lib/bit_extra.sml

+ 33 - 0
day-04/lib/bit_extra.sml

@@ -0,0 +1,33 @@
+structure Bit = struct
+    fun to_decimal (bit, ind) =
+        (* ind: the index of the bit counted from least significant bit to most
+           significant bit (MSB) *)
+        bit * IntExtra.expt (2, ind);
+
+    fun bits_to_decimal bit_vector =
+        let
+            val len = Vector.length bit_vector;
+            fun iter (bits, ind, acc) =
+                if ind < len
+                then
+                    let
+                        val bit = Vector.sub(bits, ind);
+                        val position = (len - 1) - ind;
+                        val decimal_value = to_decimal (bit, position);
+                    in
+                        iter (bits, ind + 1, acc + decimal_value)
+                    end
+                else
+                    acc;
+        in
+            iter (bit_vector, 0, 0)
+        end;
+
+    fun bit_list_from_string str =
+        map (fn c =>
+                case c of
+                    #"1" => 1
+                  | #"0" => 0
+                  | _ => raise Fail "unrecognized bit value")
+            (String.explode str);
+end;

+ 9 - 0
day-04/lib/file_extra.sml

@@ -0,0 +1,9 @@
+structure FileExtra = struct
+    fun read file =
+        let
+            val inStream = TextIO.openIn file
+        in
+            (* TextIO.inputAll returns a TextIO.vector, which is a string. *)
+            TextIO.inputAll inStream
+        end;
+end;

+ 10 - 0
day-04/lib/int_extra.sml

@@ -0,0 +1,10 @@
+structure IntExtra = struct
+    fun expt (0, _) = 0
+      | expt (1, _) = 1
+      | expt (base, 0) = 1
+      | expt (base, 1) = base
+      | expt (base, exponent) =
+        base * expt (base, exponent - 1);
+    fun even num = (num mod 2) = 0;
+    fun odd num = (num mod 2) = 1;
+end;

+ 26 - 0
day-04/lib/list_extra.sml

@@ -0,0 +1,26 @@
+structure ListExtra = struct
+    fun is_list_prefix nil nil = true
+      | is_list_prefix nil lst_elems = true
+      | is_list_prefix prefix_elems nil = false
+      | is_list_prefix prefix_elems lst_elems =
+        if (hd prefix_elems) = (hd lst_elems)
+        then is_list_prefix (tl prefix_elems) (tl lst_elems)
+        else false;
+
+    fun prepend nil nil = []
+      | prepend xlst nil = xlst
+      | prepend nil ys = ys
+      | prepend (x::nil) ys = x :: ys
+      | prepend (x::xs) ys =
+        x :: prepend xs ys;
+
+    fun sum_lists (nil, nil) = []
+      | sum_lists (nil, l2) = []
+      | sum_lists (l1, nil) = []
+      | sum_lists (alst as (a::arest), blst as (b::brest)) =
+        (a + b) :: sum_lists(arest, brest);
+
+    fun make_list (0, _) = []
+      | make_list (len, fill) =
+        fill :: make_list (len - 1, fill);
+end;

+ 56 - 0
day-04/lib/string_extra.sml

@@ -0,0 +1,56 @@
+structure StringExtra = struct
+    val empty = "";
+
+    fun split sep str =
+        let
+            val chars = String.explode str;
+            val sep_chars = String.explode sep;
+            val sep_len = length sep_chars;
+            val prefix_pred = ListExtra.is_list_prefix sep_chars;
+            fun iter (nil, collected_chars, parts) = String.implode (rev collected_chars) :: parts
+              | iter (remaining_chars as (c::cs), collected_chars, parts) =
+                if prefix_pred remaining_chars
+                then
+                    (* drop the separator, begin anew collecting chars until next separator, *)
+                    iter (List.drop (remaining_chars, sep_len),
+                          [],
+                          String.implode (rev collected_chars) :: parts)
+                else
+                    (* collect characters, which are not part of the prefix *)
+                    iter (cs, c :: collected_chars, parts)
+        in
+            rev (iter (chars, [], []))
+        end;
+
+    fun replace searched replacement str =
+        let
+            val len_searched = String.size searched;
+
+            val chars = String.explode str;
+            val searched_chars = String.explode searched;
+            val replacement_chars = String.explode replacement;
+            val starts_with_searched = ListExtra.is_list_prefix searched_chars;
+
+            fun iter nil = []
+              | iter remaining_chars =
+                if starts_with_searched remaining_chars
+                then
+                    ListExtra.prepend replacement_chars
+                                      (iter (List.drop (remaining_chars, len_searched)))
+                else
+                    (hd remaining_chars) :: iter (tl remaining_chars);
+        in
+            String.implode (iter chars)
+        end;
+
+    fun trim_left pred str =
+        let
+            fun iter nil = []
+              | iter (chars as (c::cs)) =
+                if pred c
+                then iter cs
+                else chars
+        in
+            String.implode (iter (String.explode str))
+        end;
+end;