from flask import Flask, request, abort

from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import *
# import button api
from linebot.models import ButtonsTemplate, MessageTemplateAction, TemplateSendMessage, PostbackTemplateAction
# import quick reply
from linebot.models import QuickReply, QuickReplyButton, LocationAction

import random
import configparser
import logging

from requests.models import Response

# import linebot回應模板
import view

# import subject/emotional辨識模型
from transformers import BertForSequenceClassification
import torch
from subject_bert import *
from emotional_bert import *

# import ckip_transformers模型
from ckip_transformers.nlp import CkipWordSegmenter, CkipPosTagger
from recognize_food_n import *

# import database similarity計算模型
from sentence_transformers import SentenceTransformer, util
from compute_n_silimar import *

app = Flask(__name__)

config = configparser.ConfigParser()
config.read('config.ini')

logging.basicConfig(level=logging.DEBUG, format="%(levelname)s %(message)s")

line_bot_api = LineBotApi(config.get('line-bot', 'channel-access-token'))
handler = WebhookHandler(config.get('line-bot', 'channel-secret'))

# subject bert model
logging.debug("載入主題模型中...")
subject_model = BertForSequenceClassification.from_pretrained("subject_model")
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
subject_model.to(device)
subject_model.eval()

# emotional bert model
logging.debug("載入情緒模型中...")
emotional_model = BertForSequenceClassification.from_pretrained(
    "emotional_model")
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
emotional_model.to(device)
emotional_model.eval()

# ckip_pos Initialize drivers
logging.debug("載入分詞模型中...")
ws_driver = CkipWordSegmenter(level=3)
pos_driver = CkipPosTagger(level=3)

# n similarity model
logging.debug("載入相似度計算模型中...")
simi_model = SentenceTransformer('distiluse-base-multilingual-cased-v2')

def cmp(w):
    """計算名詞相似度"""
    max = 0
    for i in data:
        i = i.keys()
        for word in i:
            sim = compute((word, w))
            if sim > max:
                max = sim
                ww = word
    return ww, max

def compute(wordpair):
    """計算名詞相似度"""
    embeddings = simi_model.encode(wordpair)
    distance = util.pytorch_cos_sim(embeddings[0], embeddings[1])
    return distance

@app.route("/callback", methods=['POST'])
def callback():
    # get X-Line-Signature header value
    signature = request.headers['X-Line-Signature']

    # get request body as text
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    # handle webhook body
    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        print("Invalid signature. Please check your channel access token/channel secret.")
        abort(400)

    return 'OK'

# global
ans = " "
lng = lat = 1.0
r = 0

@handler.add(MessageEvent)
# TextMessage
def handle_message(event):
    reply_all = []
    global ans, lng, lat, r

    # 處理地理座標type的訊息
    if event.message.type == 'location':
        logging.debug("接收到座標位置了")
        lat = event.message.latitude
        lng = event.message.longitude
        line_bot_api.reply_message(
            event.reply_token, view.transport())

    # 處理文字type的訊息
    elif event.message.type == 'text':
        text = event.message.text

        # 交通工具選擇
        if text == '步行' or text == '單車' or text == '機車' or text == '汽車':
            if(text == '步行'):
                r = 1000
            elif(text == '單車'):
                r = 3000
            elif(text == '機車'):
                r = 5000
            elif(text == '汽車'):
                r = 10000
            line_bot_api.reply_message(
                event.reply_token, view.open_q())

        # 聊天機器人開頭詞
        elif text == "哈囉" or text == "你好" or text == "嗨":
            line_bot_api.reply_message(
                event.reply_token, view.location())

        # 重新選擇交通工具
        elif text == "交通方式":
            line_bot_api.reply_message(
                event.reply_token, view.transport())

        # 資料庫無結果，透過GOOGLE NEARBY API進行搜尋
        elif text == '好的':
            logging.debug(f"{ans}, {lat}, {lng}, {r}")
            google_response = view.google_api(lat, lng, r, ans)

            # GOOGLE 查無結果
            if google_response == -1:
                reply_all.append(TextSendMessage(
                    text="不好意思，google map上也沒有你的搜尋結果，建議你可以嘗試輸入其他想吃的食物品項，讓我們再次為你服務"))

            # 回傳 GOOGLE 搜尋結果
            else:
                POI_name, POI_rating, POI_address, POI_open, POI_money, POI_url = google_response
                logging.debug(
                    f"{POI_name}, {POI_rating}, {POI_address},{POI_open}, {POI_money}, {POI_url}")
                reply_all.append(view.recommendation_pattern(
                    POI_name, POI_rating, POI_address, POI_open, POI_money, POI_url))

            line_bot_api.reply_message(event.reply_token, reply_all)

        # 資料庫比對無結果，且不需要透過GOOGLE幫忙搜尋
        elif text == '不需要':
            line_bot_api.reply_message(
                event.reply_token, TextSendMessage(text="請你再次輸入你想吃的食物內容"))

        # 處理開放式問答
        else:
            # 階段一：進行主題分類
            convert2tsv(text)
            testset = Review_Subject("response", tokenizer=tokenizer)
            testloader = DataLoader(testset, batch_size=1,
                                    collate_fn=create_mini_batch)

            predictions = get_predictions(subject_model, testloader)
            index_map = {v: k for k, v in testset.label_map.items()}
            predictions.tolist()
            df = pd.DataFrame({"label": predictions.tolist()})
            df['label_pre'] = df.label.apply(lambda x: index_map[x])
            df_pred = pd.concat([testset.df.loc[:, ["text"]],
                                 df.loc[:, 'label_pre']], axis=1)

            # 回傳主題分類結果
            for txt in df_pred['label_pre']:
                response = f"回答的主題是：{str(txt)}"
                subject = txt
            reply_all.append(TextSendMessage(text=response))

            if(subject == '食物'):
                # 階段二：若主題為食物，則進行情緒分類
                e_convert2tsv(text)
                testset = Review_Emotional(
                    "response_emotion", tokenizer=tokenizer)
                testloader = DataLoader(testset, batch_size=1,
                                        collate_fn=e_create_mini_batch)

                predictions = e_get_predictions(emotional_model, testloader)
                index_map = {v: k for k, v in testset.label_map.items()}
                predictions.tolist()
                e_df = pd.DataFrame({"label": predictions.tolist()})
                e_df['label_pre'] = e_df.label.apply(lambda x: index_map[x])
                e_df_pred = pd.concat([testset.df.loc[:, ["text"]],
                                       e_df.loc[:, 'label_pre']], axis=1)

                # 回傳情緒分類結果
                for txt in e_df_pred['label_pre']:
                    logging.debug(f"情緒是：{str(txt)}")
                    response = f"情緒是：{str(txt)}"
                    emotion = txt
                reply_all.append(TextSendMessage(text=response))

                # 階段三：進行詞性標記與篩選名詞
                text = [text]
                ws = ws_driver(text)
                pos = pos_driver(ws)
                for sentence_ws, sentence_pos in zip(ws, pos):
                    ans = pack_ws_pos_sentece(sentence_ws, sentence_pos)

                # 回傳名詞標記與篩選結果
                logging.debug(f"食物品項{ans}")
                reply_all.append(TextSendMessage(text=f"食物品項是：{ans}"))

                # 階段四：標記名詞與資料庫名詞進行相似度比對
                simi_food, simi_num = cmp(ans)
                logging.debug(f"資料庫比對結果為{simi_food},相似度{simi_num[0][0]:.3f}")

                # 回傳資料庫搜尋/隨機結果
                if emotion == "正面" or emotion == "中立":
                    if simi_num >= 0.8:
                        reply_all.append(TextSendMessage(
                            text=f"資料庫比對結果為:\n{simi_food}/相似度{simi_num[0][0]:.3f}"))
                        id = get_best_store(simi_food)
                        logging.debug(f"{id}")
                        result = view.get_poi_detail(id)
                        message = view.recommendation_pattern(
                            result[0], result[1], result[2], result[3], result[4], result[5])
                        reply_all.append(message)
                    else:
                        reply_all.append(TextSendMessage(
                            text=f"資料庫比對結果為:\n{simi_food}/相似度{simi_num[0][0]:.3f} \n⚠相似度過低"))
                        reply_all.append(view.google_needed())

                elif emotion == "負面":
                    reply_all.append(TextSendMessage(
                        text=f"資料庫比對結果為:\n{simi_food}/相似度{simi_num[0][0]:.3f}\n⚠我們將排除 {simi_food} 並隨機為您推薦資料庫中的店家"))
                    id = get_random_store()
                    logging.debug(f"{id}")
                    result = view.get_poi_detail(id)
                    message = view.recommendation_pattern(
                        result[0], result[1], result[2], result[3], result[4], result[5])
                    reply_all.append(message)

            # 回應主題"其他"
            elif(subject == '其他'):
                reply_all.append(TextSendMessage(
                    text="請您輸入想吃的食物品項喔！"))
            # 回應主題"價格、環境、地點、服務"
            else:
                reply_all.append(TextSendMessage(
                    text="不好意思，我們還不支援食物以外的主題喔~建議你可以重新搜尋，輸入想吃的食物品項，有助於我們更好的推薦你喔!"))

            line_bot_api.reply_message(event.reply_token, reply_all)

if __name__ == "__main__":
    # 主動推播第一則訊息
    line_bot_api.push_message(
        "Uf4811a6102c17022a991fcc3d85955b9", view.location())
    app.run(debug=True, port=8082)


required = lambda field, value: f"Field {field} is required" if not len(value.strip()) else None

class Validate:

    __rules = {}
    __values = {}
    __errors = {}

    def __init__(self, rules:dict, values:dict, model: object =None) -> None:
        self.__rules = rules
        self.__values = values
        self.__model = model

    def __get_value(self, field):
        if isinstance(self.__values, dict):
            return self.__values.get(field)
        return getattr(self.__values, field)

    def values_to_dict(self):
        if isinstance(self.__values, dict):
            return self.__values
        return self.__values.dict()

    def is_valid(self):

        for field, rules in self.__rules.items():

            errors = []
            for rule in rules:

                err = rule(field, self.__get_value(field))
                if err:
                    errors.append(err)

            if len(errors):
                self.__errors.update({field: errors})

    def create(self):

        if not self.__model:
            raise Exception("pass model to save")
        self.is_valid()

        if not self.__errors:
            self.__model.create(**self.values_to_dict())
            return self.__model

        raise Exception(self.__errors)

    def update(self):

        if not self.__model:
            raise Exception("pass model to save")

        self.is_valid()
        if not self.__errors:
            self.__model.update(**self.values_to_dict())
            return self.__model

        raise Exception(self.__errors)

    @property
    def errors(self):
        self.__errors


def leiaInt(msg):
    while True:
        num = str(input(msg))
        if num.isnumeric():
            return int(num)
            break
        else:
            print('\033[31mERRO!!! Digite um número válido...\033[m')

#Programa principal
valor = leiaInt('Digite um número: ')
print(f'\033[32mVocê digitou o número {valor}\033[m')


import telebot
from telebot import types
import os
import django
from slugify import slugify

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'news.settings')
django.setup()

from social_django.models import UserSocialAuth
from main.models import News
from main.models import Category

class Post:
    def __init__(self, user_id=None, title=None, category=None, text=None, description=None, image=None):
        self.user_id = user_id
        self.title = title
        self.category = category
        self.text = text
        self.description = description
        self.image = image

    def publish_post(self):
        self.slug = slugify(self.title)
        category = Category.objects.get(name=self.category)
        news = News(title=self.title, text=self.text, category=category, description=self.description, image=self.image, slug=self.slug)
        news.save()

API_TOKEN = '6478915421:AAHZH_Zxp49blHcsl7bRga0WaxOQotNn-V4'

bot = telebot.TeleBot(API_TOKEN)

def send_news_details(news_details):
    bot.send_message('-4004087466', f"Опубликована новая новость\n{news_details['title']}\n{news_details['description']}\n{news_details['category']}")

# def send_news_details(news_details):
#     bot.send_photo('-4004087466', news_details['image'], f'''Опубликована новая новость\n{news_details['title']}\n{news_details['description']}\n{news_details['category']}''')

