from celery import shared_task
from django.core.mail import EmailMultiAlternatives, send_mail
from core import settings
from yaml import load as load_yaml, Loader
from .models import Shop, Category, Product, ProductInfo, Parameter, ProductParameter
from rest_framework.response import Response
import yaml

# запуск worker ов: celery -A core.celery worker

'''Отправляем сообщение при подтверждении заказа - Клиенту'''
@shared_task
def celery_confirmation_order_email(recipient_email, username, order_id, product_infos, address_dict):
    print('yes')
    address_str = f'{address_dict["city"]}, {address_dict["street"]}, ' \
                  f'{address_dict["house"]},{address_dict["building"]}, {address_dict["apartment"]}'
    subject = f'Ваш заказ №. {order_id} подтвержден'

    product_info_str = ""
    for item in product_infos:
        product_info_str += f'\n\nИнформация о заказе:' \
                            f'\nНазвание: {product_infos[item][0]} \nМодель {product_infos[item][1]} \nКоличество: {product_infos[item][2]}  \n' \
                            f'Цена: {product_infos[item][3]}\n'
    message = f'{username}, Ваш заказ подтвержден.\n' \
              f'Details: Номер заказа: {order_id}, {product_info_str}\n' \
              f'Адрес доставки: {address_str}'
    recipient_list = [recipient_email]
    send_mail(subject=subject, message=message, from_email=settings.EMAIL_HOST_USER, recipient_list=recipient_list)

'''Отправляем сообщение при подтверждении заказа - Компании'''
@shared_task
def celery_confirmation_order_email_for_shop(dict_order: dict, order_id, address_dict):
    address_str = f'{address_dict["city"]}, {address_dict["street"]}, ' \
                  f'{address_dict["house"]},{address_dict["building"]}, {address_dict["apartment"]}'
    subject = f'В вашем магазине был сделан заказ №. {order_id} - он подтвержден'

    '''Проверяем если список - значит несколько товаров у одного магазина, собираем и отправляем сообщение магазину'''
    for key, value in dict_order.items():
        mess = ''
        if type(value) == list:
            for item in value:
                mess += f'Название продукта - {item[1]} - {item[2]} шт. \n'
            message = f'Заказ подтвержден.\n' \
                          f'Details: Номер заказа: {order_id}, Информация о заказе: \n {mess}' \
                          f'Адрес доставки: {address_str}'

            recipient_list = [key]
            send_mail(subject=subject, message=message, from_email=settings.EMAIL_HOST_USER,
                          recipient_list=recipient_list)
        else:
            mess += f'Назавание продукта - {value[1]} - {value[2]} шт. \n'
            message = f'Заказ подтвержден.\n' \
                      f'Details: Номер заказа: {order_id}, Информация о заказе: \n {mess}' \
                      f'Адрес доставки: {address_str}'

            recipient_list = [key]
            send_mail(subject=subject, message=message, from_email=settings.EMAIL_HOST_USER,
                      recipient_list=recipient_list)

'''Загружаем продукты - Компании'''
@shared_task
def celery_save_products_shop(filename):
    with open(f"media/{filename}") as stream:
        try:
            data = load_yaml(stream, Loader=Loader)
            shop_data = data['shop']

            categories = data['categories']
            goods = data['goods']
            shop, _ = Shop.objects.get_or_create(name=shop_data)
            for category_data in categories:
                category, _ = Category.objects.get_or_create(id=category_data['id'], name=category_data['name'])
                category.shops.add(shop.id)
                category.save()

            ProductInfo.objects.filter(shop_id=shop.id).delete()
            for good in goods:
                product, _ = Product.objects.get_or_create(id=good['id'], name=good['name'],
                                                           category_id=good['category'])

                product_info = ProductInfo.objects.create(
                    product=product,
                    shop=shop,
                    model=good['model'],
                    price=good['price'],
                    price_rrc=good['price_rrc'],
                    quantity=good['quantity'])
                for name, value in good['parameters'].items():
                    parameter_object, _ = Parameter.objects.get_or_create(name=name)
                    ProductParameter.objects.create(
                        product_info=product_info,
                        parameter=parameter_object,
                        value=value)
        except yaml.YAMLError as exc:
            return Response({'status': 'Error', 'message': exc})
        return Response({'status': 'OK'})


import os

def lees_bestand_in(bestandsnaam):
    fo = open(bestandsnaam)
    line = fo.readline()
    regelnr = 1
    while line != "":
        line = line.rstrip()
        print(f"regel {regelnr}: {line}")
        regelnr += 1
        line = fo.readline()
    fo.close()

def schrijf_input_naar_bestand(bestandsnaam):
    fo = open(bestandsnaam, "w")
    lijn = input("Geef een regel of druk op enter om te stoppen >")
    while lijn != "":
        fo.write(f"{lijn}\n")
        lijn = input("geef een zin op>")

if os.path.exists("DRB/temp.txt"):
    lees_bestand_in("DRB/temp.txt")
else:
    schrijf_input_naar_bestand("DRB/temp.txt")


import sys

sys.path.append(".")

import datetime
from collections import defaultdict
from tqdm import tqdm
import os

import torch
import torch.nn as nn
import torchvision.models as models
import torchvision.transforms as transforms
from torch.autograd import Variable
from PIL import Image

from common.util import *

"""
SET PARAMETER
引数1 : CATEGORY
引数2 : MODEL
引数2 : 分割数
引数3 : index
"""

## SET category
CATEGORY = "dog"
if sys.argv and len(sys.argv) >= 2:
    CATEGORY = sys.argv[1]

## SET model
MODEL_NAME = "resnet18"
if sys.argv and len(sys.argv) >= 3:
    MODEL_NAME = sys.argv[2]

## SET divide
DIVIDE = 10
DIVIDE_FLG = False
if sys.argv and len(sys.argv) >= 4:
    DIVIDE = int(sys.argv[3])
    DIVIDE_FLG = True

## SET index
DIVIDE_INDEX = 0
if sys.argv and len(sys.argv) >= 5:
    DIVIDE_INDEX = int(sys.argv[4])

"""
LOGIC
"""

## use GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print("USE GPU:", torch.cuda.is_available())

"""
Prepare MODEL
- model
- get_vector( img -> torch )
- from_layers
"""

model = None
copy_dest_embedding = {}
vectors = {}
from_layers = {}

transform = transforms.Compose(
    [
        transforms.Resize(224),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
    ]
)

if MODEL_NAME == "resnet18":
    ## LOAD: resnet pretrained model
    model = models.resnet18(pretrained=True)
    model.eval()

    ## 取得するlayerの一覧
    from_layers = {
        "avgpool": 512,
        "layer4": 512,
        "layer3": 256,
        "layer2": 128,
        "layer1": 64,
    }

    ## コピー用の関数とコピー先の変数
    def copy_data(m, i, o):
        copy_dest_embedding[m.lname].copy_(o.data[0, :, 0, 0])

    ## 各レイヤーにコピー関数をfookする
    layers = []
    handles = []
    for name, size in from_layers.items():
        l = model._modules.get(name)

        ## copy先を指定するため、attrを追加
        setattr(l, "lname", name)

        ## copy関数を登録
        handles += [l.register_forward_hook(copy_data)]

        ## 出力先を用意
        vectors[name] = []
        copy_dest_embedding[name] = torch.zeros(size)

    ## ベクトル取得用の関数
    ## copy_dest_embeddingに結果を格納
    def get_vector(img):
        ## Create a PyTorch Variable with the transformed image
        t_img = transform(img)
        t_img = torch.unsqueeze(t_img, 0)

        ## move the input to GPU for speed if available
        if torch.cuda.is_available():
            t_img = t_img.to(device)

        ## Run the model on our transformed image
        model(t_img)

        return

elif MODEL_NAME == "vgg16":
    ## LOAD: resnet pretrained model
    model = models.vgg16(pretrained=True)
    model.eval()

    ## 取得するlayerの一覧
    from_layers = {
        "0": 4096,
        "3": 4096,
        "6": 1000,
    }

    ## コピー用の関数とコピー先の変数
    def copy_data(m, i, o):
        copy_dest_embedding[m.lname].copy_(o.data[0, :])

    ## 各レイヤーにコピー関数をfookする
    layers = []
    handles = []
    for name, size in from_layers.items():
        l = model.classifier[int(name)]

        ## copy先を指定するため、attrを追加
        setattr(l, "lname", name)

        ## copy関数を登録
        handles += [l.register_forward_hook(copy_data)]

        ## 出力先を用意
        vectors[name] = []
        copy_dest_embedding[name] = torch.zeros(size)

    ## ベクトル取得用の関数
    ## copy_dest_embeddingに結果を格納
    def get_vector(img):
        ## Create a PyTorch Variable with the transformed image
        t_img = transform(img)
        t_img = torch.unsqueeze(t_img, 0)

        ## move the input to GPU for speed if available
        if torch.cuda.is_available():
            t_img = t_img.to(device)

        ## Run the model on our transformed image
        model(t_img)

        return

# move the model to GPU for speed if available
if torch.cuda.is_available():
    model.to(device)

"""
Prepare images
"""

## 画像ファイルの一覧を取得
image_dir = image_dir + CATEGORY + "/"
path, dirs, files = next(os.walk(image_dir))

