adamcrussell (adamcrussell) wrote,
adamcrussell
adamcrussell

2020 Advent Of Code Day 4

Prolog. Developed and tested with SWI-Prolog 8.0.3.

check_and_read(10, [] ,_):-
    !.
check_and_read(13, [], _):-
    !.
check_and_read(32, [], _):-
    !.
check_and_read(end_of_file, [], _):-
    !.
check_and_read(Char, [Char|Chars], Stream):-
    get_code(Stream, NextChar),
    check_and_read(NextChar, Chars, Stream).
    
read_data(Stream, []):-
    at_end_of_stream(Stream).
read_data(Stream, [X|L]):-
    \+ at_end_of_stream(Stream),
    get_code(Stream, Char),
    check_and_read(Char, Chars, Stream),
    atom_codes(X, Chars),
    read_data(Stream, L).
 
records(Lines, Records):-
    records(Lines, [[]], Records).
records([], Records, Records).
records([H|T], [HAccum|TAccum], Records):-
    atom_codes(H, [C|_]),
    \+ C == 32,
    append(HAccum, [H], NewHAccum),
    records(T, [NewHAccum|TAccum], Records).
records([_|T], [HAccum|TAccum], Records):-    
    records(T, [[],HAccum|TAccum], Records).    
 
key(KeyValue, Key):-
    key(KeyValue, '', Key).
key([], Key, Key).
key([H|T], KeyAccum, Key):-
    char_code(H, C),
    \+ C == 58,
    atom_concat(KeyAccum, H, Accum),
    key(T, Accum, Key).
key([_|_], KeyAccum, Key):-
    key([], KeyAccum, Key).
 
value(KeyValue, Value):-
    value(KeyValue, '', Value).
value([], Value, Value).
value([H|T], ValueAccum, Value):-
    char_code(H, C),
    \+ C == 58,
    atom_concat(ValueAccum, H, Accum),
    value(T, Accum, Value).
value([_|T], _, Value):-
    value(T, '', Value).
 
key_value(KeyValue, Key, Value):-
    atom_chars(KeyValue, KV),
    key(KV, Key),
    value(KV, Value).
 
all_keys(Record, Keys):-
    all_keys(Record, [], Keys).
all_keys([], Keys, Keys).
all_keys([H|T], KeysAccum, Keys):-
    key_value(H, Key, _),
    all_keys(T, [Key|KeysAccum], Keys).
 
all_values(Record, Values):-
    all_values(Record, [], Values).
all_values([], Values, Values).
all_values([H|T], ValuesAccum, Values):-
    key_value(H, _, Value),
    all_values(T, [Value|ValuesAccum], Values).    
 
all_keys_values(Record, KeysValues):-
    all_keys_values(Record, [], KeysValues).
all_keys_values([], KeysValues, KeysValues).
all_keys_values([H|T], KeysValuesAccum, KeysValues):-
    key_value(H, Key, Value),
    all_keys_values(T, [Key, Value|KeysValuesAccum], KeysValues).  
 
record_keys(Records, RecordKeys):-
    record_keys(Records, [], RecordKeys).
record_keys([], RecordKeys, RecordKeys).
record_keys([H|T], RecordKeysAccum, RecordKeys):-
    all_keys(H, Keys),
    record_keys(T, [Keys|RecordKeysAccum], RecordKeys).
 
record_values(Records, RecordValues):-
    record_values(Records, [], RecordValues).
record_values([], RecordValues, RecordValues).
record_values([H|T], RecordValuesAccum, RecordValues):-
    all_values(H, Values),
    record_values(T, [Values|RecordValuesAccum], RecordValues).
 
record_keys_values(Records, RecordKeysValues):-
    record_keys_values(Records, [], RecordKeysValues).
record_keys_values([], RecordKeysValues, RecordKeysValues).
record_keys_values([H|T], RecordKeysValuesAccum, RecordKeysValues):-
    all_keys_values(H, KeysValues),
    record_keys_values(T, [KeysValues|RecordKeysValuesAccum], RecordKeysValues).
 
validate_keys(RecordKeys, ValidRecords):-
    validate_keys(RecordKeys, [], ValidRecords).
validate_keys([], ValidRecords, ValidRecords).
validate_keys([H|T], ValidRecordsAccum, ValidRecords):-
    member(iyr, H), member(byr, H), member(eyr, H),  
    member(hgt, H), member(hcl, H), member(ecl, H), member(pid, H),
    validate_keys(T, [H|ValidRecordsAccum], ValidRecords).
validate_keys([_|T], ValidRecordsAccum, ValidRecords):-
    validate_keys(T, ValidRecordsAccum, ValidRecords).
 
hgt_number(HGT, N):-
    hgt_number(HGT, [], N).
hgt_number([], N, N).
hgt_number([H|T], NAccum, N):-
    H >= 48, H =< 57,
    append(NAccum, [H], Accum),
    hgt_number(T, Accum, N).
hgt_number([_|_], NAccum, N):-
    hgt_number([], NAccum, N).
    
