PAM_250 = Dict()
PAM_250["A"] = Dict("A" => 2, "R" => -2, "N" => 0, "D" => 0, "C" => -2, "Q" => 0, "E" => 0, "G" => 1,
                    "H" => -1, "I" => -1, "L" => -2, "K" => -1, "M" => -1, "F" => -3, "P" => 1, "S" => 1,
                    "T" => 1, "W" => -6, "Y" => -3, "V" => 0, "B" => 0, "J" => -1, "Z" => 0, "X" => -1)
PAM_250["R"] = Dict("A" => -2, "R" => 6, "N" => 0, "D" => -1, "C" => -4, "Q" => 1, "E" => -1, "G" => -3,
                    "H" => 2, "I" => -2, "L" => -3, "K" => 3, "M" => 0, "F" => -4, "P" => 0, "S" => 0,
                    "T" => -1, "W" => 2, "Y" => -4, "V" => -2, "B" => -1, "J" => -3, "Z" => 0, "X" => -1)
PAM_250["N"] = Dict("A" => 0, "R" => 0, "N" => 2, "D" => 2, "C" => -4, "Q" => 1, "E" => 1, "G" => 0,
                    "H" => 2, "I" => -2, "L" => -3, "K" => 1, "M" => -2, "F" => -3, "P" => 0, "S" => 1,
                    "T" => 0, "W" => -4, "Y" => -2, "V" => -2, "B" => 2, "J" => -3, "Z" => 1, "X" => -1)
PAM_250["D"] = Dict("A" => 0, "R" => -1, "N" => 2, "D" => 4, "C" => -5, "Q" => 2, "E" => 3, "G" => 1,
                    "H" => 1, "I" => -2, "L" => -4, "K" => 0, "M" => -3, "F" => -6, "P" => -1, "S" => 0,
                    "T" => 0, "W" => -7, "Y" => -4, "V" => -2, "B" => 3, "J" => -3, "Z" => 3, "X" => -1)
PAM_250["C"] = Dict("A" => -2, "R" => -4, "N" => -4, "D" => -5, "C" => 12, "Q" => -5, "E" => -5, "G" => -3,
                    "H" => -3, "I" => -2, "L" => -6, "K" => -5, "M" => -5, "F" => -4, "P" => -3, "S" => 0,
                    "T" => -2, "W" => -8, "Y" => 0, "V" => -2, "B" => -4, "J" => -5, "Z" => -5, "X" => -1)
PAM_250["Q"] = Dict("A" => 0, "R" => 1, "N" => 1, "D" => 2, "C" => -5, "Q" => 4, "E" => 2, "G" => -1,
                    "H" => 3, "I" => -2, "L" => -2, "K" => 1, "M" => -1, "F" => -5, "P" => 0, "S" => -1,
                    "T" => -1, "W" => -5, "Y" => -4, "V" => -2, "B" => 1, "J" => -2, "Z" => 3, "X" => -1)
PAM_250["E"] = Dict("A" => 0, "R" => -1, "N" => 1, "D" => 3, "C" => -5, "Q" => 2, "E" => 4, "G" => 0,
                    "H" => 1, "I" => -2, "L" => -3, "K" => 0, "M" => -2, "F" => -5, "P" => -1, "S" => 0,
                    "T" => 0, "W" => -7, "Y" => -4, "V" => -2, "B" => 3, "J" => -3, "Z" => 3, "X" => -1)
PAM_250["G"] = Dict("A" => 1, "R" => -3, "N" => 0, "D" => 1, "C" => -3, "Q" => -1, "E" => 0, "G" => 5,
                    "H" => -2, "I" => -3, "L" => -4, "K" => -2, "M" => -3, "F" => -5, "P" => 0, "S" => 1,
                    "T" => 0, "W" => -7, "Y" => -5, "V" => -1, "B" => 0, "J" => -4, "Z" => 0, "X" => -1)
PAM_250["H"] = Dict("A" => -1, "R" => 2, "N" => 2, "D" => 1, "C" => -3, "Q" => 3, "E" => 1, "G" => -2,
                    "H" => 6, "I" => -2, "L" => -2, "K" => 0, "M" => -2, "F" => -2, "P" => 0, "S" => -1,
                    "T" => -1, "W" => -3, "Y" => 0, "V" => -2, "B" => 1, "J" => -2, "Z" => 2, "X" => -1)