## 分割数が指定されている場合は、fileを分割
if DIVIDE_FLG:
    files.sort()
    L = len(files)
    nums = [(L + i) // DIVIDE for i in range(DIVIDE)]

    start = 0
    for i in range(DIVIDE):
        if i == DIVIDE_INDEX:
            files = files[start : start + nums[i]]
            break

        start += nums[i]

"""
Calculate vectors
"""

## ベクトルを計算
cnt = 0
for filename in tqdm(files):
    i = filename.split("_")[0][1:]

    try:
        img = Image.open(image_dir + filename)
        img = img.convert("RGB")
    except:
        print(filename)
        continue

    get_vector(img)

    for l_name, size in from_layers.items():
        t = torch.zeros(size)
        t.copy_(copy_dest_embedding[l_name]).to("cpu")

        vectors[l_name] += [(i, filename, t)]

    cnt += 1
    if cnt % 1000 == 0:
        now = datetime.datetime.now()
        print("cnt: ", cnt, now)

## remove handles
for h in handles:
    h.remove()

"""
Save to objects
"""

## SAVE
for l_name in from_layers.keys():
    vector_file = ""

    if DIVIDE_FLG:
        vector_file = "vector_{}_{}_{}_{}_{}".format(
            MODEL_NAME, CATEGORY, l_name, DIVIDE, DIVIDE_INDEX
        )
    else:
        vector_file = "vector_{}_{}_{}".format(MODEL_NAME, CATEGORY, l_name)

    save_object(vectors[l_name], vector_file)

print_time_with_str()


#!/usr/bin/env python3
# https://abc089.contest.atcoder.jp/tasks/abc089_c
import itertools

n = int(input())
a = [0] * 26
for _ in range(n):
   a[ord(input()[0]) - ord('A')] += 1
c = []
for x in 'MARCH':
    c.append(a[ord(x) - ord('A')])
s = 0
for x in itertools.combinations(c, 3):
    k = 1
    for i in x: k *= i
    s += k
print(s)


"""
Compare regional feedbacks.

Be sure to adjust data_dir5 and data_dir6 and pl_path.
"""

#%% imports
import os
import sys
import glob
import copy
import time
import numpy as np
import pylab as pl
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.colors as colors
from matplotlib import gridspec
from mpl_toolkits.axes_grid1.axes_divider import make_axes_locatable
import cartopy
import cartopy.util as cu
import cartopy.crs as ccrs
import cartopy.feature as cfeature
from netCDF4 import Dataset
from matplotlib import cm
from scipy.stats import ttest_ind
from scipy.stats import linregress as lr
from scipy.stats import pearsonr as pears_corr
from scipy import interpolate
from scipy import signal
import progressbar as pg
import dask.array as da
import time as ti

#%% set scripts directory and import self-written functions
direc = "../"
os.chdir(direc)
# needed for console
sys.path.append(direc)

from Functions.Func_Region_Mean import region_mean
from Functions.Func_Extract_Geographic_Region import extract_region
from Functions.Func_RunMean import run_mean
from Functions.Func_APRP import simple_comp, a_cs, a_oc, a_oc2, plan_al
from Functions.Func_Convert_To_Europe_Centric import eu_centric
from Functions.Func_Lat_Mean import lat_mean
from Functions.Func_Glob_Mean import glob_mean
from Functions.Func_AnMean import an_mean
from Functions.Func_Climatology import climatology
from Functions.Func_SeasonalMean import sea_mean
from Functions.Func_Round import r2, r3, r4
from Functions.Func_Regrid_Data_RectBiVSpline import remap
from Functions.Func_Regrid_Data import remap as remap2
from Functions.Func_Prep_Fb_Barplot import prep_fb_bars
from Functions.Func_Set_ColorLevels import set_levs_norm_colmap
from Classes.Class_MidpointNormalize import MidpointNormalize

#%% set model groups
# models1 = ["CanESM5", "CMCC-ESM2", "CNRM-CM6-1", "E3SM-1-0", "MPI-ESM1-2-LR", "UKESM1-0-LL"]
# models2 = ["NorESM1_M", "ACCESS-ESM1-5", "EC-Earth3", "FGOALS-g3", "INM-CM4-8"]
models1 = ["IPSL_CM5A_LR", "CanESM5", "CMCC-ESM2", "CNRM-CM6-1", "E3SM-1-0", "MPI-ESM1-2-LR", "UKESM1-0-LL"]
models2 = ["BCC_CSM1_1", "BCC_CSM1_1_M", "GFDL_CM3", "GISS_E2_H", "NorESM1_M", "BCC-CSM2-MR", "EC-Earth3", "FGOALS-g3",
           "INM-CM4-8"]

models = {"G1":models1, "G2":models2}
g_cols = {"G1":"blue", "G2":"red"}

#%% set the region
### --> Subpolar North Atlantic (SPNA) in Bellomo et al. (2021):  50-70N, 80W-10E

# 2: mid-latitude North Atlantic
x1 = [300]
x2 = [350]
y1 = [40]
y2 = [60]

x1 = [145]
x2 = [160]
y1 = [35]
y2 = [45]

x1 = [178]
x2 = [182]
y1 = [42]
y2 = [47]

# 6: excluding northern extra-tropics
x1, x2 = [0], [360]
y1, y2 = [-90], [30]

# 7: northern extra-tropics
# x1, x2 = [0], [360]
# y1, y2 = [30], [90]

# Bellomo et al. (2021)
# x1 = [280]
# x2 = [10]
# y1 = [50]
# y2 = [70]

# set the region name
reg_name = "6"
reg_name_title = {"1":"Barents-Norwegian-Greenland Sea", "2":"Mid-latitude North Atlantic",
                  "3":"Western Pacific", "4":"Central Mid-Latitude North Pacific", "5":"Eastern Japanese Coast",
                  "6":"Excl. Northern Extra-tropics", "7":"Northern Extra-tropics"}
reg_name_fn = {"1":"BNG_Sea", "2":"MLNA", "3":"NWP", "4":"CMLP", "5":"EJC", "6":"ExNExTr", "7":"NExTr"}

#%% set up some initial dictionaries and lists --> NEEDED FOR CSLT !!!

# kernels names for keys
# k_k = ["Sh08", "So08", "BM13", "H17", "P18"]
kl = "Sh08"
k_k = [kl]

# kernel names for plot titles etc.
k_n = {"Sh08":"Shell", "So08":"Soden", "BM13":"Block&Mauritsen", "H17":"Huang", "P18":"Pendergrass"}
k_p = {"Sh08":"Shell_etal_2008", "So08":"Soden_etal_2008", "BM13":"Block_Mauritsen_2013", "H17":"Huang_etal_2017",
       "P18":"Pendergrass_etal_2018"}

#%% choose the threshold year; if this is set to 0, the "year of maximum feedback change" will be taken from the below
#   dictionary
thr_yr = 20

thr_min = 15
thr_max = 75

#%% add a a plot name suffix for excluded models

all_mod = np.array(['ACCESS1.0', 'ACCESS1.3', 'BCC-CSM1.1', 'BCC-CSM1.1(m)', 'BNU-ESM', 'CanESM2', "CCSM4", 'CNRM-CM5',
                    "FGOALS-s2", 'GFDL-CM3', "GFDL-ESM2G", 'GFDL-ESM2M', 'GISS-E2-H', 'GISS-E2-R', 'HadGEM2-ES',
                    "INMCM4", 'IPSL-CM5A-LR', 'IPSL-CM5B-LR', 'MIROC5', "MIROC-ESM", 'MPI-ESM-LR', 'MPI-ESM-MR',
                    'MPI-ESM-P', 'MRI-CGCM3', 'NorESM1-M',
                    'ACCESS-CM2', 'ACCESS-ESM1.5', 'AWI-CM-1.1-MR', 'BCC-CSM2-MR', 'BCC-ESM1', 'CAMS-CSM1.0',
                    'CanESM5', "CAS-ESM2.0", "CESM2", "CESM2-FV2", "CESM2-WACCM", "CESM2-WACCM-FV2", "CIESM",
                    'CMCC-CM2-SR5', "CMCC-ESM2", 'CNRM-CM6.1', "CNRM-CM6.1-HR", 'CNRM-ESM2.1', 'E3SM-1.0', 'EC-Earth3',
                    "EC-Earth3-AerChem", 'EC-Earth3-Veg', 'FGOALS-f3-L', 'FGOALS-g3', "FIO-ESM2.0", 'GFDL-CM4',
                    'GFDL-ESM4', 'GISS-E2.1-G', 'GISS-E2.1-H', 'GISS-E2.2-G', 'HadGEM3-GC31-LL', 'HadGEM3-GC31-MM',
                    "IITM-ESM",  'INM-CM4.8', 'INM-CM5', 'IPSL-CM6A-LR', "KACE-1.0-G", "KIOST-ESM", 'MIROC-ES2L',
                    'MIROC6', 'MPI-ESM1.2-HAM', 'MPI-ESM1.2-HR', 'MPI-ESM1.2-LR', 'MRI-ESM2.0', "NESM3", 'NorCPM1',
                    "NorESM2-LM", "NorESM2-MM", 'SAM0-UNICON', 'TaiESM1', 'UKESM1.0-LL'])

#%% load model lists to check if a particular model is a member of CMIP5 or 6
import Namelists.Namelist_CMIP5 as nl5
import Namelists.Namelist_CMIP6 as nl6
import Namelists.CMIP_Dictionaries as cmip_dic
data_dir5 = ""  # SETS BASIC DATA DIRECTORY
data_dir6 = ""  # SETS BASIC DATA DIRECTORY

a4x5 = "abrupt4xCO2"
a4x6 = "abrupt-4xCO2"

cmip5_list = nl5.models
cmip6_list = nl6.models

pl_path = "/MultModPlots/G1_G2_Regional_Comparison_piC_a4x/"

# generate the plot path
os.makedirs(pl_path + "/PDF/", exist_ok=True)
os.makedirs(pl_path + "/PNG/", exist_ok=True)

#%% loop over the groups and collect their data to compare later

# set up dictionaries to collect the data
mods_d = dict()

pl_add = ""
tl_add = ""

lr_fb_e_d = dict()
lr_fb_l_d = dict()
lr_fb_d_d = dict()
c_fb_e_d = dict()
c_fb_l_d = dict()
c_fb_d_d = dict()
c_lw_fb_e_d = dict()
c_lw_fb_l_d = dict()
c_lw_fb_d_d = dict()
c_sw_fb_e_d = dict()
c_sw_fb_l_d = dict()
c_sw_fb_d_d = dict()

for g12, group in zip(["G1", "G2"], [models1, models2]):

    mods = []
    mod_count = 0

    # set up arrays to store all the feedback values --> we need this to easily calculate the multi-model mean
    lr_fb_e_l = []
    lr_fb_l_l = []
    lr_fb_d_l = []
    c_fb_e_l = []
    c_fb_l_l = []
    c_fb_d_l = []
    c_lw_fb_e_l = []
    c_lw_fb_l_l = []
    c_lw_fb_d_l = []
    c_sw_fb_e_l = []
    c_sw_fb_l_l = []
    c_sw_fb_d_l = []

    for i, mod_d in enumerate(group):
        if mod_d in cmip5_list:
            data_dir = data_dir5
            cmip = "5"
            mod = cmip_dic.mod_dict[cmip][mod_d]
            mod_pl = nl5.models_pl[mod]
            mod_n = nl5.models_n[mod]
            mod_dir = nl5.models[mod]
            b_time = nl5.b_times[mod_d]
            a4x = "abrupt4xCO2"
            si_varn = "sic"
        elif mod_d in cmip6_list:
            data_dir = data_dir6
            cmip = "6"
            mod = cmip_dic.mod_dict[cmip][mod_d]
            mod_pl = nl6.models_pl[mod]
            mod_n = nl6.models_n[mod]
            mod_dir = nl6.models[mod]
            b_time = nl6.b_times[mod_d]
            a4x = "abrupt-4xCO2"
            si_varn = "siconc"
        # end if

        # set start and end index for the piControl experiment depending on the branch year
        bst = b_time * 12
        ben = bst + 150*12

        # load nc files
        fb_nc = Dataset(glob.glob(data_dir + f"Outputs/Feedbacks_Local/Kernel/{a4x}/{k_p[kl]}/tas_Based/*{mod_d}.nc")[0])

        #% get lat and lon
        lat = fb_nc.variables["lat"][:]
        lon = fb_nc.variables["lon"][:]
        olat = lat + 90
        olon = lon + 0

        # extract region
        lr_fb_e = region_mean(fb_nc.variables["LR_fb_e"][0, :, :], x1, x2, y1, y2, lat, lon, test_plt=False,
                              plot_title="LR")
        lr_fb_l = region_mean(fb_nc.variables["LR_fb_l"][0, :, :], x1, x2, y1, y2, lat, lon, test_plt=False,
                              plot_title="LR")
        lr_fb_d = region_mean(fb_nc.variables["LR_dfb"][:, :], x1, x2, y1, y2, lat, lon, test_plt=False,
                              plot_title="LR")
        c_fb_e = region_mean(fb_nc.variables["C_fb_e"][0, :, :], x1, x2, y1, y2, lat, lon, test_plt=False,
                             plot_title="C")
        c_fb_l = region_mean(fb_nc.variables["C_fb_l"][0, :, :], x1, x2, y1, y2, lat, lon, test_plt=False,
                             plot_title="C")
        c_fb_d = region_mean(fb_nc.variables["C_dfb"][:, :], x1, x2, y1, y2, lat, lon, test_plt=False,
                             plot_title="C")
        clw_fb_e = region_mean(fb_nc.variables["C_lw_fb_e"][0, :, :], x1, x2, y1, y2, lat, lon, test_plt=False,
                               plot_title="C")
        clw_fb_l = region_mean(fb_nc.variables["C_lw_fb_l"][0, :, :], x1, x2, y1, y2, lat, lon, test_plt=False,
                               plot_title="C")
        clw_fb_d = region_mean(fb_nc.variables["C_lw_dfb"][:, :], x1, x2, y1, y2, lat, lon, test_plt=False,
                               plot_title="C")
        csw_fb_e = region_mean(fb_nc.variables["C_sw_fb_e"][0, :, :], x1, x2, y1, y2, lat, lon, test_plt=False,
                               plot_title="C")
        csw_fb_l = region_mean(fb_nc.variables["C_sw_fb_l"][0, :, :], x1, x2, y1, y2, lat, lon, test_plt=False,
                               plot_title="C")
        csw_fb_d = region_mean(fb_nc.variables["C_sw_dfb"][:, :], x1, x2, y1, y2, lat, lon, test_plt=False,
                               plot_title="C")

        lr_fb_e_l.append(lr_fb_e)
        lr_fb_l_l.append(lr_fb_l)
        lr_fb_d_l.append(lr_fb_d)
        c_fb_e_l.append(c_fb_e)
        c_fb_l_l.append(c_fb_l)
        c_fb_d_l.append(c_fb_d)
        c_lw_fb_e_l.append(clw_fb_e)
        c_lw_fb_l_l.append(clw_fb_l)
        c_lw_fb_d_l.append(clw_fb_d)
        c_sw_fb_e_l.append(csw_fb_e)
        c_sw_fb_l_l.append(csw_fb_l)
        c_sw_fb_d_l.append(csw_fb_d)

        print(g12 + " " + str(i) + ": " + mod_pl)

        mods.append(mod_pl)

        mod_count += 1
    # end for i, mod_d

    print("\n")

    # print(f"{g12} shape: {np.shape(cre_lw_pic)}")

    print("\n\n")
    # store everything in dictionaries
    lr_fb_e_d[g12] = np.array(lr_fb_e_l)
    lr_fb_l_d[g12] = np.array(lr_fb_l_l)
    lr_fb_d_d[g12] = np.array(lr_fb_d_l)
    c_fb_e_d[g12] = np.array(c_fb_e_l)
    c_fb_l_d[g12] = np.array(c_fb_l_l)
    c_fb_d_d[g12] = np.array(c_fb_d_l)
    c_lw_fb_e_d[g12] = np.array(c_lw_fb_e_l)
    c_lw_fb_l_d[g12] = np.array(c_lw_fb_l_l)
    c_lw_fb_d_d[g12] = np.array(c_lw_fb_d_l)
    c_sw_fb_e_d[g12] = np.array(c_sw_fb_e_l)
    c_sw_fb_l_d[g12] = np.array(c_sw_fb_l_l)
    c_sw_fb_d_d[g12] = np.array(c_sw_fb_d_l)

    mods_d[g12] = np.array(mods)

# end for g12

#%% t-test
lr_e_ttest = ttest_ind(lr_fb_e_d["G1"], lr_fb_e_d["G2"], axis=0)
lr_l_ttest = ttest_ind(lr_fb_l_d["G1"], lr_fb_l_d["G2"], axis=0)
lr_d_ttest = ttest_ind(lr_fb_d_d["G1"], lr_fb_d_d["G2"], axis=0)
c_e_ttest = ttest_ind(c_fb_e_d["G1"], c_fb_e_d["G2"], axis=0)
c_l_ttest = ttest_ind(c_fb_l_d["G1"], c_fb_l_d["G2"], axis=0)
c_d_ttest = ttest_ind(c_fb_d_d["G1"], c_fb_d_d["G2"], axis=0)
c_lw_e_ttest = ttest_ind(c_lw_fb_e_d["G1"], c_lw_fb_e_d["G2"], axis=0)
c_lw_l_ttest = ttest_ind(c_lw_fb_l_d["G1"], c_lw_fb_l_d["G2"], axis=0)
c_lw_d_ttest = ttest_ind(c_lw_fb_d_d["G1"], c_lw_fb_d_d["G2"], axis=0)
c_sw_e_ttest = ttest_ind(c_sw_fb_e_d["G1"], c_sw_fb_e_d["G2"], axis=0)
c_sw_l_ttest = ttest_ind(c_sw_fb_l_d["G1"], c_sw_fb_l_d["G2"], axis=0)
c_sw_d_ttest = ttest_ind(c_sw_fb_d_d["G1"], c_sw_fb_d_d["G2"], axis=0)

#%% print values
print(f"G1 LR early: {r2(np.mean(lr_fb_e_d['G1']))} +/- {r2(np.std(lr_fb_e_d['G1']))}")
print(f"G1 LR late: {r2(np.mean(lr_fb_l_d['G1']))} +/- {r2(np.std(lr_fb_l_d['G1']))}")
print(f"G1 LR change: {r2(np.mean(lr_fb_d_d['G1']))} +/- {r2(np.std(lr_fb_d_d['G1']))}")
print(f"G1 C early: {r2(np.mean(c_fb_e_d['G1']))} +/- {r2(np.std(c_fb_e_d['G1']))}")
print(f"G1 C late: {r2(np.mean(c_fb_l_d['G1']))} +/- {r2(np.std(c_fb_l_d['G1']))}")
print(f"G1 C change: {r2(np.mean(c_fb_d_d['G1']))} +/- {r2(np.std(c_fb_d_d['G1']))}\n")

print(f"G2 LR early: {r2(np.mean(lr_fb_e_d['G2']))} +/- {r2(np.std(lr_fb_e_d['G2']))}")
print(f"G2 LR late: {r2(np.mean(lr_fb_l_d['G2']))} +/- {r2(np.std(lr_fb_l_d['G2']))}")
print(f"G2 LR change: {r2(np.mean(lr_fb_d_d['G2']))} +/- {r2(np.std(lr_fb_d_d['G2']))}")
print(f"G2 C early: {r2(np.mean(c_fb_e_d['G2']))} +/- {r2(np.std(c_fb_e_d['G2']))}")
print(f"G2 C late: {r2(np.mean(c_fb_l_d['G2']))} +/- {r2(np.std(c_fb_l_d['G2']))}")
print(f"G2 C change: {r2(np.mean(c_fb_d_d['G2']))} +/- {r2(np.std(c_fb_d_d['G2']))}")

#%% plot group means
fig, axes = pl.subplots(ncols=2, nrows=1, figsize=(10, 6), sharey=True)

ax00 = axes[0].twinx()
ax01 = axes[1].twinx()

axes[0].errorbar(0, np.mean(lr_fb_e_d["G1"]), yerr=np.std(lr_fb_e_d["G1"]), c="blue", label="G1", fmt="o", zorder=101,
                linewidth=1, capsize=3.5, markersize=8)
axes[0].errorbar(0, np.mean(lr_fb_e_d["G2"]), yerr=np.std(lr_fb_e_d["G2"]), c="red", label="G2", fmt="o", zorder=101,
                linewidth=1, capsize=3.5, markersize=8)
axes[0].errorbar(1, np.mean(lr_fb_l_d["G1"]), yerr=np.std(lr_fb_l_d["G1"]), c="blue", fmt="o", zorder=101,
                linewidth=1, capsize=3.5, markersize=8)
axes[0].errorbar(1, np.mean(lr_fb_l_d["G2"]), yerr=np.std(lr_fb_l_d["G2"]), c="red", fmt="o", zorder=101,
                linewidth=1, capsize=3.5, markersize=8)
axes[0].errorbar(2, np.mean(lr_fb_d_d["G1"]), yerr=np.std(lr_fb_l_d["G1"]), c="blue", fmt="o", zorder=101,
                linewidth=1, capsize=3.5, markersize=8)
axes[0].errorbar(2, np.mean(lr_fb_d_d["G2"]), yerr=np.std(lr_fb_l_d["G2"]), c="red", fmt="o", zorder=101,
                linewidth=1, capsize=3.5, markersize=8)

ax00.scatter(0, lr_e_ttest.pvalue, c="gray")
ax00.scatter(1, lr_l_ttest.pvalue, c="gray")
ax00.scatter(2, lr_d_ttest.pvalue, c="gray")
ax00.set_ylim((0, 0.1))
ax00.set_yticks([0, 0.025, 0.05, 0.075, 0.1])

axes[0].set_ylim(-3.5, 3.5)

axes[0].axhline(y=0, c="gray", linewidth=1.5, zorder=102)

axes[0].legend(loc="upper left")

axes[0].set_xticks([0, 1, 2])
axes[0].set_xticklabels(["early", "late", "change"])

axes[0].set_ylabel("Feedback in Wm$^{-1}$K$^{-2}$")
axes[0].set_title("Lapse-rate feedback")

axes[1].errorbar(0, np.mean(c_fb_e_d["G1"]), yerr=np.std(lr_fb_e_d["G1"]), c="blue", fmt="o", zorder=101,
                linewidth=1, capsize=3.5, markersize=8)
axes[1].errorbar(0, np.mean(c_fb_e_d["G2"]), yerr=np.std(lr_fb_e_d["G2"]), c="red", fmt="o", zorder=101,
                linewidth=1, capsize=3.5, markersize=8)
axes[1].errorbar(1, np.mean(c_fb_l_d["G1"]), yerr=np.std(lr_fb_l_d["G1"]), c="blue", fmt="o", zorder=101,
                linewidth=1, capsize=3.5, markersize=8)
axes[1].errorbar(1, np.mean(c_fb_l_d["G2"]), yerr=np.std(lr_fb_l_d["G2"]), c="red", fmt="o", zorder=101,
                linewidth=1, capsize=3.5, markersize=8)
axes[1].errorbar(2, np.mean(c_fb_d_d["G1"]), yerr=np.std(lr_fb_l_d["G1"]), c="blue", fmt="o", zorder=101,
                linewidth=1, capsize=3.5, markersize=8)
axes[1].errorbar(2, np.mean(c_fb_d_d["G2"]), yerr=np.std(lr_fb_l_d["G2"]), c="red", fmt="o", zorder=101,
                linewidth=1, capsize=3.5, markersize=8)

ax01.scatter(0, c_e_ttest.pvalue, c="gray")
ax01.scatter(1, c_l_ttest.pvalue, c="gray")
ax01.scatter(2, c_d_ttest.pvalue, c="gray")
ax01.set_ylim((0, 0.1))
ax01.set_yticks([0, 0.025, 0.05, 0.075, 0.1])
# ax01.set_xticklabels(["early", "late", "change"])

axes[1].axhline(y=0, c="gray", linewidth=1.5, zorder=102)

axes[1].set_xticks([0, 1, 2])
axes[1].set_xticklabels(["early", "late", "change"])
axes[1].set_title("Cloud feedback")

fig.suptitle(f"{reg_name_title[reg_name]} " +
             f"({y1[0]}$-${y2[0]}$\degree$N, {x1[0]}$-${x2[0]}$\degree$E)")
fig.subplots_adjust(top=0.89, wspace=0.3)

pl.savefig(pl_path + f"/PDF/{reg_name_fn[reg_name]}_LR_C_Fb_G1_G2_Comp.pdf", bbox_inches="tight", dpi=250)
pl.savefig(pl_path + f"/PNG/{reg_name_fn[reg_name]}_LR_C_Fb_G1_G2_Comp.png", bbox_inches="tight", dpi=250)

pl.show()
pl.close()

#%% plot group means
fig, axes = pl.subplots(ncols=2, nrows=1, figsize=(10, 6), sharey=True)

ax00 = axes[0].twinx()
ax01 = axes[1].twinx()

axes[0].errorbar(0, np.mean(c_lw_fb_e_d["G1"]), yerr=np.std(c_lw_fb_e_d["G1"]), c="blue", label="G1", fmt="o",
                 zorder=101, linewidth=1, capsize=3.5, markersize=8)
axes[0].errorbar(0, np.mean(c_lw_fb_e_d["G2"]), yerr=np.std(c_lw_fb_e_d["G2"]), c="red", label="G2", fmt="o",
                 zorder=101, linewidth=1, capsize=3.5, markersize=8)
axes[0].errorbar(1, np.mean(c_lw_fb_l_d["G1"]), yerr=np.std(c_lw_fb_l_d["G1"]), c="blue", fmt="o", zorder=101,
                linewidth=1, capsize=3.5, markersize=8)
axes[0].errorbar(1, np.mean(c_lw_fb_l_d["G2"]), yerr=np.std(c_lw_fb_l_d["G2"]), c="red", fmt="o", zorder=101,
                linewidth=1, capsize=3.5, markersize=8)
axes[0].errorbar(2, np.mean(c_lw_fb_d_d["G1"]), yerr=np.std(c_lw_fb_l_d["G1"]), c="blue", fmt="o", zorder=101,
                linewidth=1, capsize=3.5, markersize=8)
axes[0].errorbar(2, np.mean(c_lw_fb_d_d["G2"]), yerr=np.std(c_lw_fb_l_d["G2"]), c="red", fmt="o", zorder=101,
                linewidth=1, capsize=3.5, markersize=8)

ax00.scatter(0, c_lw_e_ttest.pvalue, c="gray")
ax00.scatter(1, c_lw_l_ttest.pvalue, c="gray")
ax00.scatter(2, c_lw_d_ttest.pvalue, c="gray")
ax00.set_ylim((0, 0.1))
ax00.set_yticks([0, 0.025, 0.05, 0.075, 0.1])

axes[0].set_ylim(-3.5, 3.5)

axes[0].axhline(y=0, c="gray", linewidth=1.5, zorder=102)

axes[0].legend(loc="upper left")

axes[0].set_xticks([0, 1, 2])
axes[0].set_xticklabels(["early", "late", "change"])

axes[0].set_ylabel("Feedback in Wm$^{-1}$K$^{-2}$")
axes[0].set_title("Long-wave cloud feedback")

axes[1].errorbar(0, np.mean(c_sw_fb_e_d["G1"]), yerr=np.std(c_sw_fb_e_d["G1"]), c="blue", fmt="o", zorder=101,
                linewidth=1, capsize=3.5, markersize=8)
axes[1].errorbar(0, np.mean(c_sw_fb_e_d["G2"]), yerr=np.std(c_sw_fb_e_d["G2"]), c="red", fmt="o", zorder=101,
                linewidth=1, capsize=3.5, markersize=8)
axes[1].errorbar(1, np.mean(c_sw_fb_l_d["G1"]), yerr=np.std(c_sw_fb_l_d["G1"]), c="blue", fmt="o", zorder=101,
                linewidth=1, capsize=3.5, markersize=8)
axes[1].errorbar(1, np.mean(c_sw_fb_l_d["G2"]), yerr=np.std(c_sw_fb_l_d["G2"]), c="red", fmt="o", zorder=101,
                linewidth=1, capsize=3.5, markersize=8)
axes[1].errorbar(2, np.mean(c_sw_fb_d_d["G1"]), yerr=np.std(c_sw_fb_l_d["G1"]), c="blue", fmt="o", zorder=101,
                linewidth=1, capsize=3.5, markersize=8)
axes[1].errorbar(2, np.mean(c_sw_fb_d_d["G2"]), yerr=np.std(c_sw_fb_l_d["G2"]), c="red", fmt="o", zorder=101,
                linewidth=1, capsize=3.5, markersize=8)

ax01.scatter(0, c_sw_e_ttest.pvalue, c="gray")
ax01.scatter(1, c_sw_l_ttest.pvalue, c="gray")
ax01.scatter(2, c_sw_d_ttest.pvalue, c="gray")
ax01.set_ylim((0, 0.1))
ax01.set_yticks([0, 0.025, 0.05, 0.075, 0.1])
# ax01.set_xticklabels(["early", "late", "change"])

axes[1].axhline(y=0, c="gray", linewidth=1.5, zorder=102)

axes[1].set_xticks([0, 1, 2])
axes[1].set_xticklabels(["early", "late", "change"])
axes[1].set_title("Short-wave cloud feedback")

fig.suptitle(f"{reg_name_title[reg_name]} " +
             f"({y1[0]}$-${y2[0]}$\degree$N, {x1[0]}$-${x2[0]}$\degree$E)")
fig.subplots_adjust(top=0.89, wspace=0.3)

pl.savefig(pl_path + f"/PDF/{reg_name_fn[reg_name]}_LW_SW_C_Fb_G1_G2_Comp.pdf", bbox_inches="tight", dpi=250)
pl.savefig(pl_path + f"/PNG/{reg_name_fn[reg_name]}_LW_SW_C_Fb_G1_G2_Comp.png", bbox_inches="tight", dpi=250)

pl.show()
pl.close()


first_result = input()
second_result = input()
third_result = input()
won = 0
lost = 0
drawn = 0

if int(first_result[0]) > int(first_result[2]):
    won += 1
elif int(first_result[0]) < int(first_result[2]):
    lost += 1
else:
    drawn += 1

if int(second_result[0]) > int(second_result[2]):
    won += 1
elif int(second_result[0]) < int(second_result[2]):
    lost += 1
else:
    drawn += 1

if int(third_result[0]) > int(third_result[2]):
    won += 1
elif int(third_result[0]) < int(third_result[2]):
    lost += 1
else:
    drawn += 1

print(f"Team won {won} games.")
print(f"Team lost {lost} games.")
print(f"Drawn games: {drawn}")


import sys
sys.path.append("..")

import torch
from torch.autograd import Variable
from torch.utils.data import Dataset
import torchvision

import utils.utils as mutils

import os
from multiprocessing import Pool

import random
import torch
from torch.utils.data import Dataset
from torch.utils.data import sampler
import torchvision.transforms as transforms
import six
import sys
from PIL import Image
import numpy as np
import collections

class resizeNormalize(object):

    def __init__(self, size, interpolation=Image.BILINEAR):
        self.size = size
        self.interpolation = interpolation
        self.toTensor = transforms.ToTensor()
        self.transform = transforms.Compose([
            #transforms.ToPILImage(),
            #transforms.RandomHorizontalFlip(),
            #transforms.RandomVerticalFlip(),
            #transforms.RandomRotation(30),
            #transforms.RandomAffine(30),
            transforms.ToTensor(),

        ])

    def __call__(self, img):
        #img = img.resize(self.size, self.interpolation)
        #img = self.toTensor(img)
        img = self.transform(img)
        img.sub_(0.5).div_(0.5)
        return img

class XYDataset(Dataset):
    def __init__(self, X, Y, transform=None, target_transform=None):
        self.X = X
        self.Y = Y

        self.n_sample = len(X)
        self.transform = transform
        self.target_transform = target_transform

    def __len__(self):
        return len(self.X)

    def __getitem__(self, index):
        assert index < len(self), 'index range error'

        img = self.X[index]
        if self.transform is not None:
            img = self.transform(img)

        label = self.Y[index]
        if self.target_transform is not None:
            label = self.target_transform(label)

        return (img, label, index)

class alignCollate(object):

    def __init__(self, imgH=32, imgW=100, keep_ratio=False, min_ratio=1):
        self.imgH = imgH
        self.imgW = imgW
        self.keep_ratio = keep_ratio
        self.min_ratio = min_ratio

    def __call__(self, batch):
        images, labels, img_keys = zip(*batch)

        imgH = self.imgH
        imgW = self.imgW
        if self.keep_ratio:
            ratios = []
            for image in images:
                w, h = image.shape[:2]
                ratios.append(w / float(h))
            ratios.sort()
            max_ratio = ratios[-1]
            imgW = int(np.floor(max_ratio * imgH))
            imgW = max(imgH * self.min_ratio, imgW)  # assure imgH >= imgW

        transform = resizeNormalize((imgW, imgH))
        images = [transform(image) for image in images]
        images = torch.cat([t.unsqueeze(0) for t in images], 0)
        labels = torch.LongTensor(labels)

        return images, labels, img_keys

class FakeRecorder():
    def __init__(self):
        pass

    def print(self, *x):
        pass

from torch.nn import init
from torch import nn
def weigth_init(m):
    if isinstance(m, nn.Conv2d):
        init.xavier_uniform_(m.weight.data)
        init.constant_(m.bias.data,0.1)
    elif isinstance(m, nn.BatchNorm2d):
        m.weight.data.fill_(1)
        m.bias.data.zero_()
    elif isinstance(m, nn.Linear):
        m.weight.data.normal_(0,0.01)
        m.bias.data.zero_()

class BasicModel():
    def __init__(self,
            model,
            criterion,
            optimizer,
            converter,
            device,
            params,
            sign_list,
            recorder = None):

        self.model = model.to(device)
        self.model.apply(weigth_init)
        self.criterion = criterion
        self.optimizer = optimizer
        self.converter = converter
        self.device = device
        sign_list = sorted(list(set(sign_list)))
        self.mapping = dict(zip(sign_list, list(range(len(sign_list)))))
        self.remapping = dict(zip(list(range(len(sign_list))), sign_list))

        if recorder is None:
            recorder = FakeRecorder()
        self.recorder = recorder

        self.save_interval = params.saveInterval
        self.params = params
        pass

    def _fit(self, data_loader, n_epoch, stop_loss):
        recorder = self.recorder
        recorder.print("model fitting")

        min_loss = 999999999
        for epoch in range(n_epoch):
            loss_value = self.train_epoch(data_loader)
            recorder.print(f"{epoch}/{n_epoch} model training loss is {loss_value}")
            if loss_value < min_loss:
                min_loss = loss_value
            if loss_value < stop_loss:
                break
        recorder.print("Model fitted, minimal loss is ", min_loss)
        return loss_value

    def str2ints(self, Y):
        return [self.mapping[y] for y in Y]

    def fit(self, data_loader = None,
                  X = None,
                  y = None,
                  n_epoch = 100,
                  stop_loss = 0.001):
        if data_loader is None:
            params = self.params
            Y = self.str2ints(y)
            train_dataset = XYDataset(X, Y)
            sampler = None
            data_loader = torch.utils.data.DataLoader(train_dataset, batch_size=params.batchSize, \
                    shuffle=True, sampler=sampler, num_workers=int(params.workers), \
                    collate_fn=alignCollate(imgH=params.imgH, imgW=params.imgW, keep_ratio=params.keep_ratio))
        return self._fit(data_loader, n_epoch, stop_loss)

    def train_epoch(self, data_loader):
        loss_avg = mutils.averager()

        for i, data in enumerate(data_loader):
            X = data[0]
            Y = data[1]
            cost = self.train_batch(X, Y)
            loss_avg.add(cost)

        loss_value = float(loss_avg.val())
        loss_avg.reset()
        return loss_value

    def train_batch(self, X, Y):
        #cpu_images, cpu_texts, _ = data
        model = self.model
        criterion = self.criterion
        optimizer = self.optimizer
        converter = self.converter
        device = self.device

        # set training mode
        for p in model.parameters():
            p.requires_grad = True
        model.train()

        # init training status
        torch.autograd.set_detect_anomaly(True)
        optimizer.zero_grad()

        # model predict
        X = X.to(device)
        Y = Y.to(device)
        pred_Y = model(X)

        # calculate loss
        loss = criterion(pred_Y, Y)

        # back propagation and optimize
        loss.backward()
        optimizer.step()
        return loss

    def _predict(self, data_loader):
        model = self.model
        criterion = self.criterion
        converter = self.converter
        params = self.params
        device = self.device

        for p in model.parameters():
            p.requires_grad = False

        model.eval()

        n_correct = 0

        results = []
        for i, data in enumerate(data_loader):
            X = data[0].to(device)
            pred_Y = model(X)
            results.append(pred_Y)

        return torch.cat(results, axis=0)

    def predict(self, data_loader = None, X = None, print_prefix = ""):
        params = self.params
        if data_loader is None:
            Y = [0] * len(X)
            val_dataset = XYDataset(X, Y)
            sampler = None
            data_loader = torch.utils.data.DataLoader(val_dataset, batch_size=params.batchSize, \
                shuffle=False, sampler=sampler, num_workers=int(params.workers), \
                collate_fn=alignCollate(imgH=params.imgH, imgW=params.imgW, keep_ratio=params.keep_ratio))

        recorder = self.recorder
        recorder.print('Start Predict ', print_prefix)
        Y = self._predict(data_loader).argmax(axis=1)
        return [self.remapping[int(y)] for y in Y]

    def predict_proba(self, data_loader = None, X = None, print_prefix = ""):
        params = self.params
        if data_loader is None:
            Y = [0] * len(X)
            val_dataset = XYDataset(X, Y)
            sampler = None
            data_loader = torch.utils.data.DataLoader(val_dataset, batch_size=params.batchSize, \
                shuffle=False, sampler=sampler, num_workers=int(params.workers), \
                collate_fn=alignCollate(imgH=params.imgH, imgW=params.imgW, keep_ratio=params.keep_ratio))

        recorder = self.recorder
        recorder.print('Start Predict ', print_prefix)
        return torch.softmax(self._predict(data_loader), axis=1)

    def _val(self, data_loader, print_prefix):
        model = self.model
        criterion = self.criterion
        recorder = self.recorder
        converter = self.converter
        params = self.params
        device = self.device
        recorder.print('Start val ', print_prefix)

        for p in model.parameters():
            p.requires_grad = False

        model.eval()

        n_correct = 0
        pred_num = 0
        loss_avg = mutils.averager()
        for i, data in enumerate(data_loader):
            X = data[0].to(device)
            Y = data[1].to(device)

            pred_Y = model(X)

            correct_num = sum(Y == pred_Y.argmax(axis=1))
            loss = criterion(pred_Y, Y)
            loss_avg.add(loss)

            n_correct += correct_num
            pred_num += len(X)

        accuracy = float(n_correct) / float(pred_num)
        recorder.print('[%s] Val loss: %f, accuray: %f' % (print_prefix, loss_avg.val(), accuracy))
        return accuracy

    def val(self, data_loader = None, X = None, y = None, print_prefix = ""):
        params = self.params
        if data_loader is None:
            y = self.str2ints(y)
            val_dataset = XYDataset(X, y)
            sampler = None
            data_loader = torch.utils.data.DataLoader(val_dataset, batch_size=params.batchSize, \
                shuffle=True, sampler=sampler, num_workers=int(params.workers), \
                collate_fn=alignCollate(imgH=params.imgH, imgW=params.imgW, keep_ratio=params.keep_ratio))
        return self._val(data_loader, print_prefix)

    def score(self, data_loader = None, X = None, y = None, print_prefix = ""):
        return self.val(data_loader, X, y, print_prefix)

    def save(self, save_dir):
        recorder = self.recorder
        if not os.path.exists(save_dir):
            os.mkdir(save_dir)
        recorder.print("Saving model and opter")
        save_path = os.path.join(save_dir, "net.pth")
        torch.save(self.model.state_dict(), save_path)

        save_path = os.path.join(save_dir, "opt.pth")
        torch.save(self.optimizer.state_dict(), save_path)

    def load(self, load_dir):
        recorder = self.recorder
        recorder.print("Loading model and opter")
        load_path = os.path.join(load_dir, "net.pth")
        self.model.load_state_dict(torch.load(load_path))

        load_path = os.path.join(load_dir, "opt.pth")
        self.optimizer.load_state_dict(torch.load(load_path))

if __name__ == "__main__":
    pass


import sys
input = sys.stdin.readline

def is_black(x, y):
    # (0, 0)부터 Black
    return True if (x + y) % 2 == 0 else False

def set_bishop(x, y, eps):
    for i in range(n):
        if 0 <= x - i < n and 0 <= y - i < n:
            check_board[x - i][y - i] += eps
        if 0 <= x - i < n and 0 <= y + i < n:
            check_board[x - i][y + i] += eps
        if 0 <= x + i < n and 0 <= y - i < n:
            check_board[x + i][y - i] += eps
        if 0 <= x + i < n and 0 <= y + i < n:
            check_board[x + i][y + i] += eps

def backtracking(idx, cnt):
    global answer
    if idx >= len(bishop):
        answer = max(answer, cnt)
        return

    x, y = bishop[idx]
    if not check_board[x][y]:
        set_bishop(x, y, 1)
        backtracking(idx + 1, cnt + 1)
        set_bishop(x, y, -1)
        backtracking(idx + 1, cnt)
    else: backtracking(idx + 1, cnt)

n = int(input())
board = []
black, white = [], []
for i in range(n):
    tmp = list(map(int, input().split()))
    for j in range(n):
        if tmp[j]:
            if is_black(i, j): black.append((i, j))
            else: white.append((i, j))
    board.append(tmp)
check_board = [[0] * n for _ in range(n)]

answer, total = 0, 0
bishop = black
backtracking(0, 0)
total += answer

answer = 0
bishop = white
backtracking(0, 0)
total += answer

print(total)


from X3Dpackage import *
X3D0 = X3D()
X3D0.setProfile("Immersive")
X3D0.setVersion("3.3")
head1 = head()
meta2 = meta()
meta2.setName("creator")
meta2.setContent("John W Carlson")
head1.addMeta(meta2)
meta3 = meta()
meta3.setName("created")
meta3.setContent("December 13 2015")
head1.addMeta(meta3)
meta4 = meta()
meta4.setName("title")
meta4.setContent("force.x3d")
head1.addMeta(meta4)
meta5 = meta()
meta5.setName("identifier")
meta5.setContent("https://coderextreme.net/X3DJSONLD/force.x3d")
head1.addMeta(meta5)
meta6 = meta()
meta6.setName("description")
meta6.setContent("beginnings of a force directed graph in 3D")
head1.addMeta(meta6)
meta7 = meta()
meta7.setName("generator")
meta7.setContent("Vim, X3D-Edit, https://savage.nps.edu/X3D-Edit")
head1.addMeta(meta7)
X3D0.setHead(head1)
Scene8 = Scene()
Group9 = Group()
Shape10 = Shape()
Extrusion11 = Extrusion(spine = [-50,-50,0,50,50,0], creaseAngle = 0.785, crossSection = [1.00,0.00,0.92,-0.38,0.71,-0.71,0.38,-0.92,0.00,-1.00,-0.38,-0.92,-0.71,-0.71,-0.92,-0.38,-1.00,-0.00,-0.92,0.38,-0.71,0.71,-0.38,0.92,0.00,1.00,0.38,0.92,0.71,0.71,0.92,0.38,1.00,0.00])
Extrusion11.setDEF("extrusion")
Shape10.setGeometry(Extrusion11)
Appearance12 = Appearance()
Material13 = Material()
Material13.setDiffuseColor([0,1,0])
Appearance12.setMaterial(Material13)
Shape10.setAppearance(Appearance12)
Group9.addChildren(Shape10)
TimeSensor14 = TimeSensor()
TimeSensor14.setDEF("TourTime")
TimeSensor14.setLoop(True)
Group9.addChildren(TimeSensor14)
Script15 = Script()
Script15.setDEF("MoveCylinder")
field16 = field()
field16.setName("set_cycle")
field16.setAccessType("inputOnly")
field16.setType("SFTime")
Script15.addField(field16)
field17 = field()
field17.setName("spine")
field17.setAccessType("inputOutput")
field17.setType("MFVec3f")
field17.setValue("-50 -50 0 50 50 0")
Script15.addField(field17)

Script15.setSourceCode('''\n"+
"ecmascript:\n"+
"\n"+
"                function set_cycle(value) {\n"+
"                        Browser.print(value);\n"+
"                        var endA = new SFVec3f(spine[0].x*Math.random()*2, spine[0].y*Math.random()*2, spine[0].z*Math.random()*2);\n"+
"                        var endB = new SFVec3f(spine[1].x*Math.random()*2, spine[1].y*Math.random()*2, spine[1].z*Math.random()*2);\n"+
"		        spine = new MFVec3f([endA, endB]);\n"+
"                }\n"+
"''')
Group9.addChildren(Script15)
ROUTE18 = ROUTE()
ROUTE18.setFromNode("TourTime")
ROUTE18.setFromField("cycleTime")
ROUTE18.setToNode("MoveCylinder")
ROUTE18.setToField("set_cycle")
Group9.addChildren(ROUTE18)
ROUTE19 = ROUTE()
ROUTE19.setFromNode("MoveCylinder")
ROUTE19.setFromField("spine_changed")
ROUTE19.setToNode("extrusion")
ROUTE19.setToField("spine")
Group9.addChildren(ROUTE19)
Scene8.addChildren(Group9)
X3D0.setScene(Scene8)


from sys import exit

# def gold_room():
#     print("This room is full of gold. How much do you take?")

#     choice = input("> ")
#     if "0" in choice or "1" in choice: # what if input is 22? / GOES TO DEAD
#         how_much = int(choice)
#     else:
#         dead("Man, learn to type a number.")

#     if how_much < 50:
#         print("Nice, you're not too greedy, you win!")
#         exit(0)
#         # exits script without any return? will need to understand this in more detail, and implications / 0 is actually error message
#         # if 0, good exit, no error; other numbers would indicate specific types of errors (e.g., error(12) would be error of the type 12)
#     else:
#         dead("You greedy bastard!")

def bear_room():
    print("There's a bear here.")
    print("The bear has a bunch of honey.")
    print("The fat bear is in front of another door.")
    print("How are you going to move the bear?")
    bear_moved = False

    while True: # what does this mean? / CREATES AN INFINITE LOOP
        choice = input("> ")

        if choice == "take honey":
            dead("The bear looks at you and then slaps your face off.") # when I call another function, does WHILE stop? / SEEMS TO.
        elif choice == "taunt bear" and not bear_moved:
            # does ln above mean "and bear_moved is not true" (implied below lns 35 and 37)?
            print("The bear has moved from the door.")
            print("You can go through it now.")
            bear_moved = True
        elif choice == "taunt bear" and bear_moved: # i.e., if you taunt him once again, after you taunted him first and bear_moved became TRUE
            dead("The bear gets pissed off and chews your leg off.")
        elif choice == "open door" and bear_moved:
            gold_room()
        else:
            print("I got no idea what that means.")

def cthulhu_room():
    print("Here you see the great evil Cthulhu.")
    print("He, it, whatever stares at you and you go insane.")
    print("Do you flee for your life or eat your head?")

    choice = input("> ")

    if "flee" in choice: # does this mean "if string saved in choice contains the word "flee"?" / YES.
        start()
    elif "head" in choice:
        dead("Well that was tasty!")
    else:
        cthulhu_room()

def dead(why):
    print(why, "Good job!")
    exit(0)

def start():
    print("You are in dark room.")
    print("There is a door to your right and left.")
    print("Which one do you take?")

    choice = input("> ")

    if choice == "left":
        bear_room()
    elif choice == "right":
        cthulhu_room()
    else:
        dead("You stumble around the room until you starve.")

# STUDY DRILL 5: FIX THE WEIRD WAY IN WHICH GOLD_ROOM GETS USER TO TYPE A NUMBER
# note that functions do not have to be defined in the order that they will be called; HOWEVER, if I had put this revised GOLD_ROOM after START, things
# would have worked fine up until one of the other functions called it, in which case it would give an exception because not yet defined;
# what if I had both gold_room functions?
# PYLINT FLAGS THAT IT HAS ALREADY BEEN DEFINED, BUT IF I RUN THE SCRIPT I DON'T GET AN ERROR (AND IT USES THE SECOND ONE)

def gold_room():
    print("This room is full of gold. How much do you take?")

    choice = int(input("> "))

    if choice < 50:
        print("Nice, you're not too greedy, you win!")
        exit(0)
        # exits script without any return? will need to understand this in more detail, and implications / 0 is actually error message
        # if 0, good exit, no error; other numbers would indicate specific types of errors (e.g., error(12) would be error of the type 12)
    else:
        dead("You greedy bastard!")

start()


import math
import torch
from torch import nn
import torch.nn.functional as F

class Unet(nn.Module):
    def __init__(self):
        super(Unet, self).__init__()
        # block1~5 : Contracting Path

        self.block1 = nn.Sequential(
            nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, stride=1, padding=0, dilation=1),
            nn.ReLU(),

            nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, stride=1, padding=0, dilation=1),
            nn.ReLU(),
            # nn.MaxPool2d(kernel_size=2, stride=2)
        )

        self.block2 = nn.Sequential(
            nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, stride=1, padding=0, dilation=1),
            nn.ReLU(),

            nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, stride=1, padding=0, dilation=1),
            nn.ReLU(),

            # nn.MaxPool2d(kernel_size=2, stride=2)
        )

        self.block3 = nn.Sequential(
            nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, stride=1, padding=0, dilation=1),
            nn.ReLU(),

            nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding=0, dilation=1),
            nn.ReLU(),

            # nn.MaxPool2d(kernel_size=2, stride=2)
        )

        self.block4 = nn.Sequential(
            nn.Conv2d(in_channels=256, out_channels=512, kernel_size=3, stride=1, padding=0, dilation=1),
            nn.ReLU(),

            nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=0, dilation=1),
            nn.ReLU(),

            # nn.MaxPool2d(kernel_size=2, stride=2)
        )

        self.block5 = nn.Sequential(
            nn.Conv2d(in_channels=512, out_channels=1024, kernel_size=3, stride=1, padding=0, dilation=1),
            nn.ReLU(),

            nn.Conv2d(in_channels=1024, out_channels=1024, kernel_size=3, stride=1, padding=0, dilation=1),
            nn.ReLU(),

            nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True),
            nn.Conv2d(in_channels=1024, out_channels=512, kernel_size=3, stride=1, padding=1, dilation=1),
            nn.ReLU(),
            nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=1, dilation=1),
            nn.ReLU()
        )

        # block6~9 : Extracting Path

        self.block6 = nn.Sequential(
            nn.Conv2d(in_channels=1024, out_channels=512, kernel_size=3, stride=1, padding=0, dilation=1),
            nn.ReLU(),

            nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=0, dilation=1),
            nn.ReLU(),

            nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True),
            nn.Conv2d(in_channels=512, out_channels=256, kernel_size=3, stride=1, padding=1, dilation=1),
            nn.ReLU(),
            nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding=1, dilation=1),
            nn.ReLU()
        )

        self.block7 = nn.Sequential(
            nn.Conv2d(in_channels=512, out_channels=256, kernel_size=3, stride=1, padding=0, dilation=1),
            nn.ReLU(),

            nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding=0, dilation=1),
            nn.ReLU(),

            nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True),
            nn.Conv2d(in_channels=256, out_channels=128, kernel_size=3, stride=1, padding=1, dilation=1),
            nn.ReLU(),
            nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, stride=1, padding=1, dilation=1),
            nn.ReLU()
        )

        self.block8 = nn.Sequential(
            nn.Conv2d(in_channels=256, out_channels=128, kernel_size=3, stride=1, padding=0, dilation=1),
            nn.ReLU(),

            nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, stride=1, padding=0, dilation=1),
            nn.ReLU(),

            nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True),
            nn.Conv2d(in_channels=128, out_channels=64, kernel_size=3, stride=1, padding=1, dilation=1),
            nn.ReLU(),
            nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, stride=1, padding=1, dilation=1),
            nn.ReLU()
        )

        self.block9 = nn.Sequential(
            nn.Conv2d(in_channels=128, out_channels=64, kernel_size=3, stride=1, padding=0, dilation=1),
            nn.ReLU(),

            nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, stride=1, padding=0, dilation=1),
            nn.ReLU(),

            nn.Conv2d(in_channels=64, out_channels=3, kernel_size=1, stride=1, padding=1, dilation=1)
        )
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
    def forward(self, x):

        # block1~5 : Contracting Path
        residual = x
        block1 = self.block1(x)
        block1_pool =  self.pool(block1)
        block2 = self.block2(block1_pool)
        block2_pool = self.pool(block2)
        block3 = self.block3(block2_pool)
        block3_pool = self.pool(block3)
        block4 = self.block4(block3_pool)
        block4_pool = self.pool(block4)
        block5 = self.block5(block4_pool)
        # block1_pool = self.pool(block1)

        # block6~9 : Extracting Path

        ublock5 = block5
        diffX = block4.size()[2] - ublock5.size()[2]
        diffY = block4.size()[3] - ublock5.size()[3]
        ublock5 = F.pad(ublock5, [diffX // 2, diffX - diffX // 2,
                                diffY // 2, diffY - diffY // 2])
        x = torch.cat([block4, ublock5], dim=1)
        block6 = self.block6(x)

        ublock6 = block6
        diffX = block3.size()[2] - ublock6.size()[2]
        diffY = block3.size()[3] - ublock6.size()[3]
        ublock6 = F.pad(ublock6, [diffX // 2, diffX - diffX // 2,
                                diffY // 2, diffY - diffY // 2])
        x = torch.cat([block3, ublock6], dim=1)
        block7 = self.block7(x)

        ublock7 = block7
        diffX = block2.size()[2] - ublock7.size()[2]
        diffY = block2.size()[3] - ublock7.size()[3]
        ublock7 = F.pad(ublock7, [diffX // 2, diffX - diffX // 2,
                                  diffY // 2, diffY - diffY // 2])
        x = torch.cat([block2, ublock7], dim=1)
        block8 = self.block8(x)

        ublock8 = block8
        diffX = block1.size()[2] - ublock8.size()[2]
        diffY = block1.size()[3] - ublock8.size()[3]
        ublock8 = F.pad(ublock8, [diffX // 2, diffX - diffX // 2,
                                diffY // 2, diffY - diffY // 2])
        x = torch.cat([block1, ublock8], dim=1)
        block9 = self.block9(x)

        return block9

class Generator(nn.Module):
    def __init__(self, scale_factor):
        upsample_block_num = int(math.log(scale_factor, 2))

        super(Generator, self).__init__()
        self.block1 = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=9, padding=4),
            nn.PReLU()
        )
        self.block2 = ResidualBlock(64)
        self.block3 = ResidualBlock(64)
        self.block4 = ResidualBlock(64)
        self.block5 = ResidualBlock(64)
        self.block6 = ResidualBlock(64)
        self.block7 = nn.Sequential(
            nn.Conv2d(64, 64, kernel_size=3, padding=1),
            nn.BatchNorm2d(64)
        )
        block8 = [UpsampleBLock(64, 2) for _ in range(upsample_block_num)]
        block8.append(nn.Conv2d(64, 3, kernel_size=9, padding=4))
        self.block8 = nn.Sequential(*block8)

    def forward(self, x):
        block1 = self.block1(x)
        block2 = self.block2(block1)
        block3 = self.block3(block2)
        block4 = self.block4(block3)
        block5 = self.block5(block4)
        block6 = self.block6(block5)
        block7 = self.block7(block6)
        block8 = self.block8(block1 + block7)

        return (torch.tanh(block8) + 1) / 2

class Discriminator(nn.Module):
    def __init__(self):
        super(Discriminator, self).__init__()
        self.net = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=3, padding=1),
            nn.LeakyReLU(0.2),

            nn.Conv2d(64, 64, kernel_size=3, stride=2, padding=1),
            nn.BatchNorm2d(64),
            nn.LeakyReLU(0.2),

            nn.Conv2d(64, 128, kernel_size=3, padding=1),
            nn.BatchNorm2d(128),
            nn.LeakyReLU(0.2),

            nn.Conv2d(128, 128, kernel_size=3, stride=2, padding=1),
            nn.BatchNorm2d(128),
            nn.LeakyReLU(0.2),

            nn.Conv2d(128, 256, kernel_size=3, padding=1),
            nn.BatchNorm2d(256),
            nn.LeakyReLU(0.2),

            nn.Conv2d(256, 256, kernel_size=3, stride=2, padding=1),
            nn.BatchNorm2d(256),
            nn.LeakyReLU(0.2),

            nn.Conv2d(256, 512, kernel_size=3, padding=1),
            nn.BatchNorm2d(512),
            nn.LeakyReLU(0.2),

            nn.Conv2d(512, 512, kernel_size=3, stride=2, padding=1),
            nn.BatchNorm2d(512),
            nn.LeakyReLU(0.2),

            nn.AdaptiveAvgPool2d(1),
            nn.Conv2d(512, 1024, kernel_size=1),
            nn.LeakyReLU(0.2),
            nn.Conv2d(1024, 1, kernel_size=1)
        )

    def forward(self, x):
        batch_size = x.size(0)
        return torch.sigmoid(self.net(x).view(batch_size))

class ResidualBlock(nn.Module):
    def __init__(self, channels):
        super(ResidualBlock, self).__init__()
        self.conv1 = nn.Conv2d(channels, channels, kernel_size=3, padding=1)
        self.bn1 = nn.BatchNorm2d(channels)
        self.prelu = nn.PReLU()
        self.conv2 = nn.Conv2d(channels, channels, kernel_size=3, padding=1)
        self.bn2 = nn.BatchNorm2d(channels)

    def forward(self, x):
        residual = self.conv1(x)
        residual = self.bn1(residual)
        residual = self.prelu(residual)
        residual = self.conv2(residual)
        residual = self.bn2(residual)

        return x + residual

class UpsampleBLock(nn.Module):
    def __init__(self, in_channels, up_scale):
        super(UpsampleBLock, self).__init__()
        self.conv = nn.Conv2d(in_channels, in_channels * up_scale ** 2, kernel_size=3, padding=1)
        self.pixel_shuffle = nn.PixelShuffle(up_scale)
        self.prelu = nn.PReLU()

    def forward(self, x):
        x = self.conv(x)
        x = self.pixel_shuffle(x)
        x = self.prelu(x)
        return x
if __name__== "__main__":
    import cv2
    import torch
    import numpy as np
    img = cv2.imread('Lenna.png').astype(np.float32) / 255.
    net = Unet()
    tensor_ = torch.from_numpy(img.transpose(2,0,1)).unsqueeze(0)
    out = net(tensor_)
    print(tensor_.size())
    print(out.size())


volta = []

temp = 99999
p = 0
tm = 0
tempomed = 0

for i in range(5):
    volta.append(float(input("Informe o tempo da volta: ")))
    tm += volta[i]

for i in range(5):
    if volta[i] < temp:
        temp = volta[i]
        p = i
        tempomed = tm/(i+1)

print(volta)
print("A melhor volta teve: ", temp, " minutos")
print("E ocorreu na seguinte volta: ", p+1)
print("O tempo médio das voltas da corrida foi de ", tempomed, " minutos")


import sys
from typing import Generic, TypeVar, Any

from typing_extensions import Annotated
from packaging import version
from pydantic import Field
from pydantic.fields import ModelField
import numpy as np

Cuid = Annotated[str, Field(min_length=25, max_length=25)]

DType = TypeVar('DType')
DShape = TypeVar('DShape')

class _TypedArray(np.ndarray, Generic[DType, DShape]):

    @classmethod
    def __get_validators__(cls):
        yield cls.validate

    @classmethod
    def validate(cls, val, field: ModelField):
        if not isinstance(val, np.ndarray):
            raise TypeError(f"Expected numpy array. Found {type(val)}")

        if sys.version_info.minor > 6:
            actual_dtype = field.sub_fields[-1].type_.__args__[0]
        else:
            actual_dtype = field.sub_fields[-1].type_.__values__[0]

        if val.dtype != actual_dtype:
            raise TypeError(
                f"Expected numpy array have type {actual_dtype}. Found {val.dtype}"
            )
        return val

if version.parse(np.__version__) >= version.parse('1.25.0'):
    from typing import GenericAlias
    TypedArray = GenericAlias(_TypedArray, (Any, DType))
elif version.parse(np.__version__) >= version.parse('1.23.0'):
    from numpy._typing import _GenericAlias
    TypedArray = _GenericAlias(_TypedArray, (Any, DType))
elif version.parse('1.22.0') <= version.parse(
        np.__version__) < version.parse('1.23.0'):
    from numpy.typing import _GenericAlias
    TypedArray = _GenericAlias(_TypedArray, (Any, DType))
else:
    TypedArray = _TypedArray[Any, DType]


import os
import glob
import re
import argparse

ap = argparse.ArgumentParser()
ap.add_argument('-i', '--input_xml_dir', type=str, default='./annot', help='path to root dir of xmls')
ap.add_argument('-s', '--subfolder', type=str, default='images', help='name of image subfolder')
args = vars(ap.parse_args())

xmls = glob.glob(os.path.join(args['input_xml_dir'], '*xml'))
print('found %d xmls.' % len(xmls))
subfolder = args['subfolder'] if not args['subfolder'].endswith('/') else args['subfolder'][:-1]
print('image sub folder:', subfolder)

pattern1 = r'<filename>(.*?)</filename>'
pattern2 = r'<folder>.*?</folder>'
pattern3 = r'<path>.*?</path>'
for xml in xmls:
    with open(xml, 'r') as fin:
        s = fin.read()
    filename = re.findall(pattern1, s)[0]
    s = re.sub(pattern2, '<folder>%s</folder>' % args['subfolder'], s)
    s = re.sub(pattern3, '<path>%s/%s/%s</path>' % (os.getcwd(), args['subfolder'], filename), s)
    with open(xml, 'wb') as fout:
        fout.write(s)


import shapefile  # pyshp module

from bokeh.palettes import Magma6
from pathlib import Path
from random import choice
from shapely.geometry import Polygon
from wktplot.plots.osm import OpenStreetMapsPlot

COUNTIES_PATH = Path("/path/to/CA_Counties_TIGER2016.shp")

# Create plot and disable mercator calculation
# because data has already been projected
plot = OpenStreetMapsPlot(
    title="California Counties 2016",
    height=1000,
    width=1000,
    disable_mercator=True,
)

# Read shapefile data points from file
with shapefile.Reader(COUNTIES_PATH) as shp:
    for shape in shp.shapes():
        plot.add_shape(
            shape=Polygon(shape.points),
            fill_color=choice(Magma6),
            fill_alpha=0.75,
        )

# Save plot to disk [./california_counties_2016.html]
plot.save()


# Python Libraries
import argparse
import numpy as np
import cv2
import pickle
import os
import time

# PyTorch Libraries
import torch
import torch.nn as nn
import torchvision
from torchvision import transforms
from torchvision.utils import make_grid
from torch.autograd import Variable
import torch.cuda
import torch.backends.cudnn as cudnn
import torch.utils.data

# Local Libraries
from dataloader import MsDataset, get_loader
from build_vocab import Vocabulary
from models import Generator, Discriminator, text_encoding, weights_init, TextEncoding

# Tensorboard
from tensorboard_logger import configure, log_value

def save_checkpoint(state, filename = 'checkpoint.pth'):
	torch.save(state, filename)
	# if is_best:
	# 	shutil.copyfile(filename, 'model_best.pth')

def main(args):
	########## for tensorboard namings #############
	file_counter = 1000
	filename = "runs/run-1000"
	while os.path.isdir(filename):
		file_counter += 1
		filename = "runs/run-" + str(file_counter)
	print(filename)
	configure(filename)
	################################################

	########## Load Text Encoder #############

	##########################################

	if(args.cuda==True):
		cudnn.benchmark = True
		torch.backends.cudnn.enabled = True
	else:
		cudnn.benchmark = False
		torch.backends.cudnn.enabled = False

	# Image preprocessing
	transform = transforms.Compose([
		transforms.RandomCrop(args.crop_size),
		transforms.RandomHorizontalFlip(),
		transforms.ToTensor(),
		transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

	# Load Vocabulary
	file_vocab = open(args.vocab_path, 'rb')
	vocab = pickle.load(file_vocab)
	words = vocab.word2idx
	print(words)

	# Build data loader
	data_loader, length_data = get_loader(args.root_dir, args.image_dir, args.caption_path,
							args.vocab_path, transform, args.batch_size)

	# Load pretrained model if exists, or create if it isn't
	G = Generator(args.nz, args.nt, args.ngf, args.batch_size)
	G.apply(weights_init)
	G.cuda()

	if args.netG:
		G.load_state_dict(torch.load(args.netG))
		# print(G)
		print("loaded model")

	D = Discriminator(args.nz, args.nt, args.ngf, args.ndf, args.batch_size)
	D.apply(weights_init)
	D.cuda()

	if args.netD:
		D.load_state_dict(torch.load(args.netD))
		# print(D)
		print("loaded D")

	# Create FC-RNN-FC layer
	# text_encoder = TextEncoding(args.nt, args.batch_size)

	# Loss and Optimizer
	criterion = nn.BCELoss(size_average=True)

	# RNN
	rnn = TextEncoding(args.nt, args.batch_size, len(vocab))
	max_length = 40
	hidden_size = 40
	n_layers = 30
	# rnn = nn.LSTM(max_length, hidden_size, n_layers, batch_first=True)
	# rnn.cuda()

	# Training credentials
	real_labels = Variable(torch.ones(1)).cuda()
	fake_labels = Variable(torch.zeros(1)).cuda()
	k_t = 0
	h0 = Variable(torch.randn(n_layers, args.batch_size, hidden_size))
	x0 = Variable(torch.randn(args.batch_size, 1, max_length))
	fixed_lengths = []
	fixed_lengths.extend(range(1,65))

	for index, item in enumerate(fixed_lengths):
		fixed_lengths[index] = max_length

	for epoch in range(args.num_epochs):

		if epoch % 10 == 0:
			learning_rate = args.learning_rate * args.lr_decay
		else:
			learning_rate = args.learning_rate

		d_optimizer = torch.optim.Adam(D.parameters(), lr=learning_rate)
		g_optimizer = torch.optim.Adam(G.parameters(), lr=learning_rate)

		for i, (images, captions, lengths) in enumerate(data_loader):

			############ Data Preparation ############
			### images : load image
			### text   : encoded_text
			# TODO: need to make even size captions

			# Compute time
			start = time.time()

			real_labels = Variable(torch.ones(args.batch_size)).cuda()
			fake_labels = Variable(torch.zeros(args.batch_size)).cuda()
			captions_length = len(captions[1].numpy()) - 1
			images = Variable(images).cuda()
			captions = Variable(captions).cuda()

			encoded_text, h0 = rnn.forward(captions, lengths, h0)

			##########################################

			############# Train Discriminator ###############
			D.zero_grad()

			# Train with Real
			d_output_real = D.forward(images, captions, captions_length)
			d_loss_real = criterion(d_output_real, real_labels)
			d_loss_real.backward(retain_variables=True)

			################ Don't use this ####################
			# Train with Fake
			# encoded_text = encoded_text.data
			encoded_text_firstdim = len(encoded_text)
			encoded_text = encoded_text.view(256, encoded_text_firstdim)
			# print(encoded_text)
			fc_layer = nn.Linear(encoded_text_firstdim , args.nt + args.nz)
			fc_layer.cuda()
			encoded_text = fc_layer(encoded_text)
			# print(encoded_text)

			fake = G.forward(encoded_text)
			output = D.forward(fake, captions, captions_length)
			d_loss_fake = criterion(output, fake_labels)
			d_loss_fake.backward(retain_variables=True)

			# Train with Wrong
			wrong = D.forward(images, captions, captions_length)
			d_loss_wrong = criterion(wrong, fake_labels)
			d_loss_wrong.backward(retain_variables=True)

			# Getting D_LOSS
			d_loss = d_loss_real + d_loss_wrong + d_loss_fake / 2
			d_loss.backward(retain_variables=True)
			d_optimizer.step()
			###################################################

			############## Train Generator ###################
			G.zero_grad()

			g_output = G.forward(encoded_text)

			# discriminate fake images
			d_output_fake = D.forward(g_output, captions, captions_length)
			g_loss = criterion(d_output_fake, real_labels)

			# Getting G_LOSS
			g_loss.backward(retain_variables=True)
			g_optimizer.step()

			# d_loss =  d_loss_real + g_loss

			# d_optimizer.step()
			##################################################

			# Decode input text for sanity check

			# Reshape output based on batch size
			g_output = g_output.view(args.batch_size, 3, 64, 64)

			end = time.time()
			diff = end - start
			# print(g_output)
			if True:
				print('Epoch [%d/%d], Step[%d/%d], d_loss: %.4f, g_loss: %.4f, '
					'D(x): %.2f, D(G(z)): %.2f, Computation_time: %.5f'
					%(epoch, 200, (i + 1)*args.batch_size, length_data, d_loss.data[0], g_loss.data[0],
					d_output_real.cpu().data.mean(), d_output_fake.cpu().data.mean(), diff))

			# torchvision.utils.save_image(g_output.data,
			#  './output/generated_sample_%d.png' % (epoch+1))
			torchvision.utils.save_image(g_output.data,
			 args.output_path + '/generated_sample_%d.png' % (epoch+1))
			# visualization
			log_value('g_loss', g_loss.data[0], i)
			log_value('d_loss', d_loss.data[0], i)

			# Memory free-ups
			# del g_output, d_output_fake, d_output_real, images, d_loss_real, d_loss_fake, g_loss, d_loss

			if i >= 203:
				break
		if epoch % 1 == 0:
			epoch_count = 0
			torch.save(G.state_dict(), args.checkpoint_path + '/netG_epoch_%d.pth' % (epoch_count))
			torch.save(D.state_dict(), args.checkpoint_path + '/netD_epoch_%d.pth' % (epoch_count))
		# epoch += 1
		continue
		print(epoch)

# call main and do add_argument
if __name__ == '__main__':
	parser = argparse.ArgumentParser()
	parser.add_argument('--model_path', type=str, default='./models/' ,
						help='path for saving trained models')
	parser.add_argument('--root_dir', type=str, default='./',
						help='path of the root directory.')
	parser.add_argument('--crop_size', type=int, default=64 ,
						help='size for randomly cropping images')
	parser.add_argument('--vocab_path', type=str, default='./Data/vocab_coco.pickle',
						help='path for vocabulary wrapper')
	parser.add_argument('--image_dir', type=str, default='./resized_coco/' ,
						help='directory for resized images')
	parser.add_argument('--caption_path', type=str,
						default='./',
						help='path for train annotation json file')
	# parser.add_argument('--log_step', type=int , default=10,
	# 					help='step size for prining log info')
	# parser.add_argument('--save_step', type=int , default=1000,
	# 					help='step size for saving trained models')
	parser.add_argument('--cuda', action='store_true',
						help='use cuda?')
	parser.add_argument('--output_path', type=str, default='./output',
						help='specify output path please :)')
	parser.add_argument('--checkpoint_path', type=str, default='./checkpoint',
						help='specify checkpoint path please :)')
	parser.add_argument('--netG', type=str, default='', help='load netG pretrained')
	parser.add_argument('--netD', type=str, default='', help='load netD pretrained')

	# Model parameters
	# parser.add_argument('--embed_size', type=int , default=256 ,
	# 					help='dimension of word embedding vectors')
	# parser.add_argument('--hidden_size', type=int , default=512 ,
	# 					help='dimension of lstm hidden states')
	# parser.add_argument('--num_layers', type=int , default=1 ,
	# 					help='number of layers in lstm')

	# Model parameters
	parser.add_argument('--ngf', type=int, default=128,
		help='dim of gen filters for first layer')
	parser.add_argument('--nz', type=int, default=128,
		help='dim of noise')
	parser.add_argument('--nt', type=int, default=1024,
		help='dim of text features')
	parser.add_argument('--ndf', type=int, default=64,
		help='dim of text features')

	# TODO: add ndf for discriminator

	parser.add_argument('--num_epochs', type=int, default=5000)
	parser.add_argument('--batch_size', type=int, default=64)
	parser.add_argument('--num_workers', type=int, default=2)
	parser.add_argument('--learning_rate', type=float, default=0.0005)
	parser.add_argument('--lr_decay', type=float, default=0.5)
	parser.add_argument('--lambda_k', type=float, default=1)
	parser.add_argument('--gamma', type=float, default=1)
	args = parser.parse_args()
	print(args)

	main(args)


import datetime as dt
import pytest
from .config import OUTCOMES_ATTR
from .common import (
    PytestExperimentsError,
    PytestOutcome,
    PytestReportPhase,
    ExperimentOutcome,
)
from .store import StorageManager, ExperimentModel

class Experiment:
    def __init__(self, request: pytest.FixtureRequest) -> None:
        self.context = request
        self.store = StorageManager(experiments_db_uri(self.context))
        self.created_at = dt.datetime.utcnow()
        self.completed_at = None
        self.outcome = ExperimentOutcome.not_reported
        self.data = {}

    def record(self, **kwargs):
        """Record data about this experiment.

        As this data will be serialized as JSON, keys *must* be strings. This
        is enforced by the stricter requirement that keys be valid python
        identifiers.
        """
        self.data.update(**kwargs)

    @property
    def test_fn(self) -> pytest.Function:
        """The test function."""
        return self.context.node

    @property
    def name(self) -> str:
        """The full qualified name of the test."""
        return self.test_fn.nodeid

    @property
    def parameters(self) -> dict:
        """The input parameters of the test.

        This will contain the closure of inputs supplied to the test,
        some of which we do not care about.
        """
        return dict(
            filter(self._ignore_funcargs_items, self.test_fn.funcargs.items())
        )

    def _ignore_funcargs_items(self, item) -> bool:
        """Ignores some funcarg items that we do not care about."""
        _, v = item
        if v is self:
            return False
        if isinstance(v, pytest.FixtureRequest):
            return False
        return True

    def get_reports(self) -> dict:
        """Returns the reports dict if it exists.

        The reports dict is populated by our custom hook and is *only*
        available after the test has run.
        """
        reports = getattr(self.context.node, OUTCOMES_ATTR, None)
        if reports is None:
            raise ExperimentError(
                "Could not find a `reports` attribute. "
                "This method may only be called after the test has run."
            )
        return reports

    def post_process(self):
        """Inspect the context for test outcome.

        The method may only be run *after* the test has completed.
        """
        self.completed_at = dt.datetime.utcnow()
        self.outcome = to_experiment_outcome(self.get_reports())

    def to_model(self) -> ExperimentModel:
        """Render the experiment into its database model."""
        return ExperimentModel(
            name=self.name,
            start_time=self.created_at,
            end_time=self.completed_at,
            outcome=self.outcome.name,
            parameters=self.parameters,
            data=self.data,
        )

    def save(self):
        """Save this experiment to the database."""
        self.store.record_experiment(self.to_model())

    def finish(self):
        """Post process the experiment and save to the database."""
        self.post_process()
        self.save()

def experiments_db_uri(request: pytest.FixtureRequest) -> str:
    """Retrieve the URI of the database used to store experiment results."""
    return request.config.option.experiments_database_uri

def to_experiment_outcome(reports: dict) -> ExperimentOutcome:
    """Return an ExperimentOutcome from the pytest reports"""
    if reports[PytestReportPhase.setup] is PytestOutcome.failed:
        return ExperimentOutcome.error
    test_outcome = reports.get(PytestReportPhase.call)
    if test_outcome is None:
        return ExperimentOutcome.not_reported
    return ExperimentOutcome[test_outcome.name]

class ExperimentError(PytestExperimentsError):
    pass


# 문자열 s가 매개변수로 주어집니다.
# s에서 한 번만 등장하는 문자를 사전 순으로 정렬한 문자열을 return 하도록 solution 함수를 완성해보세요.
# 한 번만 등장하는 문자가 없을 경우 빈 문자열을 return 합니다.

def solution(s):
    answer = ''
    my_string = sorted(list(s))
    for i in my_string:
        if my_string.count(i) == 1:
            answer += i
    return answer

# def solution(s):
#     return ''.join(sorted([i for i in set(s) if (s.count(i) == 1)]))
# set를 통해서 for문에서 중복되는 문자를 하나로 통합함 -> 중복 조회를 줄인다

print(solution("abcabcadc"))


from gbrick.types.base import BaseTransaction, BaseReceipt
from utils.crypto.hash import sha3_hex

class Transaction(BaseTransaction):

    @property
    def hash(self):
        setup = self.__slots__[:-2]
        attr = self.serialize(setup)
        return sha3_hex(','.join(attr).encode())

class Receipt(BaseReceipt):

    @property
    def hash(self):
        setup = self.__slots__
        attr = self.serialize(setup)
        return sha3_hex(','.join(attr).encode())


#!/usr/bin/env python
# -*- coding: utf-8 -*-

import pygame
import math
import random

REWARD_RADIUS = 20
CAR_SPEED = 10
CAR_TURN = 30

def normalize(x, xmin, xmax):
    return ((x-xmin)/(xmax-xmin))

class pyGame(object):
    def __init__(self, width=1280, height=1024, fps=60, caption="PyGame", verbose = True, carX = 640, carY = 512, parkX = 640, parkY = 512):
        self.width = width
        self.height = height
        self.verbose = verbose

        #clock
        self.clock = pygame.time.Clock()
        self.fps = fps
        self.playtime = 0.0

        self.car = Car(carX,carY,0)
        self.env = Environment(parkX,parkY,0)

        #screen init
        if self.verbose:
            pygame.init()
            pygame.display.set_caption(caption)
            self.screen = pygame.display.set_mode((self.width, self.height), pygame.DOUBLEBUF)
            #frame init
            self.background = pygame.Surface(self.screen.get_size()).convert()
            self.background.fill((0,0,0)) # fill background black
            #font
            self.font = pygame.font.SysFont('mono', 14, bold=True)

    def reset(self, rX = False, rY = False, rD = False):
        self.car.reset(rX, rY, rD)
        self.env.reset(rX, rY, rD)
        return self.state()

    def state(self):
        return [normalize(self.car.rearAxis.x,0,self.width), normalize(self.car.rearAxis.y,0,self.height), \
              normalize(self.car.frontAxis.x,0,self.width), normalize(self.car.frontAxis.y,0,self.height), \
              normalize(self.env.parkEnd.x,0,self.width),  normalize(self.env.parkEnd.y,0,self.height), \
              normalize(self.env.parkFront.x,0,self.width), normalize(self.env.parkFront.y,0,self.height)]

    def draw(self):
        # draw functions here
        self.background.fill((0,0,0))
        self.background = self.background.convert()

    def flip(self):
        self.screen.blit(self.background, (0,0))
        pygame.display.flip()

    def __del__(self):
        #desctructor
        pygame.quit()
        print("Total play time {:.2f} seconds".format(self.playtime))

    def draw_text(self, text, x, y ):
        """Center text in window
        """
        surface = self.font.render(text, True, (0, 255, 0))
        # // makes integer division in python3
        self.background.blit(surface, (x, y))

    def reward(self):
        if math.fabs(self.car.rearAxis.x - self.env.parkEnd.x) < REWARD_RADIUS and math.fabs(self.car.rearAxis.y - self.env.parkEnd.y) < REWARD_RADIUS and \
           math.fabs(self.car.frontAxis.x - self.env.parkFront.x) < REWARD_RADIUS and math.fabs(self.car.frontAxis.y - self.env.parkFront.y < REWARD_RADIUS):
           if self.car.speed == 0:
               return 5000
           else:
                return 1000
        else:
           if self.car.speed == 0:
               return int( - (math.pow(self.car.rearAxis.x - self.env.parkEnd.x,2) + math.pow(self.car.rearAxis.y - self.env.parkEnd.y,2))/2000-100)
           else:
               return int( - (math.pow(self.car.rearAxis.x - self.env.parkEnd.x,2) + math.pow(self.car.rearAxis.y - self.env.parkEnd.y,2))/2000)

    def done(self):
        if (self.car.rearAxis.x>self.width) or (self.car.rearAxis.x<0) or \
        (self.car.rearAxis.y >self.height) or (self.car.rearAxis.y<0):
            return True
        #elif math.fabs(self.car.rearAxis.x - self.env.parkEnd.x) < REWARD_RADIUS and math.fabs(self.car.rearAxis.y - self.env.parkEnd.y) < REWARD_RADIUS and \
        #   math.fabs(self.car.frontAxis.x - self.env.parkFront.x) < REWARD_RADIUS and math.fabs(self.car.frontAxis.y - self.env.parkFront.y < REWARD_RADIUS):
        #    return True
        else:
            return False

    def step(self, action):
        #self.milliseconds = self.clock.tick(self.fps)  # milliseconds passed since last frame
        #self.seconds = self.milliseconds / 1000.0
        #self.playtime += self.seconds
        self.car.act(action)

        # all movement here
        #self.car.move(self.seconds, self.width, self.height)
        self.car.move()

        if self.verbose:
            # all render here
            self.draw()
            self.car.draw(self.background)
            self.env.draw(self.background)
            #self.draw_text("FPS {:.1f}".format(self.clock.get_fps()), 10, 10)
            self.draw_text("Action: {} speed: {} turn: {} Reward {}".format(action,self.car.speed,self.car.turnAngle, self.reward()),10, 10)
            self.flip()

        return self.state(), self.reward(), self.done(), 0

    def run(self):
        mainloop = True

        while mainloop:
            # count time
            self.milliseconds = self.clock.tick(self.fps)  # milliseconds passed since last frame
            self.seconds = self.milliseconds / 1000.0
            self.playtime += self.seconds

            # check for events
            self.car.speed = 0
            self.car.turnAngle = 0
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    mainloop = False # pygame window closed by user
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_ESCAPE:
                        mainloop = False # user pressed ESC
                    if event.key == pygame.K_r:
                        self.env.renewPark()

            pressed = pygame.key.get_pressed()
            if pressed[pygame.K_w]:
                self.car.speed = CAR_SPEED
            if pressed[pygame.K_s]:
                self.car.speed = -CAR_SPEED
            if pressed[pygame.K_a]:
                self.car.turnAngle = -CAR_TURN
            if pressed[pygame.K_d]:
                self.car.turnAngle = CAR_TURN

            # all movement here
            #self.car.move(self.seconds, self.width, self.height)
            self.car.move(1)

            # all render here
            self.draw()
            self.car.draw(self.background)
            self.env.draw(self.background)
            self.draw_text("speed: {} turn: {} Reward {}".format(self.car.speed,self.car.turnAngle, self.reward()),10, 10)
            self.flip()

class Point(object):
    def __init__(self, x = 0, y = 0):
        self.x = x
        self.y = y

    def xy(self):
        return self.x, self.y

    def xyI(self):
        return int(self.x), int(self.y)

    def rotate(self, px = 0, py = 0, angle = 0):
        self.x = px + self.x  * math.cos(math.radians(angle)) - self.y  * math.sin(math.radians(angle))
        self.y = py + self.x  * math.sin(math.radians(angle)) + self.y  * math.cos(math.radians(angle))

    def translate(self, lenght, angle, p = 0):
        if p == 0:
            self.x += lenght * math.cos(math.radians(angle))
            self.y += lenght * math.sin(math.radians(angle))
        else:
            self.x = p.x + lenght * math.cos(math.radians(angle))
            self.y = p.y + lenght * math.sin(math.radians(angle))

    def random(self, xmin, xmax, ymin, ymax):
        self.x = random.randrange(xmin, xmax)
        self.y = random.randrange(ymin, ymax)

    def copy(self, p):
        self.x = p.x
        self.y = p.y

class graphicCalculations():
    def findLocation(self,centerPointX, centerPointY, deltaX,deltaY, angle):
        # find location from center of object and apply rotation by given angle
        centerPoint = Point(centerPointX, centerPointY)
        delta = Point(deltaX, deltaY)
        return self.findLocation(centerPoint, delta, angle)

    def findLocation(self,centerPoint, delta, angle):
        # find location from center of object and apply rotation by given angle
        out = Point()
        out.x = int(centerPoint.x + delta.x  * math.cos(math.radians(angle)) - delta.y  * math.sin(math.radians(angle)))
        out.y = int(centerPoint.y + delta.x  * math.sin(math.radians(angle)) + delta.y  * math.cos(math.radians(angle)))
        return out

class Environment(object):
    def __init__(self, parkEndStartX = 400, parkEndStartY = 240, directionStart = 0 ):
        self.parkEndStart = Point()
        self.parkEndStart.x = parkEndStartX
        self.parkEndStart.y = parkEndStartY
        self.random = random
        self.parkEnd = Point()
        self.parkFront = Point()
        self.parkLenght = 50
        self.directionStart = 0
        self.direction = 30
        self.points = 0
        self.reset()

    def draw(self,surface):
        # center of the parking space
        pygame.draw.line(surface, (150,150,150), self.parkEnd.xy(), self.parkFront.xy())

        # circle to aroung front and back point
        pygame.draw.circle(surface, (100,100,100), self.parkEnd.xyI(),2,1)
        #pygame.draw.circle(surface, (100,0,100), self.parkFront.xyI(),30,1)

        # outlines of the parking space
        rl = graphicCalculations().findLocation(self.parkEnd,  Point(-20,-20),self.direction)
        rr = graphicCalculations().findLocation(self.parkEnd,  Point(-20, 20),self.direction)
        fr = graphicCalculations().findLocation(self.parkFront,Point( 20, 20),self.direction)
        fl = graphicCalculations().findLocation(self.parkFront,Point( 20,-20),self.direction)

        pygame.draw.polygon(surface, (150,150,150), (rl.xyI(),rr.xyI(),fr.xyI(),fl.xyI()), 1)

    def reset(self, rX = False, rY = False, rD = False):
        if rX:
            self.parkEnd.x = random.randrange(200,1000) #self.parkEndStart.x
        else:
            self.parkEnd.x = self.parkEndStart.x
        if rY:
            self.parkEnd.y = random.randrange(200,800) #self.parkEndStart.y
        else:
            self.parkEnd.y = self.parkEndStart.y
        if rD:
            self.direction = random.randrange(0,360) #self.directionStart
        else:
            self.direction = self.directionStart

        self.parkFront.translate(self.parkLenght, self.direction, self.parkEnd)

    def renewPark(self):
        self.parkEnd.random(100,540,100,220)
        self.direction = random.randrange(0,360)
        self.parkFront.translate(self.parkLenght, self.direction, self.parkEnd)

class Car(object):
    def __init__(self,startX = 100, startY = 140, directionStart = 0):
        self.rearAxisStart = Point()
        self.rearAxisStart.x = startX
        self.rearAxisStart.y = startY
        self.directionStart = directionStart
        self.direction = self.directionStart
        self.random = random
        self.carLenght = 50
        self.carWidth = 30
        self.wheelSize = 16
        self.rearAxis = Point()
        self.direction = 0 # angle of the car 0-360
        self.color = (255,0,0)
        self.turnAngle = 0 # turning angle 0-360
        self.speed = 0

        # point to turn around
        self.turnPoint = Point()
        self.frontAxis = Point()
        self.reset()
        #action 0 - stop, 1-forward, 2-backward, 3 forward + right, 4 forward + left, 5 - backward + rigth, 6 backward + left
        self.actSpeed = {
            0: 0,
            1: CAR_SPEED,
            2: -CAR_SPEED,
            3: CAR_SPEED,
            4: CAR_SPEED,
            5: -CAR_SPEED,
            6: -CAR_SPEED
        }
        self.actTurn = {
            0: 0,
            1: 0,
            2: 0,
            3: CAR_TURN,
            4: -CAR_TURN,
            5: CAR_TURN,
            6: -CAR_TURN
        }

    def act(self, action):
        self.speed = self.actSpeed[action]
        self.turnAngle = self.actTurn[action]
        #print("Action: ",action, "\tSpeed: ", self.speed, "\tTurn: ", self.turnAngle)

    def reset(self, rX = False, rY = False, rD = False):
        if rX:
            self.rearAxis.x = random.randrange(200,1000) #self.rearAxisStart.x
        else:
            self.rearAxis.x = self.rearAxisStart.x

        if rY:
            self.rearAxis.y = random.randrange(200,800) #self.rearAxisStart.y
        else:
            self.rearAxis.y = self.rearAxisStart.y

        if rD:
            self.direction = random.randrange(0,360) #self.directionStart
        else:
            self.direction = self.directionStart

        #update front axis
        self.frontAxis.translate(self.carLenght, self.direction, self.rearAxis)

    def move(self):

        #update front axis
        self.frontAxis.translate(self.carLenght, self.direction, self.rearAxis)

        if self.turnAngle != 0:
            turnRadius = self.carLenght / math.sin(math.radians(self.turnAngle))
            angleSpeed = ( self.speed / turnRadius )

            # calculate turn point
            self.turnPoint.x = self.frontAxis.x + self.carLenght * math.sin(math.radians(-self.direction-self.turnAngle)) / math.sin(math.radians(self.turnAngle))
            self.turnPoint.y = self.frontAxis.y + self.carLenght * math.cos(math.radians(-self.direction-self.turnAngle)) / math.sin(math.radians(self.turnAngle))

            # update direction
            self.direction += math.degrees(angleSpeed)
            if self.direction >= 360:
                self.direction -= 360
            if self.direction <=0:
                self.direction += 360;

            # rotate rear axis
            #self.rearAxis.rotate(self.turnPoint.x, self.turnPoint.y, self.angleSpeed)
            self.rearAxis.x = ((self.rearAxis.x - self.turnPoint.x) * math.cos(angleSpeed) - (self.rearAxis.y - self.turnPoint.y) * math.sin(angleSpeed) + self.turnPoint.x)
            self.rearAxis.y = ((self.rearAxis.x - self.turnPoint.x) * math.sin(angleSpeed) + (self.rearAxis.y - self.turnPoint.y) * math.cos(angleSpeed) + self.turnPoint.y)
        else:
            self.rearAxis.x += self.speed * math.cos(math.radians(self.direction))
            self.rearAxis.y += self.speed * math.sin(math.radians(self.direction))
            self.turnPoint.x = 0
            self.turnPoint.y = 0

    def findLocation(self,dx,dy):
        # find location from rearAxis centre, after appling direction
        outcome = Point()
        outcome.x = int(self.rearAxis.x + dx  * math.cos(math.radians(self.direction)) - dy  * math.sin(math.radians(self.direction)))
        outcome.y = int(self.rearAxis.y + dx  * math.sin(math.radians(self.direction)) + dy  * math.cos(math.radians(self.direction)))
        return outcome

    def drawLine(self,surface, x1,y1,x2,y2): # fro drawing a car (before rotation)
        pygame.draw.line(surface, self.color, self.findLocation(x1,y1).xy(),self.findLocation(x2,y2).xy())

    def draw(self, surface):
        #pygame.draw.circle(surface,(0,70,0), (150,100), 20)
        # draw main line
        self.drawLine(surface, 0, 0, self.carLenght, 0)

        #draw Axis
        self.drawLine(surface, 0, -self.carWidth/2, 0, self.carWidth/2)
        self.drawLine(surface, self.carLenght,  -self.carWidth/2, self.carLenght,  self.carWidth/2)

        #draw wheels
        #back
        self.drawLine(surface, -self.wheelSize/2, -self.carWidth/2, self.wheelSize/2, -self.carWidth/2)
        self.drawLine(surface, -self.wheelSize/2,  self.carWidth/2, self.wheelSize/2,  self.carWidth/2)
        #front
        #fl = Point(0,0)
        fl1 = Point( self.wheelSize/2,0)
        fl2 = Point(-self.wheelSize/2,0)
        fl1.rotate(0,0, self.turnAngle)
        fl2.rotate(0,0, self.turnAngle)
        self.drawLine(surface, self.carLenght + fl1.x, -self.carWidth/2 + fl1.y, self.carLenght+fl2.x, -self.carWidth/2 + fl2.y)
        self.drawLine(surface, self.carLenght + fl1.x,  self.carWidth/2 + fl1.y, self.carLenght+fl2.x,  self.carWidth/2 + fl2.y)

        # draw turn point (center of turning) and radius
        if self.turnPoint.x != 0 and self.turnPoint.y != 0:
            pygame.draw.circle(surface, (100,0,0), (int(self.turnPoint.x), int(self.turnPoint.y)), 2)
            pygame.draw.line(surface, (0,50,0), (int(self.frontAxis.x), int(self.frontAxis.y)), (int(self.turnPoint.x), int(self.turnPoint.y)))

if __name__ == '__main__':
    g = pyGame()
    g.run()