valid_iyr(Value):-
    atom_codes(Value, C), 
    number_codes(N, C),
    N >= 2010,
    N =< 2020.
    
valid_byr(Value):-
    atom_codes(Value, C), 
    number_codes(N, C),
    N >= 1920,
    N =< 2002.
    
valid_eyr(Value):-
    atom_codes(Value, C), 
    number_codes(N, C),
    N >= 2020,
    N =< 2030.
    
valid_hgt(Value):-
    atom_codes(Value, C),
   length(C, CL),
    Ultima is CL - 1,
    Penultima is CL - 2,
    (
       (nth0(Penultima, C, Char0),
        nth0(Ultima, C, Char1), 
        Char0 == 99,
        Char1 == 109,
        hgt_number(C, NC),!,
        number_codes(N, NC),
        N >= 150, N =< 193);
       (nth0(Penultima, C, Char0),
        nth0(Ultima, C, Char1), 
        Char0 == 105,
        Char1 == 110,
        hgt_number(C, NC),!,
        number_codes(N, NC),
        N >= 59, N =< 76)
    ).
    
valid_hcl(Value):-
    atom_codes(Value, C),
    nth0(0, C, E0), E0 == 35,
    nth0(1, C, E1), ((E1 >= 48, E1 =< 57); (E1 >= 97, E1 =< 102)),
    nth0(2, C, E2), ((E2 >= 48, E2 =< 57); (E2 >= 97, E2 =< 102)),
    nth0(3, C, E3), ((E3 >= 48, E3 =< 57); (E3 >= 97, E3 =< 102)),
    nth0(4, C, E4), ((E4 >= 48, E4 =< 57); (E4 >= 97, E4 =< 102)),
    nth0(5, C, E5), ((E5 >= 48, E5 =< 57); (E5 >= 97, E5 =< 102)),
    nth0(6, C, E6), ((E6 >= 48, E6 =< 57); (E6 >= 97, E6 =< 102)).
    
valid_ecl(Value):-
   Value == amb;
    Value == blu;
    Value == brn;
    Value == gry;
    Value == grn;
    Value == hzl;
    Value == oth.
    
valid_pid(Value):-
    atom_codes(Value, C), 
    length(C, L), L == 9,
    nth0(0, C, N0), N0 >= 48, N0 =< 57,
    nth0(1, C, N1), N1 >= 48, N1 =< 57,
    nth0(2, C, N2), N2 >= 48, N2 =< 57,
    nth0(3, C, N3), N3 >= 48, N3 =< 57,
    nth0(4, C, N4), N4 >= 48, N4 =< 57,
    nth0(5, C, N5), N5 >= 48, N5 =< 57,
    nth0(6, C, N6), N6 >= 48, N6 =< 57,
    nth0(7, C, N7), N7 >= 48, N7 =< 57,
    nth0(8, C, N8), N8 >= 48, N8 =< 57.
    
valid_cid(_):-
    true.
 
validate_key_value([]). 
validate_key_value([Key, Value|T]):-
    ( (Key == iyr, valid_iyr(Value));
      (Key == byr, valid_byr(Value));
      (Key == eyr, valid_eyr(Value));
      (Key == hgt, valid_hgt(Value));
      (Key == hcl, valid_hcl(Value));
      (Key == ecl, valid_ecl(Value));
      (Key == pid, valid_pid(Value));
      (Key == cid, valid_cid(Value))
    ),
    validate_key_value(T).
    
validate_keys_values(RecordKeysValues, ValidRecords):-
    validate_keys_values(RecordKeysValues, [], ValidRecords).
validate_keys_values([], ValidRecords, ValidRecords).
validate_keys_values([H|T], ValidRecordsAccum, ValidRecords):-
    member(iyr, H), member(byr, H), member(eyr, H),  
    member(hgt, H), member(hcl, H), member(ecl, H), member(pid, H),
    validate_key_value(H),
    validate_keys_values(T, [H|ValidRecordsAccum], ValidRecords).
validate_keys_values([_|T], ValidRecordsAccum, ValidRecords):-
    validate_keys_values(T, ValidRecordsAccum, ValidRecords).    
 
write_records([]).
write_records([H|T]):-
    write(H),nl,
    write_records(T).
 
main:-
    open('data', read, Stream),
    read_data(Stream, Lines),
    close(Stream),
    records(Lines, Records),
    length(Records, RecordLength),
    format("There are ~d passport records.~n", [RecordLength]),
    record_keys(Records, RecordKeys),
    validate_keys(RecordKeys, ValidRecords),
    length(ValidRecords, ValidLength),
    format("There are ~d valid passport records based only on keys.~n", [ValidLength]),
    record_keys_values(Records, RecordKeysValues),
    validate_keys_values(RecordKeysValues, ValidRecordsKeysValues),
    length(ValidRecordsKeysValues, ValidRecordsKeysValuesLength),
    format("There are ~d valid passport records by validating keys and values.~n", [ValidRecordsKeysValuesLength]).
Tags: advent of code, logic programming, prolog, prolog programming
Subscribe

Recent Posts from This Journal

Comments for this post were disabled by the author