PAM_250["I"] = Dict("A" => -1, "R" => -2, "N" => -2, "D" => -2, "C" => -2, "Q" => -2, "E" => -2, "G" => -3,
                    "H" => -2, "I" => 5, "L" => 2, "K" => -2, "M" => 2, "F" => 1, "P" => -2, "S" => -1,
                    "T" => 0, "W" => -5, "Y" => -1, "V" => 4, "B" => -2, "J" => 3, "Z" => -2, "X" => -1)
PAM_250["L"] = Dict("A" => -2, "R" => -3, "N" => -3, "D" => -4, "C" => -6, "Q" => -2, "E" => -3, "G" => -4,
                    "H" => -2, "I" => 2, "L" => 6, "K" => -3, "M" => 4, "F" => 2, "P" => -3, "S" => -3,
                    "T" => -2, "W" => -2, "Y" => -1, "V" => 2, "B" => -3, "J" => 5, "Z" => -3, "X" => -1)
PAM_250["K"] = Dict("A" => -1, "R" => 3, "N" => 1, "D" => 0, "C" => -5, "Q" => 1, "E" => 0, "G" => -2,
                    "H" => 0, "I" => -2, "L" => -3, "K" => 5, "M" => 0, "F" => -5, "P" => -1, "S" => 0,
                    "T" => 0, "W" => -3, "Y" => -4, "V" => -2, "B" => 1, "J" => -3, "Z" => 0, "X" => -1)
PAM_250["M"] = Dict("A" => -1, "R" => 0, "N" => -2, "D" => -3, "C" => -5, "Q" => -1, "E" => -2, "G" => -3,
                    "H" => -2, "I" => 2, "L" => 4, "K" => 0, "M" => 6, "F" => 0, "P" => -2, "S" => -2,
                    "T" => -1, "W" => -4, "Y" => -2, "V" => 2, "B" => -2, "J" => 3, "Z" => -2, "X" => -1)
PAM_250["F"] = Dict("A" => -3, "R" => -4, "N" => -3, "D" => -6, "C" => -4, "Q" => -5, "E" => -5, "G" => -5,
                    "H" => -2, "I" => 1, "L" => 2, "K" => -5, "M" => 0, "F" => 9, "P" => -5, "S" => -3,
                    "T" => -3, "W" => 0, "Y" => 7, "V" => -1, "B" => -4, "J" => 2, "Z" => -5, "X" => -1)
PAM_250["P"] = Dict("A" => 1, "R" => 0, "N" => 0, "D" => -1, "C" => -3, "Q" => 0, "E" => -1, "G" => 0,
                    "H" => 0, "I" => -2, "L" => -3, "K" => -1, "M" => -2, "F" => -5, "P" => 6, "S" => 1,
                    "T" => 0, "W" => -6, "Y" => -5, "V" => -1, "B" => -1, "J" => -2, "Z" => 0, "X" => -1)
PAM_250["S"] = Dict("A" => 1, "R" => 0, "N" => 1, "D" => 0, "C" => 0, "Q" => -1, "E" => 0, "G" => 1,
                    "H" => -1, "I" => -1, "L" => -3, "K" => 0, "M" => -2, "F" => -3, "P" => 1, "S" => 2,
                    "T" => 1, "W" => -2, "Y" => -3, "V" => -1, "B" => 0, "J" => -2, "Z" => 0, "X" => -1)
PAM_250["T"] = Dict("A" => 1, "R" => -1, "N" => 0, "D" => 0, "C" => -2, "Q" => -1, "E" => 0, "G" => 0,
                    "H" => -1, "I" => 0, "L" => -2, "K" => 0, "M" => -1, "F" => -3, "P" => 0, "S" => 1,
                    "T" => 3, "W" => -5, "Y" => -3, "V" => 0, "B" => 0, "J" => -1, "Z" => -1, "X" => -1)
PAM_250["W"] = Dict("A" => -6, "R" => 2, "N" => -4, "D" => -7, "C" => -8, "Q" => -5, "E" => -7, "G" => -7,
                    "H" => -3, "I" => -5, "L" => -2, "K" => -3, "M" => -4, "F" => 0, "P" => -6, "S" => -2,
                    "T" => -5, "W" => 17, "Y" => 0, "V" => -6, "B" => -5, "J" => -3, "Z" => -6, "X" => -1)
