using CSV, DataFrames, Random, StatsBase, LinearAlgebra

# Read data
Data = CSV.read("C:/Users/Użytkownik/Desktop/player22.csv", DataFrame)

# Indices of players for each position
RW_idx = findall(x -> occursin("RW", x), Data[!, :Positions])
ST_idx = findall(x -> occursin("ST", x), Data[!, :Positions])
GK_idx = findall(x -> occursin("GK", x), Data[!, :Positions])
CM_idx = findall(x -> occursin("CM", x), Data[!, :Positions])
LW_idx = findall(x -> occursin("LW", x), Data[!, :Positions])
CDM_idx = findall(x -> occursin("CDM", x), Data[!, :Positions])
LM_idx = findall(x -> occursin("LM", x), Data[!, :Positions])
CF_idx = findall(x -> occursin("CF", x), Data[!, :Positions])
CB_idx = findall(x -> occursin("CB", x), Data[!, :Positions])
CAM_idx = findall(x -> occursin("CAM", x), Data[!, :Positions])
LB_idx = findall(x -> occursin("LB", x), Data[!, :Positions])
RB_idx = findall(x -> occursin("RB", x), Data[!, :Positions])
RM_idx = findall(x -> occursin("RM", x), Data[!, :Positions])
LWB_idx = findall(x -> occursin("LWB", x), Data[!, :Positions])
RWB_idx = findall(x -> occursin("RWB", x), Data[!, :Positions])

# List of position vectors
position_vectors = [RW_idx, ST_idx, GK_idx, CM_idx, LW_idx,
                    CDM_idx, LM_idx, CF_idx, CB_idx, CAM_idx,
                    LB_idx, RB_idx, RM_idx, LWB_idx, RWB_idx]

# Mutation function
function mutate(selected_players, position_vectors_list, probability)
    selected_players_matrix = copy(selected_players)

    function select_random_player(idx_list, selected_players)
        while true
            random_idx = rand(idx_list)
            if ismissing(selected_players) || !(random_idx in selected_players)
                return random_idx
            end
        end
    end



    for i in 1:size(selected_players_matrix)[1]
        for pos_idx in 1:length(position_vectors_list)
            if rand() <= probability
                selected_players_matrix[i, pos_idx] = select_random_player(position_vectors_list[pos_idx],
                                                                           selected_players_matrix[i, :])
            end
        end
    end

    return convert(DataFrame, selected_players_matrix)
end

n_rows = 100
pop_init = DataFrame(Matrix{Union{Missing, Int}}(missing, n_rows, length(position_vectors)), :auto)
pop_init = mutate(pop_init, position_vectors,1.0)

# Target function
function target(row, penalty=5)
    position_ratings = ["RWRating", "STRating", "GKRating", "CMRating",
                        "LWRating", "CDMRating", "LMRating", "CFRating",
                        "CBRating", "CAMRating", "LBRating", "RBRating",
                        "RMRating", "LWBRating", "RWBRating"]
    parent_data = Data[row, :]
    ratings = parent_data[:, position_ratings]
    ratings_log = log.(ratings)

    potential_minus_age = 0.15 * parent_data.Potential - 0.6 * parent_data.Age
    int_reputation = parent_data.IntReputation

    sumratings = sum(ratings_log)
    rating_list = vec(ratings_log)

    # Apply constraints
    constraint_penalty = 0
    if sum(parent_data.ValueEUR) > 250000000
        constraint_penalty += log((sum(parent_data.ValueEUR) - 250000000) ^ penalty)
    end
    if sum(parent_data.WageEUR) > 250000
        constraint_penalty += log((sum(parent_data.WageEUR) - 250000) ^ penalty)
    end
    if any(rating_list .< 1.2)
        constraint_penalty += 1.2 ^ penalty
    end

    target_value = -(sumratings + 0.3 * sum(potential_minus_age) + sum(int_reputation)) + constraint_penalty
    return target_value
end

# Tournament selection function
function tournament_selection(parents, t_size, penalty=6)
    random_parents_idx = sample(1:nrows(parents), t_size, replace=false)
    random_parents = parents[random_parents_idx, :]

    random_parents_fitness = [target(parent, penalty=penalty) for parent in eachrow(random_parents)]

    best_parent_idx = argmin(random_parents_fitness)
    return random_parents[best_parent_idx, :]
end

# Crossover function
function crossover(parent1, parent2, crossover_point)
    offspring1 = vcat(parent1[1:crossover_point], parent2[(crossover_point + 1):end])
    offspring2 = vcat(parent2[1:crossover_point], parent1[(crossover_point + 1):end])

    return DataFrame([offspring1 offspring2]')
end

# Algorithm parameters
crossover_point = 7
population_size = 100
num_generations = 20000
tournament_size = 2
probability = 0.09
penalty = 1
parents = pop_init

global_best = pop_init[1, :]
global_best_value = target(global_best)

# Main loop
for gen in 1:num_generations
    # Parent population
    parent_pop = DataFrame(Matrix{Union{Missing, Int}}(undef, nrows(parents), length(position_vectors)), :auto)
    for c in 1:population_size
        parent_pop[c, :] = tournament_selection(parents, tournament_size, penalty=penalty)
    end
    parent_pop = fill!(parent_pop, missing)

    # Generate offspring
    offspring_temp = DataFrame(Matrix{Union{Missing, Int}}(undef, 1, length(position_vectors)), :auto)
    for c in 1:2:population_size
        offsprings = crossover(parent_pop[c, :], parent_pop[c + 1, :], crossover_point)
        offspring_temp = vcat(offspring_temp, Matrix(offsprings))
    end
    offspring_temp = offspring_temp[2:end, :]
    offspring_temp = fill!(offspring_temp, missing)

    parents = mutate(offspring_temp, position_vectors, probability=probability)

    # Evaluate solutions
    solutions = [target(parent) for parent in eachrow(parents)]
    idx_sol = argmin(solutions)
    temp_best = parents[idx_sol, :]
    temp_target_value = solutions[idx_sol]

    if temp_target_value <= global_best_value
        global_best = temp_best
        global_best_value = temp_target_value
    end
end


TypeError: non-boolean (Missing) used in boolean context

Stacktrace:
 [1] (::var"#select_random_player#252")(idx_list::Vector{Int64}, selected_players::DataFrameRow{DataFrame, DataFrames.Index})
   @ Main .\In[9]:35
 [2] mutate(selected_players::DataFrame, position_vectors_list::Vector{Vector{Int64}}, probability::Float64)
   @ Main .\In[9]:46
 [3] top-level scope
   @ In[9]:57

FIX THAT and search for other errors.