@bot.message_handler(commands=['start'])
def login_keyboard(message):
    markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
    button1 = types.KeyboardButton("Войти в аккаунт")
    markup.add(button1)
    bot.reply_to(message, "Привет!\nЯ бот который умеет взаимодействовать с новостным сайтом\nВыбери действие на клавиатуре", reply_markup=markup)

@bot.message_handler(func=lambda message: message.text=='Войти в аккаунт')
def main_keyboard(message):
    markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
    buttons = [types.KeyboardButton("Мой профиль"),
                types.KeyboardButton("Создать новость"),
                types.KeyboardButton("Подписаться на рассылку")]
    markup.add(*buttons)
    bot.reply_to(message, "Главное меню. Выберите действие на клавиатуре", reply_markup=markup)

@bot.message_handler(func=lambda message: message.text=='Мой профиль')
def profile_keyboard(message):
    user_id = message.chat.id
    user = UserSocialAuth.objects.get(provider='telegram', uid=user_id).user
    bot.send_message(message.chat.id,
                     f"Профиль\n{user.first_name} {user.last_name}\n{user.username}\nПочта: {user.email}\nДата регистрации: {user.date_joined}\nПоследний онлайн: {user.last_login}\nОставлено комментариев: {len(user.profile.get_user_comments())}\nОпубликовано новостей: {len(user.profile.get_user_news())}")

@bot.message_handler(func=lambda message: message.text=='Создать новость')
def create_post_keyboard(message):
    global post
    global create_post_markup
    post = Post(user_id=message.chat.id)
    create_post_markup = types.ReplyKeyboardMarkup(resize_keyboard=True, row_width=3)
    buttons = [types.KeyboardButton("Заголовок"),
                types.KeyboardButton("Категория"),
                types.KeyboardButton("Краткое описание"),
                types.KeyboardButton("Текст"),
                types.KeyboardButton("Изображение"),
                types.KeyboardButton("Просмотр"),
                types.KeyboardButton("Отправить"),
                types.KeyboardButton("На главную")]
    create_post_markup.add(*buttons)
    bot.send_message(message.chat.id, 'Создание новости', reply_markup=create_post_markup)

@bot.message_handler(func=lambda message: message.text=='Заголовок')
def title(message):
    title_msg = bot.send_message(message.chat.id, 'Введите заголовок новости')
    bot.register_next_step_handler(title_msg, title_validation)

@bot.message_handler(func=lambda message: message.text=='Краткое описание')
def description(message):
    title = bot.send_message(message.chat.id, 'Введите описание новости')
    bot.register_next_step_handler(title, description_validation)

@bot.message_handler(func=lambda message: message.text=='Текст')
def text(message):
    title = bot.send_message(message.chat.id, 'Введите текст новости')
    bot.register_next_step_handler(title, text_validation)

@bot.message_handler(func=lambda message: message.text=='Категория')
def category(message):
    markup = types.ReplyKeyboardMarkup(resize_keyboard=True, row_width=3)
    categories = Category.objects.all()
    buttons = []
    for category in categories:
        buttons.append(types.KeyboardButton(category.name))
    markup.add(*buttons)
    category = bot.send_message(message.chat.id, 'Выберите категорию', reply_markup=markup)
    bot.register_next_step_handler(category, category_selection)

@bot.message_handler(func=lambda message: message.text=='Изображение')
def image(message):
    title = bot.send_message(message.chat.id, 'Выберите изображение')
    bot.register_next_step_handler(title, image_validation)

@bot.message_handler(func=lambda message: message.text=='Отправить')
def send_post(message):
    global post
    if post.title and post.description and post.image and post.text:
        post.publish_post()
        news = News.objects.get(title=post.title)
        bot.send_message(message.chat.id, f'Пост опубликован\nссылка на пост: 127.0.0.1:8000{news.get_absolute_url()}')
    else:
        bot.send_message(message.chat.id, 'Не все поля заполнены!')

@bot.message_handler(func=lambda message: message.text=='Просмотр')
def view_post(message):
    bot.send_message(message.chat.id, f'Заголовок: {post.title}\nкатегория: {post.category}\nописание: {post.description}\nтекст: {post.text}')

@bot.message_handler(func=lambda message: message.text=='На главную')
def to_main_keyboard(message):
    main_keyboard(message)

def category_selection(message):
    global post
    global create_post_markup
    post.category = message.text
    bot.send_message(message.chat.id, 'Категория выбрана', reply_markup=create_post_markup)

def text_validation(message):
    global post
    global create_post_markup
    if len(message.text) <= 300:
        text = message.text
        bot.send_message(message.chat.id, 'Текст заполнен', reply_markup=create_post_markup)
    else:
        text = None
        bot.send_message(message.chat.id, 'Длина текста не может быть более 300 символов!', reply_markup=create_post_markup)
    post.text = text

def title_validation(message):
    global post
    global create_post_markup
    if len(message.text) <= 50:
        title = message.text
        bot.send_message(message.chat.id, 'Заголовок заполнен', reply_markup=create_post_markup)
    else:
        title = None
        bot.send_message(message.chat.id, 'Длина заголовка не может быть более 50 символов!', reply_markup=create_post_markup)
    post.title = title

def description_validation(message):
    global post
    global create_post_markup
    if len(message.text) <= 100:
        description = message.text
        bot.send_message(message.chat.id, 'Описание заполнено', reply_markup=create_post_markup)
    else:
        description = None
        bot.send_message(message.chat.id, 'Длина описания не может быть более 100 символов!', reply_markup=create_post_markup)
    post.description = description

def image_validation(message):
    global create_post_markup
    global post
    post.image = message.text
    bot.send_message(message.chat.id, 'Изображение выбрано', reply_markup=create_post_markup)

@bot.message_handler(func=lambda message: message.text=='Подписаться на рассылку')
def subscription_keyboard(message):
    buttons = [[types.InlineKeyboardButton(category.name, callback_data=category.name, url=f'https://t.me/django_news_subscribe_bot?start={category.slug}') for category in Category.objects.all()]]
    subscription_markup = types.InlineKeyboardMarkup(buttons, row_width=4)
    bot.reply_to(message, "Выберите ниже желаемые категории", reply_markup=subscription_markup)

# @bot.message_handler(func=lambda message: message.text=='Подписаться на рассылку')
# def subscription_keyboard(message):
#     global subscription_markup
#     buttons = [[types.InlineKeyboardButton("Спорт", callback_data='Спорт'),
#                 types.InlineKeyboardButton("Политика", callback_data='Политика'),
#                 types.InlineKeyboardButton("Кино", callback_data='Кино'),
#                 types.InlineKeyboardButton("Бизнес", callback_data='Бизнес')],
#                 [types.InlineKeyboardButton("Подписаться на рассылку", callback_data='Подписка', url='https://t.me/django_news_subscribe_bot')]]
#     subscription_markup = types.InlineKeyboardMarkup(buttons, row_width=4)
#     bot.reply_to(message, "Выберите ниже желаемые категории", reply_markup=subscription_markup)

# @bot.callback_query_handler(func=lambda call: True)
# def inline_callback(call):
#     if call.message:
#         bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text=f'{call.message.text}\n{call.data} ✅', reply_markup=subscription_markup)

if __name__ == '__main__':
    bot.polling()


import numpy as np
import pandas as pd
import cv2
import glob

img_list = glob.glob("../Data/img_align_celeba/*.jpg")
img_data = []