PAM_250["Y"] = Dict("A" => -3, "R" => -4, "N" => -2, "D" => -4, "C" => 0, "Q" => -4, "E" => -4, "G" => -5,
                    "H" => 0, "I" => -1, "L" => -1, "K" => -4, "M" => -2, "F" => 7, "P" => -5, "S" => -3,
                    "T" => -3, "W" => 0, "Y" => 10, "V" => -2, "B" => -3, "J" => -1, "Z" => -4, "X" => -1)
PAM_250["V"] = Dict("A" => 0, "R" => -2, "N" => -2, "D" => -2, "C" => -2, "Q" => -2, "E" => -2, "G" => -1,
                    "H" => -2, "I" => 4, "L" => 2, "K" => -2, "M" => 2, "F" => -1, "P" => -1, "S" => -1,
                    "T" => 0, "W" => -6, "Y" => -2, "V" => 4, "B" => -2, "J" => 2, "Z" => -2, "X" => -1)
PAM_250["B"] = Dict("A" => 0, "R" => -1, "N" => 2, "D" => 3, "C" => -4, "Q" => 1, "E" => 3, "G" => 0,
                    "H" => 1, "I" => -2, "L" => -3, "K" => 1, "M" => -2, "F" => -4, "P" => -1, "S" => 0,
                    "T" => 0, "W" => -5, "Y" => -3, "V" => -2, "B" => 3, "J" => -3, "Z" => 2, "X" => -1)
PAM_250["J"] = Dict("A" => -1, "R" => -3, "N" => -3, "D" => -3, "C" => -5, "Q" => -2, "E" => -3, "G" => -4,
                    "H" => -2, "I" => 3, "L" => 5, "K" => -3, "M" => 3, "F" => 2, "P" => -2, "S" => -2,
                    "T" => -1, "W" => -3, "Y" => -1, "V" => 2, "B" => -3, "J" => 5, "Z" => -2, "X" => -1)
PAM_250["Z"] = Dict("A" => 0, "R" => 0, "N" => 1, "D" => 3, "C" => -5, "Q" => 3, "E" => 3, "G" => 0,
                    "H" => 2, "I" => -2, "L" => -3, "K" => 0, "M" => -2, "F" => -5, "P" => 0, "S" => 0,
                    "T" => -1, "W" => -6, "Y" => -4, "V" => -2, "B" => 2, "J" => -2, "Z" => 3, "X" => -1)
PAM_250["X"] = Dict("A" => -1, "R" => -1, "N" => -1, "D" => -1, "C" => -1, "Q" => -1, "E" => -1, "G" => -1,
                    "H" => -1, "I" => -1, "L" => -1, "K" => -1, "M" => -1, "F" => -1, "P" => -1, "S" => -1,
                    "T" => -1, "W" => -1, "Y" => -1, "V" => -1, "B" => -1, "J" => -1, "Z" => -1, "X" => -1)

# score same as fitness but without building the string
function score_gap_list_pam250(input_sequence_set, gap_list, sequence_length, score_list, gap_ext_penalty)
    sequence_length = Int(sequence_length)
    score = 0
    num_items = length(input_sequence_set)
    # start offsets for accessing with respect to current index,
    # ex: [AAA] w/ gap [2,3] = [A__AA] - a 5 item string
    # but instead of building string, we want to look at A, then gap of 2, 3, then AAA
    # so index will be 1-5, when needing second A, which should be index 4, offsets will be
    # +2 gap_list, -2 sequence_list, so index of 4 will give 2 into sequence_list and show
    # that we've looked past the end of the gap list (because we already had 2 gaps)
    gap_offset_list = fill(0, num_items)

    prev_gaps = fill(false, num_items)

    gap_list_begin = fill(0, num_items)
    gap_list_end = fill(sequence_length + 1, num_items)

    
    #println("starting")
    for i = 1:num_items
        for j = 1:length(gap_list[i])
            if gap_list[i][j] == gap_list_begin[i] + 1
                gap_list_begin[i] = gap_list[i][j]
                #println("here")
            else
                break
            end
        end
    end

    for i = 1:num_items
        for j = length(gap_list[i]):-1:1
            if gap_list[i][j] == gap_list_end[i] - 1
                gap_list_end[i] = gap_list[i][j]
                #println("here2")
            else
                break
            end
        end
    end
    

    # make the last item an overflow position
    for i = 1:num_items
        push!(gap_list[i], -1)
    end

    # save variable allocation later
    score_buffer = 0
    item_one = nothing
    item_two = nothing

    # go through sequence length, to index by column, all input sequences + gaps should = sequence length
    for i = 1:sequence_length
        score_buffer = 0

        # go through each input sequence, which is a single line of characters
        # last one will just pass through, either not doing a score or it was a gap
        # so that gap count and offset still needs to increase
        for j = 1:num_items
            # get either a gap or the character
            # if it is a gap, this layer is all gap gap_penalty
            # so save a lot of calculation by mult and continue
            if i == gap_list[j][1 + gap_offset_list[j]]
                gap_offset_list[j] += 1
                item_one = '_'
            else
                item_one = input_sequence_set[j][i - gap_offset_list[j]]
            end

            # go through each input seqence from the next item up to the last
            # final pattern of access = [1, 2, 3] => 12, 13, 23
            for k = j + 1:num_items
                # get either a blank space or the character
                if i == gap_list[k][1 + gap_offset_list[k]]
                    item_two = '_'
                else
                    item_two = input_sequence_set[k][i - gap_offset_list[k]]
                end

                if item_one == '_' || item_two == '_'
                    
                    if item_one == '_' && (i <= gap_list_begin[j] || i >= gap_list_end[j])
                        #=
                        if i <= gap_list_begin[j]
                            score_buffer += min(abs(score_list[3]), i)
                        end

                        if i >= gap_list_end[j]
                            score_buffer += min(abs(score_list[3]), sequence_length - i)
                        end
                        =#

                        #score_buffer += 1
                        continue
                    end

                    if item_two == '_' && (i <= gap_list_begin[k] || i >= gap_list_end[k])
