"""
This way more closely matches what's in my notes, but is SLOW and gets worse results.

"""
import random

import matplotlib.pyplot as plt  # type: ignore
from tsp import TSP
from tsp_plotter import TSPPlotter

random.seed(1)


def hill_climb_with_2_opt(tsp, tour):
    fails_before_quit = 5000

    fails = 0
    sol = tour
    score = tsp.score(tour)
    while fails < fails_before_quit:
        new_sol = tsp.k_opt(sol, 2)
        new_score = tsp.score(new_sol)
        if new_score < score:
            sol = new_sol
            score = new_score
            fails = 0
            # print(score)
        else:
            fails += 1
    return sol


# tries_per_nbhd = 10
# tries_per_nbhd_per_k = {2: 100, 3: 100, 4: 100, 5: 100, 6: 10}

tsp = TSP.from_file("tsp100.txt")
plotter = TSPPlotter()

sol = tsp.random_tour()
score = tsp.score(sol)

failures = 0
while failures < 1000:

    improvement = False
    for k in range(3, 7):
        print(f"doing {k}-opt move. old score: {score}")
        new_sol = tsp.k_opt(sol, k, try_only_random_matching=True)
        new_score = tsp.score(new_sol)
        print(f"new score: {new_score}. time to H-C.")
        new_sol = hill_climb_with_2_opt(tsp, new_sol)
        new_score = tsp.score(new_sol)
        print(f"result: {new_score}")
        if new_score < score:
            sol = new_sol
            score = new_score
            improvement = True
            break

    if improvement:
        print(f"improvement with k = {k}")
        plotter.show_tour(sol)
        plotter.add_to_score_line(score)
        plotter.update_best(score)
        plt.pause(0.00001)
    else:
        failures += 1
        print(f"Failure # {failures}.")

plt.show(block=True)
