# DAY 4 PROBLEM 1 ADVENT OF CODE
# Get the winning board and calculate the output.

data = """1,76,38,96,62,41,27,33,4,2,94,15,89,25,66,14,30,0,71,21,48,44,87,73,60,50,77,45,29,18,5,99,65,16,93,95,37,3,52,32,46,80,98,63,92,24,35,55,12,81,51,17,70,78,61,91,54,8,72,40,74,68,75,67,39,64,10,53,9,31,6,7,47,42,90,20,19,36,22,43,58,28,79,86,57,49,83,84,97,11,85,26,69,23,59,82,88,34,56,13

85 23 65 78 93
27 53 10 12 26
 5 34 83 25  6
56 40 73 29 54
33 68 41 32 82

 8 31 14 70 91
53 49 86 13 21
66 28 76 78 93
39 63 80 43 23
56 25 60 67 72

67 78 36 64 14
46 16 80 23 94
22 47 51 65 57
33 76 21 92 97
31 95 54 27 20

 1 77 86 43 30
28 88  7  5 60
66 24  3 57 33
38 23 59 84 44
74 47 17 29 85

21 50 86  2 70
85 19 22 93 25
99 38 74 30 65
81  0 47 78 63
34 11 51 88 64

45 15 29 81 30
75 21 88 91 49
39 20  4 17 78
10 12 38 11  7
98  6 65 69 86

36 20 31 44 69
30 65 55 88 64
74 85 82 61  5
57 17 90 43 54
58 83 52 23  7

42 16 82 86 76
60 26 27 59 55
 7 53 22 78  5
18 61 10 15 17
28 46 14 87 77

21 43 15 47 61
24 76 28  3 27
19 62 69 82 93
49 29 97 74 41
92 36 37 99 40

31  4  3 62 51
24 57 78 67 53
13  5 76 38 55
79  9 75 98 71
65  1 39 18 47

59  4 38 95 99
85 68 69 93 43
83 57 48 42 15
47 50 80 79 90
56 87 78 64 25

21 37 14 67 95
88 39 26 38 49
89 83 54 77 96
48 86 94 19 20
43 41  8 74 58

 1 36 12 90 91
63 21 98 82 66
39 86  7 52 77
80 81 44 33 58
78 30 11 51 28

81 74  7 33 96
75 60 87 47 91
39 73 30 50 13
 4 41  9 43 77
34 82 72 48 12

93 63 74 25 57
29 76  9 45 70
98 77 71 16 41
47 54 18 14 55
31 89 67 87 83

 8 72 45 93 68
74 26 69 94 65
28  9 20 47 41
46 54 21 56 22
84 62 18 15 48

20 51 81 40 69
71 10 13 93 75
44 86  0 95 37
99 39 76 80 66
14 64 49 62 27

75  7 51 86 79
43 30 61 39 16
85 63 90 28 96
88 78 72 31 73
98 87 23 19 58

20 95 47 97 12
92 25 68 87 91
37 10 78 23 63
74 93 58 39  5
76 51 48 72 16

37 18 32 34 85
22 31 98 42 19
29 72 48 76 25
47  1 21  7 53
79 82 86 52 78

20 16 47 78 92
88 15 71 67  2
 5 52 90 70  9
22 49 28 82 27
 6 19 61 73 48

71 26  7 11 79
52 30 47  1 31
17 75 94 91 28
81 98 23 55 21
77 15 39 24 16

 5 75 44 88 65
89 45 23 69 19
41 61 67 52 54
47 38 57 12 98
62 70 26 87 53

50  4 65 77 25
 6 21  5 27 92
39 63 97 75 79
60 34 87 26 74
99 24 44 85  2

13 64 38 78 21
74 17 83 57 94
25 39 69 53  4
54 33 81 50 76
42 75 19 77 26

63 31 70 19 39
38 87 15 90 75
61 98  6 29 86
78 62 32 11 60
55 97 13 73 82

51 63 68 84 36
12 33 37 31  8
18 41 34 74 23
72 39 85 48 60
24 19 29 88  0

46 51 17 23 13
20 93 97 99 81
57 47 33 84 44
28 96  2 43 56
68 36 62 15  5

81 99  5 30 10
38 62 57  8 37
 7 86 98  3 54
46 82 96 15 72
83  1 75 25 50

47 57 11 61 27
53 10 31 91 98
76 85 55 38 23
 6 81 67 71 70
35 29 17 50 56

24 65 15  1 89
45 60 97 23 14
84 56 58  5 54
 3 72 51 46 79
67 70 78 34 77

38 11 54 23  2
33 14 10 96 63
43  5 36 20 30
70 53 66 71  9
91 90 21  7 88

94 44  4 86 26
39 70 54 50 30
55 40 12 72 71
68  7 66 47 91
31 24 13  1 96

79 14 40 87 68
16 32 53 46 98
38 95 21 89 69
62 60 19 81 33
70 52 28 83  0

62 42 38 48 64
61 79 78 97 98
89  7  3 29 68
92 76 14 67  1
41 99 72 47 60

 5 75 18 42 33
72 61 36 31 29
19 58  1 34 94
54 84 92 99 38
76 68 79 53 37

14 91 37  5 98
68 29 34 76 43
75  0 67 33 69
81 47 58 30 93
88 92 42 77 54

64 24 28 54 53
72 68  3 73  4
83  6 59 66 94
87 80 55 20 16
13 82 74 31 70

63 92 71  0 83
98 40 50 55  2
88  5 85 30 23
10 75 81 58 68
51 31 14 89  1

67 93 94 54 53
38 71 34 40 24
31 63 30 99 75
 4 57 86 19 70
60 49 87 68 74

56 94 79 53  7
24 12 19  6 99
82 51 41 46 43
17 49 52 78 55
75 48 61 70 87

14 55 32 21 31
88 83 23 44  4
 1 77 45 90 85
46 81 51 27 62
60 24 29 18  0

95 92 91 27 26
22 43 45 64 62
83 23 25 85 94
84 53 72 28 20
75 60 52 18 73

95 41  7 21 32
58 65 16 56 97
68 25 91 83 24
66 89 15 55  6
 2 30 84 10 90

58 86 44 19 74
57 89 17  6 83
77 35 60 32 13
97 63 62 28 76
55 31 11  0 52

33 39 59 42 45
61 50 92  9 79
15  0 28  5 72
91 24 21 29 87
86 76 43 31 93

63 11 86 45 85
96 74 66 93 32
95 30 99 23 18
69 97 48 15  1
42 87 47 83 80

93  5 40 64  2
44 51 15 54 83
69 77 90 58 11
 0 48 43 30 55
25 72 38 73 52

89 58 71 68 15
23 65  9 36 74
21 29 42 79 98
55 47 33 39 28
16 75 91 69 57

13 79 12 71  2
60 94 99 43 82
84 89 29 91 87
74 80 25 32 21
70 14 68 92 11

78  1 16 51 87
58 94 59 15 43
79 41 50 47 39
53 37  9 28 72
34 63 89 35 18

31 67 70 42 43
60  2 89 49 22
56 17 81 24 74
20 65  1 96 51
68  7  0 38 25

59 14 29 53 19
 9  2 11 33 44
81  6 10 47 58
20 34 62 55 40
71 38 69 45 78

59 36 70 42 21
 3 16 49 79 98
74 25  8 84 19
61 80 47 65 64
91 62 52  9 40

 1 85 63  7  2
 0 20 61 26 77
99 37 74 42 76
25 94 19 78 60
79 72 95 22 11

51 21 79 76 32
55 23 69 19 61
71 54 94 47 92
 5 64  6 68 16
91 81  9 99 30

61 69 82 86 68
66 81 28 38 36
26 29 31 11  8
72 51 12 95 63
18 30 88 17 32

34  8 14 42 67
66 79 65 20 52
37 87 74 24  3
59 54 21 32 89
31  4 62 76 30

11 93  8 92 55
38 72 99  3 83
12 75  0 41 46
17 25  5 39 48
14 18 86 29 84

 6 20 41 51 48
 5 67 30 24 47
 3  8 92 22 39
 4 56 36 31 75
 2 45 85 81 96

47 43 72 22  3
19 87 53 12 60
29 40 56 68 18
66 97 70 33 39
85 37  0 90 98

61 35 81 84 94
11  1 58 45 77
 6 99 67 36 43
 5  7  0 87 80
44 78 39 70 20

58 34 49 29 75
17 15 28 23 84
59 25 92 48  0
20 81 47  3 71
68 60  5 22 87

90 32 41 39  6
36 78 67 24 50
55 72 52 75 44
87 15 92 31 58
83 89 68 19 43

99 44 53 68 25
71 67 16 19 36
35 58 14 86 48
88 18 61 24 23
87  9 91 37 15

37  5 63 68 28
41 50 76 99 64
34 92 78 94 71
11 96 97 42 58
33 45  0 93 48

33 68  9 12 81
60 98 28  8 99
14 17  6 82 15
57 69 43 38 29
47 84 76 22 18

79 70 92 38 47
12 82 98 46  0
76 15 53 59 97
18 52 49 29 96
44 64 68 89 24

95 14 17 27 42
55 43 57 29 25
34 73 86 50 16
69 37 75 63 39
78 79  3  4 30

27 31 15 92 46
36 23 72 40 50
51 99 55 89 21
12 70 84 63 85
78 88 77 75  0

15 67 40 39 28
 9 79 22 52 75
96 65 86 98 14
97 87 44 84 68
36 26 89 43 27

79 59 48 27 36
85 92 93 76 24
 2 25  7 42 90
23 29 74 35 86
58 60 31 75 57

10 43 83 75  8
88 12 38 30  9
60 67 59 76  6
55 45 74 34 25
97 49 65 96 69

59 86 15  3 19
89  4 74 61 23
52 98  8 79 39
95 17 22 14 51
50 18 94 30 84

19 63 58 72 67
35 93 29 91  0
39 26 43 84 21
70 42  2 53 12
59 99  8  1 86

23 86 34 22 65
71 10 16 50 91
66 89 49 81 43
40  7 26 75 61
62 59  2 46 95

24 21  0 49 25
92 42 48 12  7
81 93 59 68  3
14 23 63 39 29
35 43  6 44 89

67 74 95 34 10
39 90 59 44 51
17 16 97 24 62
20 54 76 63 88
87 66 14 78 82

96 86 67 59 79
66  3 30 77 71
 2 91 99 82 31
48 65 75 98 53
63 54 64 76  1

85 96 40 98 24
16 20 10 23 17
79 59 53 42 65
67  2  5 80 75
62 38 19 74 73

43 10 79 92  8
52 36  4  5 67
56 29 33 24 97
85 17 53 75 65
62 64  1 21 83

93 92 79 17 12
40 88  6 82 34
90 96 53 25 43
14 62 54 10 39
49 68 41 16 44

67 99 24 58 76
43 53 59 54 51
47  6 61  8  2
80 68 90 14  4
29 46 94 89 50

14 45 19 33 43
 6 55  4 31 80
51  2 69 68 61
71 70 79 91 93
66 18 54 13 87

 8 45 61 54 30
85 16 19 82 37
56 39 11 47  4
74 70 10 60 91
21 63 95 53 72

71 21 63 86 27
53 52 40 23 81
 2 47 92 68 15
46 45 31  8  1
34 80 37 11 69

96  0 15 90 66
65 43 92 83 18
 3 47 19  8 32
71 26 42 34 28
62 99 55  5 12

37 99 30 21  3
63 18 68 47 27
57  0 65 85 20
 7 58 40 92 43
15 19  5  4 53

46 16 45 95 68
 6 44 31 47 73
84 82 71 75 94
26 25 17 32 49
18 96 13 58  9

71 36 13 68 10
84  7 60 79 41
 1 83 43 81 97
90 53 80 19 38
48 25 32 42 29

37 68 86 44 78
87 67 77 70 60
45 34 27 15 47
12 21 13 55 26
81 41 63 40 74

24 50 93 94 57
99  4 56  5 28
42 31 22  6 76
90 89 16 49 59
 9  7 43 71 54

69 75 94 38 46
52 64 50 72 42
76 63 13 60 10
99 80 43 33 17
25 31  4 89 22

88 57 22 66 34
85 16 87 95 59
73  2 46  5 29
25 69 53  6 14
96 77 19 91 43

46 99 52 47 76
89 53 24 13 59
45  5  1 30 19
68 25 22 10 73
42 27 31  0 94

42 44 98 89 87
65 10 80 56 41
 3 35 95 48 43
85 97 83 12 94
50 38 93 47 17

16 73 18 81 89
 6 48 54 93 19
35 52 88 49 31
43 79 83 14 28
50 62 98 26 22

38 47  7 20 35
45 76 63 96 24
98 53  2 87 80
83 86 92 48  1
73 60 26 94  6

80 50 29 53 92
66 90 79 98 46
40 21 58 38 60
35 13 72 28  6
48 76 51 96 12

79 80 24 37 51
86 70  1 22 71
52 69 10 83 13
12 40  3  0 30
46 50 48 76  5"""