#=
                        if i <= gap_list_begin[k]
                            score_buffer += min(abs(score_list[3]), i)
                        end

                        if i >= gap_list_end[k]
                            score_buffer += min(abs(score_list[3]), sequence_length - i)
                        end
=#
                        #score_buffer += 1
                        continue
                    end
                    

                    if item_one != item_two
                        ratio = length(gap_list[j])
                        count = 1
                        if item_one == '_' && i - 1 in gap_list[j]
                            for item = i - 2:-1;1
                                if item in gap_list[j]
                                    count += 1
                                end
                            end

                            score_buffer += (1 - (count / ratio)) * gap_ext_penalty
                            #score_buffer += gap_ext_penalty
                        elseif item_two == '_' && i - 1 in gap_list[k]
                            for item = i - 2:-1;1
                                if item in gap_list[k]
                                    count += 1
                                end
                            end

                            score_buffer += (1 - (count / ratio)) * gap_ext_penalty
                            #score_buffer += gap_ext_penalty
                        else
                            score_buffer += score_list[3]
                        end
                        
                        #score_buffer += score_list[3]
                    end

                    continue
                end

                score_buffer += PAM_250[string(item_one)][string(item_two)]
            end
        end

        # dont add to score if all items ended up being a gap
        score += score_buffer
    end

    # remove the added overflow position
    for i = 1:num_items
        pop!(gap_list[i])
    end

    return score
end

function score_sequence_pam250(input_sequence_set, sequence_length, score_list, gap_ext_penalty)
    score = 0
    score_buffer = 0
    item_one = nothing
    item_two = nothing
    num_items = length(input_sequence_set)

    try
        # go through sequence length, to index by column, all input sequences + gaps should = sequence length
        for i = 1:sequence_length
            score_buffer = 0

            for j = 1:num_items - 1
                for k = j + 1:num_items
                    item_one = input_sequence_set[j][i]
                    item_two = input_sequence_set[k][i]

                    # get either a blank space or the character
                    if item_one == '_' || item_two == '_'
                        if item_one != item_two
                            
                            if i != 1 && item_one == '_'
                                if input_sequence_set[j][i - 1] != '_'
                                    score_buffer += score_list[3]
                                else
                                    score_buffer += gap_ext_penalty
                                end
                            elseif i != 1 && item_two == '_'
                                if input_sequence_set[k][i - 1] != '_'
                                    score_buffer += score_list[3]
                                else
                                    score_buffer += gap_ext_penalty
                                end
                            else
                                score_buffer += score_list[3]
                            end
                            
                            #score_buffer += score_list[3]
                        end
                    else
                        score_buffer += PAM_250[string(item_one)][string(item_two)]
                    end
                end
            end

            score += score_buffer
        end
    catch e
        println("ERROR")
        println(item_one)
        println(item_two)
    end

    return score
end

export score_gap_list_pam250
export score_sequence_pam250