for i in range(len(img_list)):
    img_file = img_list[i]
    img = cv2.imread(img_file)
    gray_img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    gray_img = gray_img[20:198,:]
    gray_img = cv2.resize(gray_img, (32,32), interpolation=cv2.INTER_AREA)
    gray_img_list = np.ravel(gray_img).tolist()
    img_data.append(gray_img_list)
    if (i%100)==0:
        print("Converted {}/{}".format(i+1,len(img_list)))
    if ((i+1)%16277)==0:
        img_df = pd.DataFrame(img_data)
        img_df.to_csv("../Data/celeba_grayscale_32/train_{:02d}.csv".format((i+1)//16277),header=False,index=False)
        img_data = []
        if((i+1)//16277)==10:
            break


from collections import deque

def open(door):        # 열 수 있는 key가 있는지 확인
    if chr(ord(door) + 32) in keys:
        return True
    else:
        return False

def bfs(x, y):          # 현재 노드 주위를 탐색
    que = deque()
    que.append([x, y])
    while que:
        x, y = que.popleft()
        for nxt in range(4):
            nx = x + dx[nxt]
            ny = y + dy[nxt]
            if 0 <= nx < h and 0 <= ny < w and go(nx, ny):
                que.append([nx, ny])

def go(x, y):       # 갈 수 있으면 가고 True 리턴, 아니면 안 가고 False 리턴
    global cnt
    if visited[x][y]:                   # 이미 방문했으면 갈 수 없다.
        return False
    elif arr[x][y] == '.':                # 빈 공간을 만나면 갈 수 있다.
        visited[x][y] = 1
        return True
    elif arr[x][y] == '*':              # 벽을 만나면 갈 수 없다.
        return False
    elif 'a' <= arr[x][y] <= 'z':       # 열쇠를 주웠을 때
        keys.append(arr[x][y])          # 열쇠 추가
        visited[x][y] = 1
        return True
    elif 'A' <= arr[x][y] <= 'Z':       # 문을 마주쳤을 때
        if open(arr[x][y]):             # 열 수 있는지 확인
            visited[x][y] = 1
            return True
        else:
            doors.append([x, y])     # 열 수 없으면 열지 못한 문에 추가
            return False
    else:
        cnt += 1                        # 문서를 만났을 때 + 1
        visited[x][y] = 1               # 방문 표시
        return True

dx, dy = [0, 1, 0, -1], [1, 0, -1, 0]
n = int(input())
for _ in range(n):
    h, w = map(int, input().split())    # 지도의 높이 h, 너비 w
    arr = [input() for _ in range(h)]   # 지도
    keys = list(input())                # 소지하고 있는 키들
    doors = deque()      # 열지 못한 문의 좌표를 큐에 담는다 : [x, y]
    visited = [[0] * w for _ in range(h)]   # 방문 표시
    cnt = 0     # 획득한 문서의 수

    # 건물 가장자리 탐색
    for i in range(h):
        if i == 0 or i == h - 1:    # 첫 행과 마지막 행은 전부 다 탐색
            for j in range(w):
                if go(i, j):
                    bfs(i, j)
        else:                       # 나머지 행은 양 끝만 탐색
            if go(i, 0):
                bfs(i, 0)
            if go(i, w - 1):
                bfs(i, w - 1)

    while doors:                    # 열지 못했던 문들을 탐색
        change = 0
        sz = len(doors)
        for _ in range(sz):
            x, y = doors.popleft()
            if go(x, y):            # 문을 열 수 있는지 확인하고 이동
                bfs(x, y)
                change = 1
            else:
                doors.append([x, y])
        if not change:              # 더 열었던 문이 있을 때만!
            break

    print(cnt)


from outputs_fromDrone import InitializeConnectDrone, ReturnDroneAngle

from input_forDrone import droneArm, droneTakeOff, condition_yaw, send_global_velocity, send_ned_velocity_heading, goto_position_target_local_ned
from drone_variousMovements import fixDistanceToBlade,moveToNewLocation, moveDroneInLocalCoord, moveToNewDistance

import time
import math
import numpy
from dronekit import VehicleMode

import serial

import json

safeDistance = 2000

distDroneToBlade = 2500

## Initialize connection to drone
vehicle = InitializeConnectDrone()

print("Arm the drone...")
## Arm drone
droneArm(vehicle)

print("Drone take off...")
## Drone take off - test take of to 10 meters
droneTakeOff(10, vehicle)

##moveToNewDistance(vehicle, 331,320)
##
##time.sleep(5)
##
##print("slept")

## move drone using velocity from given distance
def movementToDistancePosition(distX, distY):
    stopper = False

    ## x is +forward, -backward, y is +right, -left

    signX = numpy.sign(distX)
    signY = numpy.sign(distY)
    counterX = abs(distX)
    counterY = abs(distY)
    while stopper is False:

        if counterX > 0:
            xMove = 1
            counterX-=0.5
        else:
            xMove = 0

        if counterY > 0:
            yMove = 1
            counterY-=0.5
        else:
            yMove = 0

        if yMove == 0 and xMove == 0:
            stopper = True

        moveDroneInLocalCoord(vehicle, [signX*xMove,signY*yMove,0], [0.5,0.5,0.5])
        time.sleep(0.1)

## move drone using velocity and given position
def movementToPositionNEW(posX, posY):
    stopper = False

    ## x is +forward, -backward, y is +right, -left
    distX = posX - vehicle.location.local_frame.north
    distY = posY - vehicle.location.local_frame.east

    signX = numpy.sign(distX)
    signY = numpy.sign(distY)

    while True:
        moveDroneInLocalCoord(vehicle, [distX,distY,0], [1,1,1])
        if math.fabs(vehicle.location.local_frame.north) >= math.fabs(posX*0.95) and math.fabs(vehicle.location.local_frame.east) >= math.fabs(posY*0.95):
            print("Reached")
            break

##        time.sleep(1)

def getDataFromServer(sock):

    if sock.inWaiting():

        receiveMsg = sock.readline()

        try:

            unpickledDataFull = json.loads(receiveMsg.strip().decode())

            outputArr = numpy.array(unpickledDataFull)

            sock.write('4Send'.encode())

#            print(unpickledDataFull)

            return outputArr
        except json.JSONDecodeError:
            sock.write('4Send'.encode())
            print("error")

    return -1

serialReceive = serial.Serial('COM15', 115200, timeout = 10)

print("start waiting for data...")
try:
    while True:
        sendData = getDataFromServer(serialReceive)

        if sendData is not -1:

            for i in range(0,len(sendData)):
                print(sendData[i,:])

                xPosNew = float(sendData[i,1])

                yPosNew = float(sendData[i,0])
##                while True:

##                    send_ned_velocity_heading(1/sendData[i,1], 1/sendData[i,0], 0, vehicle)

                while True:

                        distToTravel = math.sqrt((xPosNew - float(vehicle.location.local_frame.north))**2 + (yPosNew - float(vehicle.location.local_frame.east))**2)

                        velX = (0.5/distToTravel)*(xPosNew - float(vehicle.location.local_frame.north))
                        velY = (0.5/distToTravel)*(yPosNew - float(vehicle.location.local_frame.east))
                        send_ned_velocity_heading(velX, velY, 0, vehicle)
                        print(vehicle.location.local_frame.north)
                        if math.fabs(float(vehicle.location.local_frame.north)) >= math.fabs(xPosNew*0.95) and math.fabs(float(vehicle.location.local_frame.east)) >= math.fabs(yPosNew*0.95):
                            print("Reached")
                            break
                        time.sleep(1)
##                movementToDistancePosition(sendData[i,1], sendData[i,0])
##                time.sleep(1)

except KeyboardInterrupt:
    print("exit")

##movementToDistancePosition(-1, -5)
##
##time.sleep(1)
##
##movementToDistancePosition(1, -4)
##
##time.sleep(1)
##
##movementToDistancePosition(3, -2)
##
##time.sleep(1)
##
##movementToDistancePosition(5, 0)
##
##time.sleep(1)
##
##movementToDistancePosition(4, 2)
##
##time.sleep(1)

##Rotate the drone and add the angle to the heading of the drone
##print("rotate the drone ")
##print(math.degrees(vehicle.attitude.yaw))
##condition_yaw(45,vehicle,relative=True)
##
##send_global_velocity(0,0,0,vehicle)
##time.sleep(1)
##
##print(math.degrees(vehicle.attitude.yaw))

##time.sleep(1)
##
#### Move Drone in local Coord system
##for i in range(0,10):
##    moveDroneInLocalCoord(vehicle, [1,0,0], [1,0,0])
##
##    time.sleep(0.1)
##
##print(math.degrees(vehicle.attitude.yaw))

## Send command to drone
##print("Fly by velocity")
##for i in range(0,10):
##    moveDroneInLocalCoord(vehicle, [1,1,0], [2,2,2])

####    fixDistanceToBlade(safeDistance, distDroneToBlade, vehicle)
####    distDroneToBlade -=10
##    ##condition_yaw(meanAngle_compensated)
##    time.sleep(1)

print("Setting LAND mode...")
vehicle.mode = VehicleMode("LAND")

print ("Close vehicle object")
vehicle.close()

##sitl.stop()

print("Completed")


from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import BaggingClassifier
from sklearn.datasets import make_moons
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split

import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
import numpy as np

if __name__ == "__main__":
    """
    bagging
    在sklearn 中想复现，random_state 一定要设置相同
    """
    X,y = make_moons(n_samples=500,noise=0.25,random_state=42)
    X_train,X_test,y_train,y_test = train_test_split(X,y,random_state=42)

    # 500 个决策树，自举法抽样100个样本
    bag_clf = BaggingClassifier(DecisionTreeClassifier(random_state=42),max_samples=100,n_estimators=500,bootstrap=True,n_jobs=-1,oob_score=True)
    dt_clf = DecisionTreeClassifier(random_state=42)
    bag_clf.fit(X_train,y_train)
    dt_clf.fit(X_train,y_train)

    custom_cmap = ListedColormap(['#fafab0', '#9898ff', '#a0faa0'])
    x1s = np.linspace(-1.5,2.5,100)
    x2s = np.linspace(-1,1.5,100)
    x1,x2 = np.meshgrid(x1s,x2s)
    X_new = np.c_[x1.ravel(),x2.ravel()]
    y_bag_pred = bag_clf.predict(X_new).reshape(x1.shape)
    y_dt_pred = dt_clf.predict(X_new).reshape(x1.shape)
    print(y_bag_pred.shape)
    plt.subplot(121)
    plt.plot(X[:,0][y==0],X[:,1][y==0],"yo")
    plt.plot(X[:, 0][y == 1], X[:, 1][y == 1], "bs")
    plt.contourf(x1, x2, y_dt_pred, alpha=0.3, cmap=custom_cmap)
    plt.title("DecisionTreeClassifier")
    plt.axis([-1.5, 2.5, -1, 1.5])

    plt.subplot(122)
    plt.plot(X[:,0][y==0],X[:,1][y==0],"yo")
    plt.plot(X[:, 0][y == 1], X[:, 1][y == 1], "bs")
    plt.contourf(x1, x2, y_bag_pred, alpha=0.3, cmap=custom_cmap)
    plt.title("BaggingClassifier")
    plt.axis([-1.5, 2.5, -1, 1.5])

    """
    bagging_oob_score 0.9333333333333333
    bagging_test_score 0.952
    看到2者很相近，在工程中我们那oob 来评估模型 - 尽可能不碰测试数据
    """
    print("bagging_oob_score",bag_clf.oob_score_)
    print("bagging_test_score", accuracy_score(y_test,bag_clf.predict(X_test)))
    plt.show()


import os
from netCDF4 import Dataset
import numpy as np

here = os.path.dirname(os.path.abspath(__file__))
datadir = os.path.join(here, '../../data')
outdir = os.path.join(here, '../../output')

paramf = {'nh': os.path.join(datadir, 'paramfiles/inv_params_osi455_nh_200301-202012_1day.nc'),
          'sh': os.path.join(datadir, 'paramfiles/inv_params_osi455_sh_200208-202007_1day.nc')}

outfile = os.path.join(outdir, 'latex_stats_paramfiles.tex')

mondict = {0: 'Jan',
           1: 'Feb',
           2: 'Mar',
           3: 'Apr',
           4: 'May',
           5: 'Jun',
           6: 'Jul',
           7: 'Aug',
           8: 'Sep',
           9: 'Oct',
           10: 'Nov',
           11: 'Dec'}

def main():

    varlist = ['flags', 'absA_gapfill', 'ThetaA_gapfill', 'RMS_Res_real',
               'RMS_Res_imag', 'C_real_gapfill', 'C_imag_gapfill', 'lat', 'lon']
    stats = {}
    data = {}

    for hemi in ['nh', 'sh']:

        stats[hemi] = {}
        data[hemi] = {}

        with Dataset(paramf[hemi], 'r') as dataset:

            for var in varlist:
                data[hemi][var] = dataset.variables[var][:]

        # Finding data shape
        shx, shy = data['nh']['RMS_Res_real'][0, :, :].shape
        rmsdtype = data['nh']['RMS_Res_real'].dtype

        # Finding the per-month flags
        flagok = np.zeros((12, shx, shy), dtype=data[hemi]['flags'][:].dtype)
        for mon in range(12):
            flagok[mon, :, :] = data[hemi]['flags'][mon, :, :] == 0

        # Calculating the geostrophic speeds
        cdtype = np.double
        data[hemi]['C_gapfill'] = np.zeros((12, shx, shy), dtype=cdtype)

        # In addition to the other flagging, we want to flag any NaNs
        # in the geostropic currents
        flagokgeo = flagok.copy()
        for mon in range(12):
            flagokgeo[mon, :, :] = np.logical_and(flagok[mon, :, :], ~data[hemi]['C_real_gapfill'][mon, :, :].mask)
            flagokgeo[mon, :, :] = np.logical_and(flagok[mon, :, :], ~data[hemi]['C_imag_gapfill'][mon, :, :].mask)
        data[hemi]['C_real_gapfill'].mask = 0
        data[hemi]['C_imag_gapfill'].mask = 0

        for mon in range(12):
            # Set the gapfilled and sea/land areas to 0 to avoid nasty numbers
            data[hemi]['C_real_gapfill'][mon, :, :][flagokgeo[mon, :, :] == 0] = 0
            data[hemi]['C_imag_gapfill'][mon, :, :][flagokgeo[mon, :, :] == 0] = 0

            ccomb = np.zeros((2, shx, shy), dtype=cdtype)
            cc1 = data[hemi]['C_real_gapfill'][mon, :, :]
            ccomb[0, :, :] = cc1 * cc1
            cc2 =  data[hemi]['C_imag_gapfill'][mon, :, :]
            ccomb[1, :, :] = cc2 * cc2
            ccombsum = np.nansum(ccomb, axis=0)
            data[hemi]['C_gapfill'][mon, :, :] = np.sqrt(ccombsum)

        # Averaging the RMS var
        data[hemi]['RMS_Res'] = np.zeros((12, shx, shy), dtype=rmsdtype)
        for mon in range(12):
            rmsav = np.zeros((2, shx, shy), dtype=rmsdtype)
            rmsav[0, :, :] = data[hemi]['RMS_Res_real'][mon, :, :]
            rmsav[1, :, :] = data[hemi]['RMS_Res_real'][mon, :, :]
            data[hemi]['RMS_Res'][mon, :, :] = np.nanmean(rmsav, axis=0)

        for var in ['absA_gapfill', 'ThetaA_gapfill', 'RMS_Res', 'C_gapfill']:
            stats[hemi][var] = {}

            for mon in range(12):
                # Calculate the per-month stats where the flag shows
                # no gapfilling
                if var == 'C_gapfill':
                    field = data[hemi][var][mon, :, :][flagokgeo[mon, :, :] == 1]
                else:
                    field = data[hemi][var][mon, :, :][flagok[mon, :, :] == 1]
                stats[hemi][var][mon] = np.nanmean(field)
                # Changing the absA variables to percentage
                if var == 'absA_gapfill':
                    stats[hemi][var][mon] = 100. * stats[hemi][var][mon]

    # Write out the latex file
    with open(outfile, 'a+') as outf:

        outf.write("\\begin{table}[htb]\n")
        outf.write("\\begin{center}\n")
        outf.write("\\begin{tabular}{|l||c|c|c||c|c|c|}\n")
        outf.write("\hline\n")
        outf.write("{} & \multicolumn{3}{|c||}{Northern hemisphere} & \multicolumn{3}{|c|}{Southern hemisphere} \\\\ \n")
        outf.write("\hline\n")
        outf.write("Month & $\\langle|A|\\rangle$ & $\\langle\\theta \\rangle$ & $\\langle U_{wg} \\rangle$ & $\\langle|A|\\rangle$ & $\\langle\\theta\\rangle$ & $\\langle U_{wg} \\rangle$ \\\\ \n")
        outf.write("{} & / \\% & / degree & / ms$^{-1}$ & / \\% & / degree & / ms$^{-1}$ \\\\ \n")
        outf.write("\hline\n")

        for mon in range(12):
            outf.write("{} & {} & {} & {} & {} & {} & {} \\\\ \n".format(
                mondict[mon],
                "{:+.1f}".format(stats['nh']['absA_gapfill'][mon]),
                "{:+.1f}".format(stats['nh']['ThetaA_gapfill'][mon]),
                "{:+.3f}".format(stats['nh']['C_gapfill'][mon]),
                "{:+.1f}".format(stats['sh']['absA_gapfill'][mon]),
                "{:+.1f}".format(stats['sh']['ThetaA_gapfill'][mon]),
                "{:+.3f}".format(stats['sh']['C_gapfill'][mon])))
        outf.write("\hline\n")
        outf.write("\end{tabular}\n")
        outf.write("\end{center}\n")
        outf.write("\caption[Parameter statistics]{}\n")
        outf.write("\label{tab:stats:param}\n")
        outf.write("\end{table}\n")
        outf.write("\n\n")

#    # OLD VERSION WITH RMS ERRORS
#    # Write out the latex file
#    with open(outfile, 'a+') as outf:
#
#        outf.write("\\begin{table}[htb]\n")
#        outf.write("\\begin{center}\n")
#        outf.write("\\begin{tabular}{|l||c|c|c||c|c|c|}\n")
#        outf.write("\hline\n")
#        outf.write("{} & \multicolumn{3}{|c||}{Northern hemisphere} & \multicolumn{3}{|c|}{Southern hemisphere} \\\\ \n")
#        outf.write("\hline\n")
#        outf.write("Month & $\\langle|A|\\rangle$ & $\\langle\\theta \\rangle$ & $\\langle \\varepsilon(dX) + \\varepsilon(dY) \\rangle$ & $\\langle|A|\\rangle$ & $\\langle\\theta\\rangle$ & $\\langle \\varepsilon(dX) + \\varepsilon(dY) \\rangle$ \\\\ \n")
#        outf.write("{} & / \\% & / degree & / ms$^{-1}$ & / \\% & / degree & / ms$^{-1}$ \\\\ \n")
#        outf.write("\hline\n")
#
#        for mon in range(12):
#            outf.write("{} & {} & {} & {} & {} & {} & {} \\\\ \n".format(
#                mondict[mon],
#                "{:+.1f}".format(stats['nh']['absA_gapfill'][mon]),
#                "{:+.1f}".format(stats['nh']['ThetaA_gapfill'][mon]),
#                "{:+.3f}".format(stats['nh']['RMS_Res'][mon]),
#                "{:+.1f}".format(stats['sh']['absA_gapfill'][mon]),
#                "{:+.1f}".format(stats['sh']['ThetaA_gapfill'][mon]),
#                "{:+.3f}".format(stats['sh']['RMS_Res'][mon])))
#        outf.write("\hline\n")
#        outf.write("\end{tabular}\n")
#        outf.write("\end{center}\n")
#        outf.write("\caption[Parameter statistics]{}\n")
#        outf.write("\label{tab:stats:param}\n")
#        outf.write("\end{table}\n")
#        outf.write("\n\n")

if __name__ == '__main__':

    main()


import xml.etree.ElementTree as ET
from tqdm import tqdm
import numpy as np
import random
import matplotlib.pyplot as plt
import datetime
import time

# pip install -r requirements.txt

# Read the XML file and save the data in NumPy format. Note: one of brazil and burma must be True and the other False.
# Parse the XML file through xml.etree.ElementTree,
# create a numpy array with city_count*city_count dimensions, and save the read data into the array.
def readXml():
    if brazil:
        tree_brazil = ET.parse('brazil58.xml')
        root_brazil = tree_brazil.getroot()
        graph_element_brazil = root_brazil.find('graph')
        city_count_brazil = len(graph_element_brazil.findall('vertex'))
        # make use of a distance matrix denoted as D
        d_brazil = np.zeros((city_count_brazil, city_count_brazil), dtype=object)

        for vertex_idx, vertex_element in enumerate(graph_element_brazil.findall('vertex')):
            for edge_element in vertex_element.findall('edge'):
                cost = edge_element.get('cost')
                city_id = edge_element.text
                d_brazil[vertex_idx, int(city_id)] = float(cost)
        return d_brazil, city_count_brazil
    if burma:
        tree_burma = ET.parse('burma14.xml')
        root_burma = tree_burma.getroot()
        graph_element_burma = root_burma.find('graph')
        city_count_burma = len(graph_element_burma.findall('vertex'))
        # make use of a distance matrix denoted as D
        d_burma = np.zeros((city_count_burma, city_count_burma), dtype=object)

        for vertex_idx, vertex_element in enumerate(graph_element_burma.findall('vertex')):
            for edge_element in vertex_element.findall('edge'):
                cost = edge_element.get('cost')
                city_id = edge_element.text
                d_burma[vertex_idx, int(city_id)] = float(cost)
        return d_burma, city_count_burma

# compute fitness of every route
# The method is to traverse the array data,
# and add the distance between the last city and the first city
def CountF(p_list):
    s = 0
    for i in range(city_count - 1):
        s += data[p_list[i], p_list[i + 1]]
    s += data[p_list[-1], p_list[0]]
    return s

# 1. Generate an initial population of p randomly created solutions and assess the fitness of each individual in
# the population.
# Give a seed so that the random value returned each time is fixed
# The first column is the path, and the second column is the sum of the distances along the path.
def initial(list_range):
    p = np.zeros((list_range, 2), dtype=object)
    for i, j in zip(range(list_range), range(2023, 2023 + population_size)):
        random.seed(j)
        # 给出一个初始化的population
        initial_list = list(range(city_count))
        random.shuffle(initial_list)
        p[i, 0] = initial_list
        p[i, 1] = CountF(initial_list)
    return p

# 2. Use tournament selection twice to select two parents, denoted as a and b
# Select random numbers within the number of tournament_size non-repeating populations in the population,
# and select the one with the best result to return
def Tournament_Selection(p_list, count):
    random_t_1 = np.random.choice(population_size, count, replace=False)
    selected_values = population[random_t_1, 1]
    min_index = int(random_t_1[np.argmin(selected_values)])
    res_a = p_list[min_index, 0]

    np.random.seed(seed + np.random.choice(population_size, 1))
    random_t_2 = np.random.choice(population_size, count, replace=False)
    selected_values = population[random_t_2, 1]
    min_index = int(random_t_1[np.argmin(selected_values)])
    res_b = p_list[min_index, 0]
    return res_a, res_b

# 3. apply a Crossover_with_fix on these selected parents to generate two children, referred to as c and d.
# First select a random number so that the two subsets are truncated
# from the index of that number and exchange each other's data.
# When exchanging data here,
# pay attention to whether the values corresponding to the same index between a and b are equal.
# If they are not equal, it means there will be duplication. The duplicate data in c and d must be replaced.
def Crossover_with_fix(kid_a, kid_b):
    random_single_point = int(np.random.choice(city_count))
    kid_c = kid_a[:random_single_point] + kid_b[random_single_point:]
    kid_d = kid_b[:random_single_point] + kid_a[random_single_point:]
    for j in range(random_single_point, city_count):
        if kid_b[j] != kid_a[j]:
            kid_c[kid_c.index(kid_b[j])] = kid_a[j]
            kid_d[kid_d.index(kid_a[j])] = kid_b[j]
    return kid_c, kid_d

# 3. apply a OrderedCrossover on these selected parents to generate two children, referred to as c and d.
# Exchange data first, then add unique data later
def OrderedCrossover(kid_a, kid_b):
    random_single_point = int(np.random.choice(city_count))
    kid_c = kid_a[:random_single_point]
    kid_d = kid_b[:random_single_point]
    for j1 in kid_b:
        if j1 not in kid_c:
            kid_c.append(j1)
    for j2 in kid_a:
        if j2 not in kid_d:
            kid_d.append(j2)

    return kid_c, kid_d

# 4. Run a single_swap_mutation on c and d to give two new solutions e and f. Evaluate the fitness of e and f.
# Swap two points
def single_swap_mutation(m_c, m_d):
    random_e = np.random.choice(city_count, 2, replace=False)
    random_f = np.random.choice(city_count, 2, replace=False)
    m_e = m_c.copy()
    m_f = m_d.copy()

    m_e[random_e[0]], m_e[random_e[1]] = m_e[random_e[1]], m_e[random_e[0]]
    m_f[random_f[0]], m_f[random_f[1]] = m_f[random_f[1]], m_f[random_f[0]]

    return m_e, m_f

# 4. Run a inversion on c and d to give two new solutions e and f. Evaluate the fitness of e and f.
# Slice at random values, then flip the data after that
def inversion(m_c, m_d):
    random_e = np.random.choice(city_count)
    random_f = np.random.choice(city_count)
    m_e = m_c.copy()
    m_f = m_d.copy()

    m_e = m_e[:random_e] + list(reversed(m_e[random_e:]))
    m_f = m_f[:random_f] + list(reversed(m_f[random_f:]))
    return m_e, m_f

# 4. Run a multiple_swap_mutation on c and d to give two new solutions e and f. Evaluate the fitness of e and f.
# Swap multiple points
def multiple_swap_mutation(m_c, m_d, count):
    random_e = np.random.randint(0, city_count, count)
    random_f = np.random.randint(0, city_count, count)
    m_e = m_c.copy()
    m_f = m_d.copy()
    for g in range(count // 2):
        m_e[random_e[g]], m_e[random_e[-(g + 1)]] = m_e[random_e[-(g + 1)]], m_e[random_e[g]]
        m_f[random_f[g]], m_f[random_f[-(g + 1)]] = m_f[random_f[-(g + 1)]], m_f[random_f[g]]

    return m_e, m_f

# 5. Run Replace_Weakest function, firstly for e,        then f
# Replace the value of the worst data in the list
def Replace_Weakest(fit_list):
    fit_score = CountF(fit_list)
    sorted_idx = np.argsort(-population[:, 1])
    if fit_score < population[sorted_idx[0], 1]:
        population[sorted_idx[0], 0], population[sorted_idx[0], 1] = fit_list, fit_score

# 5. Run Replace_FirstWeakest function, firstly for e, then f
# Replace the first value lower than the current value
def Replace_FirstWeakest(fit_list):
    fit_score = CountF(fit_list)
    for h in range(population_size):
        if population[h, 1] >= fit_score:
            population[h, 0], population[h, 1] = fit_list, fit_score
            break

result = []
mutation_count_list = []
tournament_size_list = []

seed = 2000  # Seed value for random number generation
mutation_count = 2  # Number of mutation operations if 10 exchange 5 times
tournament_size = 4
population_size = 10

brazil = True  # Flag for using Brazil data
burma = False  # Flag for using Burma data
data, city_count = readXml()  # Read data from XML files and get the city count
population = initial(population_size)  # Initialize the population

# Flags for different states
Crossover_with_fix_state = False  # Whether to enable Crossover_with_fix
OrderedCrossover_state = True  # Whether to enable OrderedCrossover
single_swap_mutation_state = False  # Whether to enable single swap mutation
inversion_state = True  # Whether to enable inversion mutation
multiple_swap_mutation_state = False  # Whether to enable multiple swap mutation
Replace_FirstWeakest_state = True  # Whether to enable replacing the first weakest individual
Replace_Weakest_state = False  # Whether to enable replacing the weakest individual

use_cross = True  # Whether use crossover
save_pic_state = False  # Whether save picture

start_time = time.time()
steps = 10000
# start to loop
for step in tqdm(range(steps)):
    np.random.seed(seed)
    # if step == 2000:
    #     mutation_count = 6
    # if step == 6000:
    #     mutation_count = 2
    # if step == 6000:
    #     tournament_size = 6
    a, b = Tournament_Selection(population, tournament_size)
    if use_cross:
        if Crossover_with_fix_state:
            c, d = Crossover_with_fix(a, b)
        if OrderedCrossover_state:
            c, d = OrderedCrossover(a, b)
    if not use_cross:
        c, d = a.copy(), b.copy()
    if single_swap_mutation_state:
        e, f = single_swap_mutation(c, d)
    if inversion_state:
        e, f = inversion(c, d)
    if multiple_swap_mutation_state:
        e, f = multiple_swap_mutation(c, d, mutation_count)
    if Replace_FirstWeakest_state:
        Replace_FirstWeakest(e)
        Replace_FirstWeakest(f)
    if Replace_Weakest_state:
        Replace_Weakest(e)
        Replace_Weakest(f)
    score = np.sum(population[:, 1]) / population_size
    result.append(score)
    mutation_count_list.append(mutation_count)
    tournament_size_list.append(tournament_size)
    seed = seed + 1
end_time = time.time()

y = min(population[:, 1])
z = np.argmin(population[:, 1])
x = list(range(0, steps))
current_time = datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')

plt.figure(figsize=(10, 8))
plt.subplots_adjust(hspace=0.3)
city = ""
if brazil:
    city = "Brazil"
elif burma:
    city = "Burma"
plt.subplot(2, 1, 1)
plt.xlabel('step')
plt.ylabel('sum population cost')
plt.title(f'city:{city},min_value:{y},m_count:{mutation_count},t_count:{tournament_size},len_p:{population_size}')
plt.plot(x, result, 'r-', lw=3)
plt.legend(['result'])

plt.subplot(2, 2, 3)
plt.plot(x, mutation_count_list, 'g-', lw=3)
plt.xlabel('step')
plt.ylabel('mutation_count')
plt.legend(['mutation_count'])

plt.subplot(2, 2, 4)
plt.plot(x, tournament_size_list, 'b-', lw=3)
plt.xlabel('step')
plt.ylabel('kid_count')
plt.legend(['kid_count'])
if save_pic_state:
    plt.savefig(f'{city}_{current_time}.png')
plt.show()
plt.close()
print(f'min value of {city} is {population[z, 1]}\nthe route is {population[z, 0]} ')
# Calculate the time difference
elapsed_time = end_time - start_time
print(f"Elapsed time: {elapsed_time} seconds")


# We've started writing a function named whoWon(). It takes in the following variables:
# - team1 (a string)
# - score1 (an integer)
# - team2 (a string)
# - score2 (an integer)
#
# Create two variables. Name the first one 'winner', and give it the value of the winning
# team. Name the second one 'margin', and give it the number of points that the winning
# team won by. If the game was a tie, set the value of 'winner' equal to "It's a tie!",
# and set 'margin' equal to 0.
#
# For example, calling whoWon("Georgia Tech", 30, "Duke", 20) would result in a value of
# "Georgia Tech" for the variable 'winner' and 10 for the variable 'margin'.

def whoWon(team1, score1, team2, score2):
    # Add your code here. When your code is done running, there should exist a variable
    # called winner, with the value of the name of the team with the higher score, and
    # a variable called margin, with the value the number of points the winning team
    # won by.

    if score1 > score2:
        winner = team1
        margin = score1 - score2
    elif score1 == score2:
        winner = "It's a tie!"
        margin = 0
    else:
        winner = team2
        margin = score2 - score1

    return (winner, margin)

# You may modify the variables below to test your code.
testTeam1 = "Georgia Tech"
testScore1 = 26
testTeam2 = "Georgia"
testScore2 = 26

# Don't worry with the code below, it just prints the result!
print("Score:", testTeam1, testScore1, "-", testTeam2, testScore2)
resultTuple = whoWon(testTeam1, testScore1, testTeam2, testScore2)
if not resultTuple[1] == 0:
    print(resultTuple[0], "won by", resultTuple[1], "points.")
else:
    print(resultTuple[0])


import os
import re
import hashlib
import shutil

SOURCE_CODE_DIRECTORY = "C:\\Users\\Evyatar\\Documents\\NetBeansProjects\\TodoList\\"
DESTINATION_CODE_DIRECTORY = "C:\\wamp\\www\\TodoList2\\TodoList\\"
DB_CONTAINER_FILE = "mappings.txt"

BLACKLIST_NAMES = (	'Config', 'Error', 'Flash', 'NotFoundException', 'TodoDao', 'TodoMapper', 'Todo', 'TodoSearchCriteria', 'TodoValidator', 'Utils',
					'this',
					'self',
					'getMessage', 'handleException', 'error_field', 'quote', 'query', 'errorInfo', 'format', 'setTime', 'setDueOn', 'fetch', 'prepare', 'lastInsertId',  'execute',
					'rowCount',
					'loadClass',
					'_GET', '_POST', '_REQUEST', '_SERVER', '_SESSION', '_FILES', '_COOKIE', '_ENV')

FILE_EXTENSION_TO_OBFUSCATE = ('.php', '.phtml')

mappings = {}

def GetFileContants(filename):
	fin = open(filename, 'r')
	data = fin.read()
	fin.close()

	return data

def GenerateDestinationPath(originalFilename):
	relativeOriginalFilename = originalFilename[len(SOURCE_CODE_DIRECTORY):]
	filenameToReturn = DESTINATION_CODE_DIRECTORY + relativeOriginalFilename

	dirname = filenameToReturn.rsplit("\\", 1)[0]
	if not os.path.exists(dirname):
		os.makedirs(dirname)

	return filenameToReturn

def WriteFile(filename, data):
	fout = open(filename, 'w+')
	data = fout.write(data)
	fout.close()

def DictionaryHasValue(dict, value):
	for currentValue in dict.values():
		if currentValue == value:
			return True

	return False

def CreateValueMapping(originalName):
	global mappings

	EncodedValue = hashlib.sha256(originalName.group(2)).hexdigest()
	# Name must not start with a digit
	if (EncodedValue[0].isdigit()):
		EncodedValue = "a" + EncodedValue

	mappings[originalName.group(2)] = EncodedValue

	return ""

def ReplaceNameWithMappedValue(originalName):
	global mappings

	if originalName.group(2) in BLACKLIST_NAMES:
		return (originalName.group(1) + originalName.group(2) + originalName.group(3))

	if (mappings.has_key(originalName.group(2))):
		return originalName.group(1) + mappings[originalName.group(2)] + originalName.group(3)
	else:
		return originalName.group(1) + originalName.group(2) + originalName.group(3)

def EncodeName(originalName):
	global mappings

	retVal = originalName.group(1)
	if originalName.group(2) in BLACKLIST_NAMES:
		return (retVal + originalName.group(2) + originalName.group(3))

	hashResult = hashlib.sha256(originalName.group(2)).hexdigest()
	# Name must not start with a digit
	if (hashResult[0].isdigit()):
		hashResult = "a" + hashResult

	# In case the variable is already obfuscated
	if DictionaryHasValue(mappings, originalName.group(2)):
		retVal += originalName.group(2)

	# In case we already have a mapping for this variable
	elif mappings.has_key(originalName.group(2)):
		retVal += hashResult
	else:
		retVal += hashResult
		mappings[originalName.group(2)] = hashResult

	retVal += originalName.group(3)

	return retVal

# Looks for functions in the code, by looking for the following formats:
#  function SomeFunction(
#  ::SomeFunction(
#  ->SomeFunction(
def ObfuscateFunctions(data):
	data = re.sub('(function )([a-zA-Z0-9_]+)(\()', ReplaceNameWithMappedValue, data)
	data = re.sub('(::)([a-zA-Z0-9_]+)(\()', ReplaceNameWithMappedValue, data)
	data = re.sub('(->)([a-zA-Z0-9_]+)(\()', ReplaceNameWithMappedValue, data)

	return data

# Looks for variable in the code, by looking for the following formats:
#  $SomeVariable
def ObfuscateVariables(data):
	data = re.sub('(\$)([a-zA-Z0-9_]+)()', EncodeName, data)
	data = re.sub('(->)([a-zA-Z0-9_]+)([^a-zA-Z0-9_\(])', EncodeName, data)

	return data

# Looks for classes in the code, by looking for the following formats:
#  SomeClass::
#  new SomeClass
#  class SomeClass
#  extends SomeClass
#  interface SomeClass
def ObfuscateClasses(data):
	data = re.sub('([^a-zA-Z0-9_])([a-zA-Z0-9_]+)(::)', ReplaceNameWithMappedValue, data)
	data = re.sub('(new )([a-zA-Z0-9_]+)()', ReplaceNameWithMappedValue, data)
	data = re.sub('(class )([a-zA-Z0-9_]+)()', ReplaceNameWithMappedValue, data)
	data = re.sub('(extends )([a-zA-Z0-9_]+)()', ReplaceNameWithMappedValue, data)
	data = re.sub('(interface )([a-zA-Z0-9_]+)()', ReplaceNameWithMappedValue, data)

	return data

def ObfuscateConstants(data):
	data = re.sub('(const )([A-Z0-9_]+)([^A-Z0-9_])', ReplaceNameWithMappedValue, data)
	data = re.sub('(::)([A-Z0-9_]+)([^A-Z0-9_])', ReplaceNameWithMappedValue, data)

	return data

def MapFunctions(data):
	re.sub('(function )([a-zA-Z0-9_]+)(\()', CreateValueMapping, data)

def MapConstants(data):
	re.sub('(const )([A-Z0-9_]+)([^A-Z0-9_])', CreateValueMapping, data)

def MapClasses(data):
	data = re.sub('(class )([a-zA-Z0-9_]+)()', CreateValueMapping, data)
	data = re.sub('(interface )([a-zA-Z0-9_]+)()', CreateValueMapping, data)

def CreateInitialMappings(sourceFilename):
	data = GetFileContants(sourceFilename)

	MapFunctions(data)
	MapClasses(data)
	MapConstants(data)

def ObfuscateSourceFile(sourceFilename, destFilename):
	data = GetFileContants(sourceFilename)

	data = ObfuscateVariables(data)
	data = ObfuscateFunctions(data)
	data = ObfuscateConstants(data)
	data = ObfuscateClasses(data)

	WriteFile(destFilename, data)

def WriteMappingsTofile():
	global mappings

	mappingsString = ""
	for key, value in mappings.iteritems():
		mappingsString += key + " - " + value + "\n"

	WriteFile(DB_CONTAINER_FILE, mappingsString)

def RunOnAllFiles(directory, isMappingRun):
	for (path, dirs, files) in os.walk(directory):
		for filename in files:
			sourcePath = os.path.join(path, filename)
			fileExtension = os.path.splitext(filename)[1]

			if (True == isMappingRun):
				if fileExtension in FILE_EXTENSION_TO_OBFUSCATE:
					CreateInitialMappings(sourcePath)
			else:
				destinationPath = GenerateDestinationPath(sourcePath)

				if fileExtension in FILE_EXTENSION_TO_OBFUSCATE:
					ObfuscateSourceFile(sourcePath, destinationPath)
				else:
					shutil.copy(sourcePath, destinationPath)

def Main():
	RunOnAllFiles(SOURCE_CODE_DIRECTORY, True)
	RunOnAllFiles(SOURCE_CODE_DIRECTORY, False)
	WriteMappingsTofile()

Main()


from enum import Enum
from io import TextIOWrapper
from typing import Any, Dict
import requests
import config

from models import GoodDetail, ReceiptInfo, ReceiptMetadata, ReceiptResult

class StatusCodes(Enum):
    SUCCESS = 1
    TOO_MANY_REQUESTS = 3

def request_receipt_details(qr_file_data: TextIOWrapper) -> ReceiptResult:
    url = 'https://proverkacheka.com/api/v1/check/get'
    data = {'token': config.PROVERKA_CHECKA_TOKEN}
    files = {'qrfile': qr_file_data}
    response = requests.post(
        url, data=data, files=files)  # send request to API
    parsed_data = response.json()
    list_of_items = []
    if (response.status_code == 200):
        if (parsed_data["code"] != StatusCodes.SUCCESS.value):
            return ReceiptResult(is_ok=False, errror_msg=str(parsed_data["data"]))

        receipt_info = parsed_data["data"]['json']
        metadata = get_metadata(receipt_info)

        for k in receipt_info['items']:
            unit_price = round(k['price']/100) if is_countable(k) else to_rub_per_kg(k['price'], k['quantity'])
            list_of_items.append(GoodDetail(
                label=k['name'], unit_price=unit_price, count=k['quantity'], sum_price=k['price']/100))
        return ReceiptResult(ReceiptInfo(goods=list_of_items, metadata=metadata))
    else:
        return ReceiptResult(is_ok=False, errror_msg="Response status code is " + response.status_code)

def get_metadata(receipt_info: Dict[str, Any]) -> ReceiptMetadata:
    return ReceiptMetadata(
        receipt_id=receipt_info.get("metadata", {}).get("id", -1),
        retail_place=receipt_info.get("retailPlace", ""),
        total_sum=receipt_info.get("totalSum", 0)/100,
        date_time=receipt_info.get("dateTime", "")
    )

def is_countable(item):
    return isinstance(item['quantity'], int)

def to_rub_per_kg(total_price: float, quantity: float) -> int:
    return round(float('{:.2f}'.format(total_price / 100 * quantity)))


import datetime as dt
import time
import uuid

import pytest

import timtools.settings
from timtools.notify.notify import AbstractNotify

timtools.settings.replace_config_with_dummy()

class Notify(AbstractNotify):
    config_key = "test"

    def send_text(self, *args, **kwargs):
        ...

    def send_file(self, *args, **kwargs):
        ...

    def send_image(self, *args, **kwargs):
        ...

def test_no_config():
    if Notify.config_key in timtools.settings.USER_CONFIG:
        del timtools.settings.USER_CONFIG[Notify.config_key]

    with pytest.raises(ValueError):
        _ = Notify().config

def test_single_instance_timeout():
    Notify.timeout_window = dt.timedelta(milliseconds=500)
    notification_msg = f"TEST -- {uuid.uuid4()}"

    t = Notify()
    t._log_notification(notification_msg)
    assert t._is_timedout(notification_msg) is True
    time.sleep(t.timeout_window.total_seconds())
    assert t._is_timedout(notification_msg) is False

def test_cross_instance_timeout():
    Notify.timeout_window = dt.timedelta(milliseconds=500)
    notification_msg = f"TEST -- {uuid.uuid4()}"

    t = Notify()
    t._log_notification(notification_msg)

    t2 = Notify()
    assert t2._is_timedout(notification_msg) is True

    time.sleep(t.timeout_window.total_seconds())

    t3 = Notify()
    assert t3._is_timedout(notification_msg) is False


import logging
import socket

from .Common.Connector import Connector

log   = logging.getLogger(__name__ + '   ')
logPT = logging.getLogger(__name__ + ':PT')
logPU = logging.getLogger(__name__ + ':PU')

class Counterpart:

    def __init__(self, port, address='0.0.0.0', probePort=0, probeAddress='0.0.0.0'):
        self.probePort    = probePort
        self.probeAddress = probeAddress
        self.con   = Connector(log,   Connector.new(socket.SOCK_DGRAM, None,      port,      address))
        self.conPU = Connector(logPU, Connector.new(socket.SOCK_DGRAM,    2, probePort, probeAddress))

    def task(self):
        data, addr = self.con.recvfrom(1024)
        try:
            token      = data[:16]
            dest       = data[16:].decode('utf-8').split('\n')
            remoteAddr = dest[0]
            remotePort = int(dest[1])
        except:
            return

        log.info('    with token: x{0}'.format(token.hex()))
        log.info('    destination: [{0}]:{1}'.format(remoteAddr, remotePort))

        if token[0] == b'T'[0]:
            with Connector(logPT, Connector.new(socket.SOCK_STREAM, 2, self.probePort, self.probeAddress)) as conPT:
                try:
                    conPT.connect((remoteAddr, remotePort))
                    conPT.sendall(data)
                except OSError as e:
                    logPT.exception(e)
                    pass
        elif token[0] == b'U'[0]:
            for _ in range(3):
                self.conPU.sendto(data, (remoteAddr, remotePort))
        else:
            log.debug('    token does not specify TCP or UDP')


#coding:utf-8
import jieba
import os
from scipy.misc import imread  # 这是一个处理图像的函数
from wordcloud import WordCloud, STOPWORDS, ImageColorGenerator
import matplotlib.pyplot as plt

#reload(sys)

npath = os.getcwd()
filename = npath +'\\ntlk1\gg.txt'
print(filename)
gg = open(filename,'rb').read()
words = jieba.lcut( gg)
''' counts = {}
excludes = {" ", "我们","不是","两个","一个","如果","这个","那个"}
for word in words:
    if len(word) ==1:
        continue

    counts[word] = counts.get(word, 0) +1
    if word in excludes:
        del counts[word]

items = list(counts.items())
items.sort(key=lambda x:x[1], reverse=True)
for i in range(20):
    word, count = items[i]
    print("{0:<10}{1:>5}".format(word, count))
'''

imgfile = npath +'\\ntlk1\\1.jpg'
#使用词云显示
back_ground = imread(imgfile)
wc = WordCloud(background_color="white",max_words=1000, mask=back_ground, max_font_size=100,random_state=42, font_path="C:/Windows/Fonts/STFANGSO.ttf",)
wcword = ' '.join( words)
wc.generate( wcword)
# 基于彩色图像生成相应彩色
image_colors = ImageColorGenerator(back_ground)
# 显示图片
plt.imshow(wc)
# 关闭坐标轴
plt.axis('off')
# 绘制词云
plt.figure()
plt.imshow(wc.recolor(color_func=image_colors))
plt.axis('off')
# 保存图片
wc.to_file('19th.png')


from odoo import models, fields, api, _
from odoo.exceptions import UserError, ValidationError
from datetime import datetime, timedelta

class AccountJournal(models.Model):
    _inherit = 'account.journal'

    type = fields.Selection(selection_add=[('wip', 'WIP')])

class AccountInvoice(models.Model):
    _inherit = "account.invoice"

    @api.one
    @api.depends('invoice_line_ids')
    def _compute_month_id(self):
        analytic_invoice_id = self.invoice_line_ids.mapped('analytic_invoice_id')
        self.month_id = analytic_invoice_id and analytic_invoice_id[0].month_id.id or False

    target_invoice_amount = fields.Monetary(
        'Target Invoice Amount'
    )
    month_id = fields.Many2one(
        'date.range',
        compute='_compute_month_id',
        string="Invoicing Period"
    )
    wip_move_id = fields.Many2one(
        'account.move',
        string='WIP Journal Entry',
        readonly=True,
        index=True,
        ondelete='restrict',
        copy=False
    )

    def compute_target_invoice_amount(self):
        if self.amount_untaxed != self.target_invoice_amount:
            factor = self.target_invoice_amount / self.amount_untaxed
            discount = (1.0 - factor) * 100
            for line in self.invoice_line_ids:
                line.discount = discount

    def reset_target_invoice_amount(self):
        for line in self.invoice_line_ids:
            line.discount = 0.0

    @api.model
    def invoice_line_move_line_get(self):
        """Copy operating_unit_id from invoice line to move lines"""
        res = super(AccountInvoice, self).invoice_line_move_line_get()
        ailo = self.env['account.invoice.line']
        for move_line_dict in res:
            iline = ailo.browse(move_line_dict['invl_id'])
            if iline.user_id:
                move_line_dict['user_id'] = iline.user_id.id
        return res

    @api.model
    def line_get_convert(self, line, part):
        res = super(AccountInvoice, self).line_get_convert(line, part)
        res['user_id'] = line.get('user_id', False)
        return res

    def inv_line_characteristic_hashcode(self, invoice_line):
        """Overridable hashcode generation for invoice lines. Lines having the same hashcode
        will be grouped together if the journal has the 'group line' option. Of course a module
        can add fields to invoice lines that would need to be tested too before merging lines
        or not."""
        res = super(AccountInvoice, self).inv_line_characteristic_hashcode(invoice_line)
        return res + "%s" % (
            invoice_line['user_id']
        )

    @api.multi
    def _get_timesheet_by_group(self):
        self.ensure_one()
        aal_ids = []
        analytic_invoice_ids = self.invoice_line_ids.mapped('analytic_invoice_id')
        for analytic_invoice in analytic_invoice_ids:
            for grp_line in analytic_invoice.user_total_ids:
                aal_ids += grp_line.detail_ids
        userProject = {}
        for aal in aal_ids:
            project_id, user_id = aal.project_id if aal.project_id else aal.task_id.project_id , aal.user_id
            if project_id.correction_charge and project_id.specs_invoice_report:
                if (project_id, user_id) in userProject:
                    userProject[(project_id, user_id)] = userProject[(project_id, user_id)] + [aal]
                else:
                    userProject[(project_id, user_id)] = [aal]
        return userProject

    @api.multi
    def action_invoice_open(self):
        res = super(AccountInvoice, self).action_invoice_open()
        if self.type in ('out_invoice'):
            analytic_invoice_id = self.invoice_line_ids.mapped('analytic_invoice_id')
            if not analytic_invoice_id:
                return res
            # if invoicing period doesn't lie in same month
            period_date = datetime.strptime(analytic_invoice_id.month_id.date_start, "%Y-%m-%d").strftime('%Y-%m')
            cur_date = datetime.now().date().strftime("%Y-%m")
            invoice_date = self.date or self.date_invoice
            inv_date = datetime.strptime(invoice_date, "%Y-%m-%d").strftime('%Y-%m') if invoice_date else cur_date
            if inv_date != period_date and self.move_id:
                self.action_wip_move_create()
        return res

    @api.model
    def get_wip_default_account(self):
        if self.type in ('out_invoice', 'in_refund'):
            return self.journal_id.default_credit_account_id.id
        return self.journal_id.default_debit_account_id.id

    @api.multi
    def action_wip_move_create(self):
        """ Creates invoice related analytics and financial move lines """
        for inv in self:
            wip_journal = self.env.ref('magnus_timesheet.wip_journal')
            if not wip_journal.sequence_id:
                raise UserError(_('Please define sequence on the type WIP journal.'))
            sequence = wip_journal.sequence_id
            if inv.type in ['out_refund', 'in_invoice','in_refund'] or inv.wip_move_id:
                continue
            date_end = inv.month_id.date_end
            new_name = sequence.with_context(ir_sequence_date=date_end).next_by_id()
            if inv.move_id:
                wip_move = inv.move_id.wip_move_create( wip_journal, new_name, inv.account_id.id, inv.number)
            wip_move.post()
            # make the invoice point to that wip move
            inv.wip_move_id = wip_move.id
            #wip reverse posting
            reverse_date = datetime.strptime(wip_move.date, "%Y-%m-%d") + timedelta(days=1)
            line_amt = sum(ml.credit + ml.debit for ml in wip_move.line_ids)
            reconcile = False
            if line_amt > 0:
                reconcile = True
            reverse_wip_move = wip_move.create_reversals(
                date=reverse_date,
                journal=wip_journal,
                move_prefix='WIP Invoicing Reverse',
                line_prefix='WIP Invoicing Reverse',
                reconcile=reconcile
            )
            if len(reverse_wip_move) == 1:
                wip_nxt_seq = sequence.with_context(ir_sequence_date=reverse_wip_move.date).next_by_id()
                reverse_wip_move.write({'name':wip_nxt_seq})

        return True

    @api.multi
    def action_cancel(self):
        res = super(AccountInvoice, self).action_cancel()
        wip_moves = self.env['account.move']
        for inv in self:
            if inv.wip_move_id:
                wip_moves += inv.wip_move_id

        # First, set the invoices as cancelled and detach the move ids
        self.write({'wip_move_id': False})
        if wip_moves:
            # second, invalidate the move(s)
            wip_moves.button_cancel()
            # delete the move this invoice was pointing to
            # Note that the corresponding move_lines and move_reconciles
            # will be automatically deleted too
            wip_moves.unlink()
        return res

class AccountInvoiceLine(models.Model):
    _inherit = "account.invoice.line"

    analytic_invoice_id = fields.Many2one(
        'analytic.invoice',
        string='Invoice Reference',
        ondelete='cascade',
        index=True
    )
    user_id = fields.Many2one(
        'res.users',
        'Timesheet User',
        index = True
    )
    user_task_total_line_id = fields.Many2one(
        'analytic.user.total',
        string='Grouped Analytic line',
        ondelete='cascade',
        index=True
    )

    @api.depends('account_analytic_id', 'user_id', 'invoice_id.operating_unit_id')
    @api.multi
    def _compute_operating_unit(self):
        super(AccountInvoiceLine, self)._compute_operating_unit()
        for line in self.filtered('user_id'):
            line.operating_unit_id = line.user_id._get_operating_unit_id()

    # @api.multi
    # def write(self, vals):
    #     res = super(AccountInvoiceLine, self).write(vals)
    #     self.filtered('analytic_invoice_id').mapped('invoice_id').compute_taxes() #Issue: Vat creation double after invoice date change
    #     return res

    @api.model
    def default_get(self, fields):
        res = super(AccountInvoiceLine, self).default_get(fields)
        ctx = self.env.context.copy()
        if 'default_invoice_id' in ctx:
            invoice_obj = self.env['account.invoice'].browse(ctx['default_invoice_id'])
            analytic_invoice_id = invoice_obj.invoice_line_ids.mapped('analytic_invoice_id')
            if analytic_invoice_id:
                res['analytic_invoice_id'] = analytic_invoice_id.id
        return res

#    @api.onchange('product_id')
#    def _onchange_product_id(self):
#        if self.analytic_invoice_id:
#            self.invoice_id = self.env['account.invoice'].browse(self.analytic_invoice_id.invoice_ids.id)
#        return super(AccountInvoiceLine, self)._onchange_product_id()


import pickle
import time
import argparse
import os
import errno
import numpy as np

from SAC import trainSAC
from SACHyperparameters import Hyperparameters

def my_import(name):
    components = name.split('/')
    mod = __import__(components[0])
    for comp in components[1:]:
        mod = getattr(mod, comp)
    return mod

def parseArguments():
    """
    Parse arguments from the command line.

    Returns
    -------
    root_dir : str
        Root directory for saving the results.

    hp : Hyperparameters
        Hyperparameters for the SAC algorithm.

    """
    # Parse arguments
    parser = argparse.ArgumentParser(description='MLQTransfer')
    parser.add_argument('-r', '--root_dir', type=str, required=True, help='Root directory for saving the results')
    parser.add_argument('-hp', '--hyperparameters', type=str, help='File containing the hiperparameters')
    parser.add_argument('-shp', '--save_hyperparameters', action='store_true', help='Save the hyperparameters')
    args = parser.parse_args()

    if args.hyperparameters is None:
        hp = Hyperparameters(root_dir=args.root_dir)
    else:
        print("---------------------------------------")
        print("Loading hyperparameters from: ", args.hyperparameters)
        print("---------------------------------------")
        hp = my_import(args.hyperparameters).Hyperparameters(root_dir=args.root_dir)

    root_dir = args.root_dir
    saveHyperparameters = args.save_hyperparameters

    if saveHyperparameters:
        print("Saving hyperparameters")
        filepath = root_dir + "/hyperparameters_" + time.strftime("%Y%m%d-%H%M%S") + ".pkl"
        try:
            os.makedirs(root_dir)
        except OSError as exc:
            if exc.errno == errno.EEXIST and os.path.isdir(root_dir):
                pass
            else: raise

        with open(filepath, 'wb') as f:
            pickle.dump(hp, f)

    return root_dir, hp

if __name__ == '__main__':
    # Parse arguments
    root_dir, hp = parseArguments()

    # Create and Train the agent
    trainSAC(
        env_collect_py=hp.env_collect_py,
        env_eval_py=hp.env_eval_py,
        root_dir=root_dir,
        num_iterations=hp.num_iterations,
        actor_fc_layers=hp.actor_fc_layers,
        critic_joint_fc_layers=hp.critic_joint_fc_layers,
        replay_buffer_capacity=hp.replay_buffer_capacity,
        initial_collect_steps=hp.initial_collect_steps,
        eval_interval=hp.eval_interval,
        summary_interval=hp.summary_interval,
        collect_steps_per_iteration=hp.collect_steps_per_iteration,
        batch_size=hp.batch_size,
        actor_learning_rate=hp.actor_learning_rate,
        critic_learning_rate=hp.critic_learning_rate,
        alpha_learning_rate=hp.alpha_learning_rate,
        gamma=hp.gamma,
        num_eval_episodes=hp.num_eval_episodes,
        target_entropy=hp.target_entropy,
        train_checkpoint_interval=hp.train_checkpoint_interval,
        policy_checkpoint_interval=hp.policy_checkpoint_interval,
        rb_checkpoint_interval=hp.rb_checkpoint_interval
        )

    max_target_population = np.max(hp.env_eval_py.best_populations[:, :-1][-1, :])
    max_intermediate_population = np.max(hp.env_eval_py.best_populations[:, :-1][1:-1, :])

    print("---------------------------------------")
    print("Training finished")
    print("---------------------------------------")
    print("Best Reward: ", hp.env_eval_py.best_reward)
    print("Final Target Population: ", hp.env_eval_py.best_populations[:, :-1][-1, -1])
    print("Max Target Population: ", max_target_population)
    print("Max intermidiate population: ", max_intermediate_population)
    print("---------------------------------------")


def get_info():
    info = []
    surname = input('Введите фамилию: ')
    info.append(surname)
    name = input('Введите имя: ')
    info.append(name)
    phone_number = ''
    valid = False
    while not valid:
        try:                 # Обработка исключений. Оператор try-except и if-else проверка на количество цифр и вводимые символы
            phone_number = input('Введите номер телефона: ')
            if len(phone_number) != 11:
                print('в номере телефона должно быть 11 цифр')
            else:
                phone_number = int(phone_number)
                valid = True
        except:
            print('Номер телефона должен состоять только из цифр.')
    info.append(phone_number)
    description = input('Введите описание: ')
    info.append(description)
    return info

# Когда ошибки в программе возникают в процессе написания кода или его тестирования, то код исправляется программистом
# так, чтобы ошибок не возникало. Однако нередко действия пользователя приводят к тому, что в программе возникает
# исключение. Например, программа ожидает ввод числа, но человек ввел букву. Попытка преобразовать ее к числу приведет к
# возбуждению исключения ValueError, и программа аварийно завершится. На этот случай в языках программирования, в том
# числе Python, существует специальный оператор, позволяющий перехватывать возникающие исключения и обрабатывать их так,
# чтобы программа продолжала работать или корректно завершала свою работу. В Питоне такой перехват выполняет оператор
# try-except. "Try" переводится как "попытаться", "except" – как исключение. Словами описать его работу можно так:
# "Попытаться сделать то-то и то-то, если при этом возникло исключение, то сделать вот это и это."
# Его конструкция похожа на условный оператор с веткой else.


import pyautogui
from PIL import Image
import cv2
import time
import numpy as np

class daotianlu():
    def __init__(self) -> None:
        self.x = 734 #小程序左上角坐标x轴  1187   734
        self.y = 98  #小程序左上角y轴       97    98
        self.w = 449 #小程序宽度(通过 左上角x轴-右上角x轴 得出结果)
        self.h = 841 #小程序高度(通过 左上角y轴-左下角y轴 得出结果)
        self.fanhuizuobiao = 1138,897 #返回按钮的坐标(当需要手动时)1586  1138
        self.dibuzuobiao = 962,912 #空白处底部坐标(当需要手动时)1404  962
        self.tupozuobiao= 960,599 #突破坐标(当需要手动时)1409  960

        self.dizi = cv2.imread('images/dizi.png') #主页弟子图片
        self.peiyang = cv2.imread('images/peiyang.png') #进入弟子培养图片
        self.xiuxing = cv2.imread('images/xiuxing.png') #进入培养找到修行按钮
        self.xiuxingtupo = cv2.imread('images/xiuxingtupo.png') #修行突破标识
        self.next = cv2.imread('images/next.png') #下一个人物
        self.pojing = cv2.imread('images/pojing.png') #破镜按钮
        self.tupo = cv2.imread('images/tupo.png') #突破按钮
        self.querentupo = cv2.imread('images/querentupo.png') #确认突破
        self.queren = cv2.imread('images/queren.png') #成功率不足时出现确认
        self.tiaoguo = cv2.imread('images/tiaoguo.png') #跳过突破
        self.renwu = cv2.imread('images/renwu.png') #主页任务图片
        self.fanhui = cv2.imread('images/fanhui.png') #主页任务图片
        self.liandanrenwu = cv2.imread('images/liandanrenwu.png') #任务中的炼丹任务
        self.zhibiao = cv2.imread('images/zhibiao.png') #任务指标
        self.liandankefenpei = cv2.imread('images/liandankefenpei.png') #炼丹人物分配点击
        self.liandanxuanze = cv2.imread('images/liandanxuanze.png') #炼丹人物选择
        self.danyao = cv2.imread('images/danyao.png') #炼丹丹药
        self.danyaolianzhi = cv2.imread('images/danyaolianzhi.png') #丹药炼制
        self.danyaodi = cv2.imread('images/danyaodi.png') #丹药炼制调整最低
        self.liandanqueren = cv2.imread('images/liandanqueren.png') #丹药确认
        self.tuichu = cv2.imread('images/tuichu.png') #丹药退出
        self.changjinggerenwu = cv2.imread('images/changjinggerenwu.png') #藏经阁任务
        self.yanxi = cv2.imread('images/yanxi.png') #藏经阁研习
        self.yanxiquanbu = cv2.imread('images/yanxiquanbu.png') #藏经阁研习全部
        self.youli = cv2.imread('images/youli.png') #游历任务
        self.youlitiaozhan = cv2.imread('images/youlitiaozhan.png') #游历挑战
        self.youlijiangli = cv2.imread('images/youlijiangli.png') #游历奖励
        self.lingqu = cv2.imread('images/lingqu.png') #游历奖励领取
        self.youlishouyi = cv2.imread('images/youlishouyi.png') #游历快速收益
        self.youlilingqu = cv2.imread('images/youlilingqu.png') #游历快速领取
        self.youlihuicheng = cv2.imread('images/youlihuicheng.png') #游历回城
        self.suoyaota = cv2.imread('images/suoyaota.png') #锁妖塔任务
        self.suoyaota1 = cv2.imread('images/suoyaota1.png') #选择锁妖塔
        self.suoyaotajiangli = cv2.imread('images/suoyaotajiangli.png') #锁妖塔奖励

        self.douji = cv2.imread('images/douji.png') #主页斗技图片
        self.tiaozhan = cv2.imread('images/tiaozhan.png') #挑战3/3按钮
        self.tiaozhan1 = cv2.imread('images/tiaozhan1.png') #挑战按钮
        self.zhuye = cv2.imread('images/zhuye.png') #挑战按钮
        self.wanshangtiaozhan = cv2.imread('images/wanshangtiaozhan.png') #晚上过十点的挑战图片

        self.fangke = cv2.imread('images/fangke.png') #访客按钮
        self.fangkewenhao = cv2.imread('images/fangkewenhao.png') #访客人按钮
        self.fangkewenhao1 = cv2.imread('images/fangkewenhao1.png') #访客人按钮(夜间)
        self.fangkejixu = cv2.imread('images/fangkejixu.png') #访客继续按钮
        self.fangkewenti = cv2.imread('images/fangkewenti.png') #访客确认问题按钮
        self.fangkewenti1 = cv2.imread('images/fangkewenti1.png') #访客确认问题按钮
        self.fangkezhandou = cv2.imread('images/fangkezhandou.png') #访客战斗按钮

    def jietu(self):
        # 截取整个屏幕
        screenshot = pyautogui.screenshot()
        # 截取指定区域，这里的参数是一个元组，分别指定左上角和右下角的坐标
        # 例如，这里截取了屏幕上方 100 像素的区域
        region = (self.x,self.y,self.w,self.h)
        screenshot = pyautogui.screenshot(region=region)
        # 保存截图到文件
        screenshot.save('images/screenshot.png')
        large_image = cv2.imread('images/screenshot.png')
        return large_image

    #查找
    def chazhao(self):
        #查找弟子按钮在哪
        self.zuobiao(self.dizi)
        #查找培养按钮
        self.zuobiao(self.peiyang)
        #查找修行按钮
        self.zuobiao(self.xiuxing)
        #弟子轮询
        for i in range(60):
            location = self.zuobiao(self.xiuxingtupo)
            if location is None:
                self.zuobiao(self.next)
            else:
                self.tupos()
        self.click(self.dibuzuobiao[0],self.dibuzuobiao[1])#手动点击空白处
        #返回到主页
        locahost = self.zuobiao(self.fanhui)
        if locahost is None:
            self.click(self.fanhuizuobiao[0],self.fanhuizuobiao[1]) #手动返回
        #访客操作
        self.fangkes()
        #任务操作
        location = self.zuobiao(self.renwu)
        if location is None:
            self.click(self.fanhuizuobiao[0],self.fanhuizuobiao[1])#手动点击返回
            self.zuobiao(self.renwu)
        self.renwus()
        time.sleep(1)
        #斗技场操作
        self.zuobiao(self.douji)
        self.doujis()

    #任务
    def renwus(self):
        localhost = self.zuobiao(self.liandanrenwu)
        if localhost is not None:
            self.liandan(localhost=localhost)
        localhost = self.zuobiao(self.changjinggerenwu)
        if localhost is not None:
            self.changjingge(localhost)
        localhost = self.zuobiao(self.youli)
        if localhost is not None:
            self.youlirenwu(localhost)
        pyautogui.moveTo(217+self.x, 461+self.y)#移动到任务栏中心
        pyautogui.scroll(-100) #滚动到最下栏
        pyautogui.scroll(-100)
        pyautogui.scroll(-100)
        localhost = self.zuobiao(self.suoyaota)
        if localhost is not None:
            self.suoyaotarenwu(localhost)
        self.click(self.dibuzuobiao[0],self.dibuzuobiao[1])#手动到主页

    #锁妖塔操作
    def suoyaotarenwu(self,localhost):
        self.click(localhost[0]+250+self.x,localhost[1]+self.y+20)
        time.sleep(5)
        localhost = self.zuobiao(self.zhibiao)
        if localhost is not None:
             self.click(localhost[0]+self.x,localhost[1]+self.y+170)#进入锁妖塔
             time.sleep(2)
        self.zuobiao(self.suoyaota1)
        localhost = self.zuobiao(self.suoyaotajiangli)
        self.click(self.dibuzuobiao[0],self.dibuzuobiao[1])#手动返回锁妖塔主页
        #如果有主页弹窗就会取消掉
        locahost = self.zuobiao(self.zhuye)
        if locahost is not None:
            self.click(self.fanhuizuobiao[0],self.fanhuizuobiao[1]) #手动退出弹窗

    #游历操作
    def youlirenwu(self,localhost):
        self.click(localhost[0]+250+self.x,localhost[1]+self.y+20)
        time.sleep(1)
        self.zuobiao(self.youlitiaozhan)
        time.sleep(4)
        localhost = self.zuobiao(self.youlijiangli)
        if localhost is not None:
            self.zuobiao(self.lingqu)
            time.sleep(3)
            self.click(self.dibuzuobiao[0],self.dibuzuobiao[1])#手动点击空白处
        localhost = self.zuobiao(self.youlijiangli)
        if localhost is not None:
            self.zuobiao(self.youlishouyi)
            self.zuobiao(self.youlilingqu)
            time.sleep(3)
            self.click(self.dibuzuobiao[0],self.dibuzuobiao[1])#手动点击空白处
            self.click(self.dibuzuobiao[0],self.dibuzuobiao[1])#手动点击空白处
        self.zuobiao(self.youlihuicheng)#退出游历
        time.sleep(5)
        #如果有主页弹窗就会取消掉
        locahost = self.zuobiao(self.zhuye)
        if locahost is not None:
            self.click(self.fanhuizuobiao[0],self.fanhuizuobiao[1]) #手动退出弹窗
        self.zuobiao(self.renwu)#返回任务

    #藏经阁操作
    def changjingge(self,localhost):
        self.click(localhost[0]+250+self.x,localhost[1]+self.y+20)
        time.sleep(5)
        localhost = self.zuobiao(self.zhibiao)
        if localhost is not None:
             self.click(localhost[0]+self.x+20,localhost[1]+self.y+170)#进入藏经阁
             time.sleep(2)
        localhost = self.zuobiao(self.yanxi)
        if localhost is not None:
            self.zuobiao(self.yanxiquanbu)
            time.sleep(5)
            self.click(self.dibuzuobiao[0],self.dibuzuobiao[1])#研习完毕
            self.click(self.dibuzuobiao[0],self.dibuzuobiao[1])#退出研习
        self.zuobiao(self.tuichu)#退出藏经阁
        time.sleep(0.5)
        #如果有主页弹窗就会取消掉
        locahost = self.zuobiao(self.zhuye)
        if locahost is not None:
            self.click(self.fanhuizuobiao[0],self.fanhuizuobiao[1]) #手动退出弹窗
        self.zuobiao(self.renwu)#返回任务

    #炼丹炉操作
    def liandan(self,localhost):
        self.click(localhost[0]+250+self.x,localhost[1]+self.y+20)
        time.sleep(5)
        localhost = self.zuobiao(self.zhibiao)
        if localhost is not None:
            self.click(localhost[0]+self.x-10,localhost[1]+self.y+128)#进入丹炉
            time.sleep(1)
            self.click(localhost[0]+self.x-10,localhost[1]+self.y+168)#进入丹炉配置
            time.sleep(1)
        localhost = self.zuobiao(self.liandankefenpei)
        #选择炼丹分配人物
        if localhost is not None:
            self.zuobiao(self.liandanxuanze)
            self.zuobiao(self.queren)
            time.sleep(1)
        #炼丹丹药选择
        localhost = self.zuobiao(self.danyao)
        if localhost is not None:
            self.zuobiao(self.danyaolianzhi)
            localhost = self.zuobiao(self.danyaodi)
            if localhost is not None:
                self.click(localhost[0]+self.x+34,localhost[1]+self.y+16)#丹炉炼制调制最低
                localhost = self.zuobiao(self.liandanqueren)
                pyautogui.moveTo(localhost[0]+self.x, localhost[1]-50+self.y)
                pyautogui.mouseDown(button='left')
                end_x, end_y = (localhost[0]+61+self.x, localhost[1]-50+self.y)  # 指定结束点位置
                pyautogui.moveTo(end_x, end_y, duration=1)  # 移动鼠标到结束点位置
                pyautogui.PAUSE = 1  # 等待一段时间
                pyautogui.mouseUp(button='left')  # 松开鼠标左键
                self.click(end_x+60,end_y)#点击边缘
        self.zuobiao(self.tuichu)
        time.sleep(0.5)
        self.zuobiao(self.renwu)#返回任务

    #访客
    def fangkes(self):
        localhost = self.zuobiao(self.fangke)
        if localhost is None:
            self.zuobiao(self.fangke)
        time.sleep(3)
        while True:
            print("进入访客")
            localhost = self.zuobiao(self.fangkewenhao)
            if localhost is not None:
                break
            else:
                localhost = self.zuobiao(self.fangkewenhao1)
                if localhost is not None:
                    break
        time.sleep(1)
        while True:
            #连续对话(普通)
            print("访客连续对话")
            localhost = self.zuobiao(self.fangkejixu)
            if localhost is None:
                print("访客结束")
                break
            #当出现问题时(随机点击一个问题)
            localhost = self.zuobiao(self.fangkewenti)
            if localhost is not None:
                self.zuobiao(self.queren)
            localhost = self.zuobiao(self.fangkewenti1)
            if localhost is not None:
                self.zuobiao(self.queren)
            localhost = self.zuobiao(self.fangkezhandou)
            if localhost is not None:
                print("进入访客战斗")
                time.sleep(8)
                localhost = self.zuobiao(self.tiaoguo)
                if localhost is None:
                    self.click(self.dibuzuobiao[0],self.dibuzuobiao[1])#手动点击空白处(返回到主页)
                time.sleep(3)
        locahost = self.zuobiao(self.zhuye)
        if locahost is not None:
            self.click(self.fanhuizuobiao[0],self.fanhuizuobiao[1]) #手动退出弹窗

    #斗技
    def doujis(self):
        time.sleep(2)
        for i in range(3):
            #判断是否过了十点的挑战
            locahost = self.zuobiao(self.wanshangtiaozhan)
            if locahost is not None:
                    self.click(self.fanhuizuobiao[0],self.fanhuizuobiao[1]) #手动返回
                    return
            #点击挑战
            locahost = self.zuobiao(self.tiaozhan)
            if locahost is None:
                self.click(self.fanhuizuobiao[0],self.fanhuizuobiao[1])
                return
            #选择挑战人物
            self.zuobiao(self.tiaozhan1)
            time.sleep(10)
            #循环查找是否通过挑战
            while True:
                print("进入斗技")
                locahost = self.zuobiao(self.tiaoguo)
                if locahost is not None:
                    break
            time.sleep(3)
        #返回到主页
        locahost = self.zuobiao(self.fanhui)
        if locahost is None:
            self.click(self.fanhuizuobiao[0],self.fanhuizuobiao[1]) #手动返回
        time.sleep(3)
        #如果有主页弹窗就会取消掉
        locahost = self.zuobiao(self.zhuye)
        if locahost is not None:
            self.click(self.fanhuizuobiao[0],self.fanhuizuobiao[1]) #手动退出弹窗

    #突破
    def tupos(self):
        #查找破镜按钮
        localhost = self.zuobiao(self.pojing)
        print("有突破:",localhost)
        if localhost is None:
            self.click(self.tupozuobiao[0],self.tupozuobiao[1])
        self.zuobiao(self.querentupo)
        #如果遇到成功率不足
        self.zuobiao(self.queren)
        #跳过突破
        localhost = self.zuobiao(self.tiaoguo)
        if localhost is not None:
            self.click(localhost[0]+self.x,localhost[1]+self.y)
            time.sleep(2)
            self.click(localhost[0]+self.x,localhost[1]+self.y)
        else:
            #手动跳过
            self.click(self.dibuzuobiao[0],self.dibuzuobiao[1])
            self.click(self.dibuzuobiao[0],self.dibuzuobiao[1])

    #查找图片是否存在
    def find_image_location(self,large_image, small_image, threshold=0.9):
        w, h = small_image.shape[::2]
        res = cv2.matchTemplate(large_image, small_image, cv2.TM_CCOEFF_NORMED)
        loc = np.where(res >= threshold)
        # 获取匹配结果中的最大值和位置
        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
        top_left = max_loc
        bottom_right = (top_left[0] + w, top_left[1] + h)
        # 计算小图在大图中的中心点坐标
        center_x = int((top_left[0] + bottom_right[0]) / 2)
        center_y = int((top_left[1] + bottom_right[1]) / 2)

        if len(loc[0]) == 0:
            return None

        #显示每个阶段图片
        # cv2.rectangle(large_image, top_left, bottom_right, (0, 0, 255), 2)
        # cv2.imshow('Large Image', large_image)
        # cv2.waitKey(0)
        # cv2.destroyAllWindows()
        return center_x,center_y

    #坐标
    def zuobiao(self,small_image):
        #截图当前
        large_image = self.jietu()
        location = self.find_image_location(large_image,small_image)
        if location is None:
            print("没有找到")
        else:
            print("找到图片:", location)
            self.click(location[0]+self.x,location[1]+self.y)
        return location

    #点击
    def click(self,x,y):
        pyautogui.moveTo(x, y)
        pyautogui.click()
        time.sleep(0.5)

if __name__ == "__main__":
    dao = daotianlu()
    dao.chazhao()
    cv2.waitKey(0)
    cv2.destroyAllWindows()