"""
"""
function parse_board(board::AbstractString) ::Vector{Vector{Integer}}
    return [[parse(Int16, n) for n in split(row, ' ') if !isempty(n)]
            for row in split(board, '\n')]
end

"""
"""
function parse_boards(boards::AbstractString) ::Tuple{Vector{Integer}, Vector{Vector{Vector{Integer}}}}
    # Get individual boards and number draws.
    boards = split(boards, "\n\n")
    # Get number draws.
    numbers = [parse(Int16, n) for n in split(first(boards), ',')]
    # return number draws, the parsed boards.
    return numbers, [parse_board(b) for b in boards[2:end]]
end

"""
"""
function get_board_dimensions(board::Vector{Vector{Integer}}) ::Tuple{Integer, Integer}
    return length(board), length(first(board))
end

"""
"""
function get_valid_board_start_indexes(board::Vector{Vector{Integer}}; n::Integer=5) ::Vector{Tuple{Integer, Integer}}
    # Get the dimensions of table and maximum x and y to get n adjacent items.
    y_dim, x_dim = get_board_dimensions(board)
    x_max = x_dim - (n-1)
    y_max = y_dim - (n-1)
    # Get indexes to start from to get n successive items.
    indexes::Vector{Tuple{Integer, Integer}} = []
    # Get x indexes.
    for (x,y) in Iterators.product(1:x_max, 1:y_dim)
        push!(indexes, (x,y))
    end
    # Get y indexes.
    for (x,y) in Iterators.product(2:x_dim, 1:y_max)
        push!(indexes, (x,y))
    end
    return indexes
