|
@@ -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);
|