end


"""
"""
function get_sequences(board::Vector{Vector{Integer}}, x::Integer, y::Integer; n::Integer=5) ::Vector{Vector{Integer}}
    # Establish return.
    returnval::Vector{Vector{Integer}} = []
    # Get the dimensions of table and maximum x and y to get n adjacent items.
    y_dim::Integer, x_dim::Integer = get_board_dimensions(board)
    x_max::Integer = x + n - 1
    y_max::Integer = y + n - 1
    # Check if we have enough items left to get the column and row to get a sequence of n.
    row_valid::Bool = x_max <= x_dim
    col_valid::Bool = y_max <= y_dim
    # Add items.
    if row_valid
        push!(returnval, board[y][x:x_max])
    end
    if col_valid
        push!(returnval, [board[i][x] for i=y:y_max])
    end
    if (row_valid && col_valid)
        push!(returnval, [board[y+i][x+i] for i=0:n-1])
    end
    # handle up and right diagonal case.
    if (row_valid && (y - n + 1) >= 1)
        push!(returnval, [board[y-i][x+i] for i=0:n-1])
    end
    return returnval
end


"""
TODO solve this function.
"""
function get_board_axes(board::Vector{Vector{Integer}}; n::Integer=5) # ::Vector{Vector{Integer}}
    """
    1 1 1 1 1
    1 0 0 0 0
    1 0 0 0 0
    1 0 0 0 0
    1 0 0 0 0

    1 1 1 1 1 1
    1 1 0 0 0 0
    1 1 0 0 0 0
    1 1 0 0 0 0
    1 1 0 0 0 0

    If we come up with an iteration method that hits only the cells marked 1
    for each array, we can use them to get items on the diagonal, horizontal,
    and vertical with length 5.
    """
    return [i
            for (x, y) in get_valid_board_start_indexes(board, n=n)
            for i in get_sequences(board, x, y, n=n)]
end


"""
"""
function is_winner(board::Vector{Vector{Integer}}, draws::Vector{<:Integer}; n::Integer=5) ::Bool
    return any(all(x in draws for x in axis)
               for axis in get_board_axes(board, n=n))
end


"""
"""
function get_winning_board(boards::Vector{Vector{Vector{Integer}}}, draws::Vector{Integer}; n::Integer=5) ::Tuple{Vector{Vector{Integer}}, Vector{Integer}}
    # Iterate from n to all numbers drawn. 
    for i=n:length(draws)
        drawn = draws[begin:i]
        # See if any boards win given this set of draws.
        for board in boards
            if is_winner(board, drawn, n=n)
                return board, drawn
            end
        end
    end
    return nothing
end

"""
"""
function calculate_board_score(board::Vector{Vector{Integer}}, drawn::Vector{Integer}) ::Integer
    score = sum(x for x in Iterators.flatten(board) if !(x in drawn))
    return score * drawn[end]
end

draws, boards = parse_boards(data)
winning_board, drawn = get_winning_board(boards, draws)
calculate_board_score(winning_board, drawn)