import math
import random
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from collections import namedtuple, deque
from itertools import count
from random import choice
from copy import deepcopy

from project.tools.logger import logger, init_logger

import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F

from project.env.environnement import Environnement
from project.env.states import State

env = Environnement.init("3dadvanced")

# set up matplotlib
is_ipython = 'inline' in matplotlib.get_backend()
if is_ipython:
    from IPython import display

plt.ion()

# if gpu is to be used
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

Transition = namedtuple('Transition',
                        ('state', 'action', 'next_state', 'reward'))

class ReplayMemory(object):

    def __init__(self, capacity):
        self.memory = deque([],maxlen=capacity)

    def push(self, *args):
        """Save a transition"""
        self.memory.append(Transition(*args))

    def sample(self, batch_size):
        return random.sample(self.memory, batch_size)

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

class DQN(nn.Module):

    def __init__(self, n_observations, n_actions):
        super(DQN, self).__init__()
        self.layer1 = nn.Linear(n_observations, 256)
        self.layer2 = nn.Linear(256, 2048)
        self.layer3 = nn.Linear(2048, 128)
        self.layer4 = nn.Linear(128, n_actions)

    # Called with either one element to determine next action, or a batch
    # during optimization. Returns tensor([[left0exp,right0exp]...]).
    def forward(self, x):
        x = F.relu(self.layer1(x))
        x = F.relu(self.layer2(x))
        x = F.relu(self.layer3(x))
        return self.layer4(x)

# BATCH_SIZE is the number of transitions sampled from the replay buffer
# GAMMA is the discount factor as mentioned in the previous section
# EPS_START is the starting value of epsilon
# EPS_END is the final value of epsilon
# EPS_DECAY controls the rate of exponential decay of epsilon, higher means a slower decay
# TAU is the update rate of the target network
# LR is the learning rate of the AdamW optimizer
BATCH_SIZE = 64
GAMMA = 0.9999
EPS_START = 0.1
EPS_END = 0.005
EPS_DECAY = 10000
TAU = 0.005
LR = 1e-3

init_logger(logger)

all_poss_action = env.getPossibleActions()
all_poss_state = env.getEveryState()
# ennumerate all state
transfo_state_to_int = dict()
for i,x in enumerate(all_poss_state):
    transfo_state_to_int[x] = i
# Get number of actions from gym action space
n_actions = len(all_poss_action)
# Get the number of state observations
transfo_action_to_int = dict()
for i,a in enumerate(all_poss_action):
    transfo_action_to_int[a] = i

def one_hot_state(s:int):
    res = np.zeros(len(all_poss_state))
    res[s] = 1
    return res

def one_hot_action(a:int):
    res = np.zeros(len(all_poss_action))
    res[a] = 1
    return res

state = env.reset()

def state_to_obs(state:State):
    np_obs = one_hot_state(transfo_state_to_int[state])
    return torch.tensor(np_obs, device=device, dtype=torch.float32).unsqueeze(0)

n_observations = 35

policy_net = DQN(n_observations, n_actions).to(device)
target_net = DQN(n_observations, n_actions).to(device)
target_net.load_state_dict(policy_net.state_dict())

optimizer = optim.AdamW(policy_net.parameters(), lr=LR, amsgrad=True)
memory = ReplayMemory(10000)

steps_done = 0

def select_action(state):
    global steps_done
    sample = random.random()
    eps_threshold = EPS_END + (EPS_START - EPS_END) * \
        math.exp(-1. * steps_done / EPS_DECAY)
    steps_done += 1
    if sample > eps_threshold:
        with torch.no_grad():
            # t.max(1) will return largest column value of each row.
            # second column on max result is index of where max element was
            # found, so we pick action with the larger expected reward.
            return policy_net(state).max(1)[1]
    else:
        return torch.tensor([transfo_action_to_int[choice(all_poss_action)]], device=device, dtype=torch.long)

rewards = []

def plot_rewards(show_result=False):
    plt.figure(1)
    rewards_t = torch.tensor(rewards, dtype=torch.float)
    if show_result:
        plt.title('Result')
    else:
        plt.clf()
        plt.title('Training...')
    plt.xlabel('Episode')
    plt.ylabel('Reward')
    plt.plot(rewards_t.numpy())
    # Take 100 episode averages and plot them too
    if len(rewards_t) >= 100:
        means = rewards_t.unfold(0, 100, 10).mean(10).view(-1)
        means = torch.cat((torch.zeros(99), means))
        plt.plot(means.numpy())

    plt.pause(0.001)  # pause a bit so that plots are updated
    if is_ipython:
        if not show_result:
            display.display(plt.gcf())
            display.clear_output(wait=True)
        else:
            display.display(plt.gcf())

def optimize_model():
    if len(memory) < BATCH_SIZE:
        return
    transitions = memory.sample(BATCH_SIZE)
    # Transpose the batch (see https://stackoverflow.com/a/19343/3343043 for
    # detailed explanation). This converts batch-array of Transitions
    # to Transition of batch-arrays.
    batch = Transition(*zip(*transitions))

    # Compute a mask of non-final states and concatenate the batch elements
    # (a final state would've been the one after which simulation ended)
    non_final_mask = torch.tensor(tuple(map(lambda s: s is not None,
                                          batch.next_state)), device=device, dtype=torch.bool)
    non_final_next_states = torch.cat([s for s in batch.next_state
                                                if s is not None])
    state_batch = torch.cat(batch.state)
    action_batch = torch.cat(batch.action)
    reward_batch = torch.cat(batch.reward)

    # Compute Q(s_t, a) - the model computes Q(s_t), then we select the
    # columns of actions taken. These are the actions which would've been taken
    # for each batch state according to policy_net
    state_action_values = policy_net(state_batch).gather(1, action_batch)

    # Compute V(s_{t+1}) for all next states.
    # Expected values of actions for non_final_next_states are computed based
    # on the "older" target_net; selecting their best reward with max(1)[0].
    # This is merged based on the mask, such that we'll have either the expected
    # state value or 0 in case the state was final.
    next_state_values = torch.zeros(BATCH_SIZE, device=device)
    with torch.no_grad():
        next_state_values[non_final_mask] = target_net(non_final_next_states).max(1)[0]
    # Compute the expected Q values
    expected_state_action_values = (next_state_values * GAMMA) + reward_batch

    # Compute Huber loss
    criterion = nn.MSELoss()
    loss = criterion(state_action_values, expected_state_action_values.detach())

    # Optimize the model
    optimizer.zero_grad()
    loss.backward()
    # In-place gradient clipping
    torch.nn.utils.clip_grad_value_(policy_net.parameters(), 100)
    optimizer.step()

num_episodes = 2000

for i_episode in range(num_episodes):
    # Initialize the environment and get it's state
    state = env.reset()
    state = state_to_obs(state)
    done = False
    while not done:
        action = F.one_hot(select_action(state), n_actions)

        observation, reward, done = env.step(all_poss_action[torch.argmax(action)])
        reward = torch.tensor([reward], device=device)
        logger.info(f"Step : {env.step_number-1} Agent observes: state={all_poss_state[torch.argmax(state)]}, action={all_poss_action[torch.argmax(action)]}, reward={reward}, done={done}")

        env.render()

        if done:
            print(state)
            print(env.score)
            if i_episode%2 == 1:
                env.final_render()
            next_state = None
        else:
            next_state = state_to_obs(observation)

        # Store the transition in memory
        memory.push(state, action, next_state, reward)

        # Move to the next state
        state = deepcopy(next_state)

        # Perform one step of the optimization (on the policy network)
        optimize_model()

        # Soft update of the target network's weights
        # θ′ ← τ θ + (1 −τ )θ′
        target_net_state_dict = target_net.state_dict()
        policy_net_state_dict = policy_net.state_dict()
        for key in policy_net_state_dict:
            target_net_state_dict[key] = policy_net_state_dict[key]*TAU + target_net_state_dict[key]*(1-TAU)
        target_net.load_state_dict(target_net_state_dict)

        if done:
            print(EPS_END + (EPS_START - EPS_END) * \
        math.exp(-1. * steps_done / EPS_DECAY))
            rewards.append(env.score)
            plot_rewards()
            break

print('Complete')
plot_rewards(show_result=True)
plt.ioff()
plt.show()


# 导入需要的包
from skimage.exposure import rescale_intensity
import numpy as np
import  argparse
import cv2

# 定义卷积方法
def convolve(image, K):
    # 获取图像和核的空间维度
    (iH, iW) = image.shape[:2]
    (kH, kW) = K.shape[:2]

    # 为输出分配内存
    pad = (kW - 1) // 2
    image = cv2.copyMakeBorder(image, pad, pad, pad, pad, cv2.BORDER_REPLICATE)
    output = np.zeros((iH, iW), dtype="float")

    # 循环输入图像，“滑动”内核
    # 每个(x, y)从左到右和从上到下的坐标
    for y in np.arange(pad, iH + pad):
        for x in np.arange(pad, iW + pad):
            # 通过提取当前(x, y)坐标维度的中心区域，提取图像的ROI
            roi = image[y - pad : y + pad + 1 ,x - pad:x + pad + 1]

            # #执行实际的卷积，在ROI和核之间进行元素的乘法，然后对矩阵求和
            k = (roi * K).sum()

            # #将卷积值存储在输出图像的(x, y)坐标中
            output[y - pad, x - pad] = k

    # 然后，完成输出
    output = rescale_intensity(output, in_range=(0, 255))
    output = (output * 255).astype("uint8")

    return output

# 设置命令行参数，主要设置为输入的图片
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="path to the input image")
args = vars(ap.parse_args())

# 构造用于平滑图像的平均模糊核
smallBlur = np.ones((7, 7), dtype="float") * (1.0 / (7 * 7))
largeBlur = np.ones((21, 21), dtype="float") * (1.0 / (21 * 21))

# 构造一个锐化过滤器
sharpen = np.array((
[0, -1, 0],
[-1, 5, -1],
[0, -1, 0]), dtype="int")

# 构造用于检测图像边缘区域的拉普拉斯核
laplacian = np.array((
[0, 1, 0],
[1, -4, 1],
[0, 1, 0]), dtype="int")

# 构造 Sobelx轴 核
sobelX = np.array((
[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1]), dtype="int")

# 构造 Sobely轴 核
sobelY = np.array((
[-1, -2, -1],
[0, 0, 0],
[1, 2, 1]), dtype="int")

 # 构造一个emboss核
emboss = np.array((
[-2, -1, 0],
[-1, 1, 1],
[0, 1, 2]), dtype="int")

# 构造内核库，一个我们将用的内核列表
# 同时使用我们自己构造的‘convole‘函数和OpenCV库中的‘filter2D‘函数
kernelBank = (
("small_blur", smallBlur),
("large_blur", largeBlur),
("sharpen", sharpen),
("laplacian", laplacian),
("sobel_x", sobelX),
("sobel_y", sobelY),
("emboss", emboss))

# 下面的code演示了使用上述内核库的方法
image = cv2.imread(args["image"])
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 循环覆盖内核库
for (kernelName, K) in kernelBank:
    # 使用我们自定义的' convolve '函数和OpenCV的' filter2d '函数将内核应用到灰度图像
    print("[INFO] applying {} kernel".format(kernelName))
    convolveOutput = convolve(gray, K)
    opencvOutput = cv2.filter2D(gray, -1, K)

    # 展示输出的图像
    cv2.imshow("Original", gray)
    cv2.imshow("{} - convole".format(kernelName), convolveOutput)
    cv2.imshow("{} - opencv".format(kernelName), opencvOutput)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


import json
import hashlib
import math

class ReadFile:
  def __init__(self):
    pass

  def getInfoHash(file_path):
    with open(file_path) as json_file:
      data = json.load(json_file)
      info = json.dumps(data['info'], sort_keys=True)
      hs = hashlib.sha256(info.encode('utf-8')).hexdigest()
      return hs

  def getTrackerIp(file_path):
    with open(file_path) as json_file:
      data = json.load(json_file)
      trackerIp = data['announce']
      return trackerIp

  def getNPiece(file, n, piece_length):
    file.seek(piece_length*n, 0)
    answer = file.read(piece_length)
    return answer

  def getNHashPiece(file_path, n):
    with open(file_path) as json_file:
      data = json.load(json_file)
      info = data['info']
      pieces = info['pieces']
      return pieces[n*64:(n+1)*64]

  def getNumberOfPieces(file_path):
    with open(file_path) as json_file:
      data = json.load(json_file)
      info = data['info']
      length = int(info['length'])
      piece_length = int(info['piece_length'])
      return math.ceil(length/piece_length)

  def getPieceLength(file_path):
    with open(file_path) as json_file:
      data = json.load(json_file)
      info = data['info']
      length = int(info['length'])
      return length

  def getName(file_path):
    with open(file_path) as json_file:
      info = data['info']
      return info['name']


import math

def rec(n):
    if n <= 2:
        return 1
    else:
        return rec(n - 1) + rec(n - 2)

def dynamic(n):
    a = 1
    b = 1
    for i in range(3, n + 1):
        t = a + b
        a = b
        b = t
    return b

def golden_ratio(n):
    f = (1 + math.sqrt(5)) / 2
    return int((math.pow(f, n) / math.sqrt(5)) + 0.5)

if __name__ == '__main__':
    print(rec(13))
    print(dynamic(100))
    print(golden_ratio(100))


import Vertex
import Edge
import WeightedGraph
import pygame

# A group of functions that were redundantly added into the main code, so they were turned into functions instead for
# Clarity

def print_text(window,text,pos):
	myFont = pygame.font.SysFont("Calibri", 20)
	myText = myFont.render(text, 1, (0,0,0))
	window.blit(myText,pos)

def add_to_vertex_list(window,GraphicalVertexList,VertexList,counter,pos,Graph):
	GraphicalVertexList.append([pygame.draw.circle(window, (255, 0, 0),pos, 15),counter])
	VertexList.append(Vertex.Vertex(counter))
	print_text(window,counter,pos)
	counter = chr(ord(counter)+1)
	add_to_Graph(Graph,VertexList[-1])

def add_to_Graph(Graph,vertex):
	Graph.add_vertex(vertex)

def add_to_edge_list(window,GraphicalPathList,GraphicalVertexList,VertexList,PathList,counter1,counter2,directional,start,end,cost,Graph):

									#Node 1                         Node 2                      Directional?
	GraphicalPathList.append([GraphicalVertexList[counter1],GraphicalVertexList[counter2],     directional,
				#LineObject                                           Weight
	pygame.draw.line(window,(0,0,0),start.center,end.center)     ,cost])

	PathList.append(Edge.Edge(VertexList[counter1],VertexList[counter2],int(cost)))
	#VertexList[counter1].add_neighbour(VertexList[counter2])

	Graph.add_edge(VertexList[counter1],VertexList[counter2],int(cost))

	if(directional == False):

		GraphicalPathList.append([GraphicalVertexList[counter2],GraphicalVertexList[counter1],     directional,

		pygame.draw.line(window,(0,0,0),end.center,start.center)     ,cost])

		PathList.append(Edge.Edge(VertexList[counter2],VertexList[counter1],int(cost)))
		#VertexList[counter2].add_neighbour(VertexList[counter1])
		Graph.add_edge(VertexList[counter2],VertexList[counter1],int(cost))

	if(directional == True):
		pygame.draw.circle(window,(255,255,0),GraphicalPathList[-1][3].center,7)
		Graph.directed == True

	print_text(window,cost,GraphicalPathList[-1][3].center)

	pygame.draw.circle(window, (255,0, 0),end.center, 15)#color the end node red again
	print_text(window,GraphicalVertexList[counter2][1],((end.x+7),(end.y+7)))

	pygame.draw.circle(window, (255, 0, 0),start.center, 15)#color the start node red again
	print_text(window,GraphicalVertexList[counter1][1],((start.x+7),(start.y+7)))

def add_neighbour(Graph,vertex1,vertex2,cost):
	Graph.add_edge(vertex1,vertex2,cost)
"""
#file Read/Write Functions. They were not implemented due to
#time constraints.
def read_from_file(self,filename):
	File = open(filename, 'r')

def write_to_file(Graph,filename,GraphicalPathList,GraphicalVertexList):
	File = open(filename, 'w')
	File.write(Graph.vertexList)
	File.write("-")
	File.write(Graph.edgeList)
	File.write("-")
	for Vertex in GraphicalVertexList:
		File.write(Vertex[0]+","+Vertex[1])
	File.Write("-")
	for Path in GraphicalPathList:
		File.write(Path[3])
	File.Write("-")
	File.close()
"""


#!/usr/bin/env python3

import os           # path/file searching, etc
import subprocess   # Subprocesses for each run
import time         # Delay between spawning of runs
import platform     # Linux vs Windows checks
import argparse     # parses command line arguments

def run(threads, processes, directory='.', recursive=True):

    command = 'Sea-Safari.exe'
    if platform.system() == 'Linux':
        command = './Sea-Safari'

    for filename in os.listdir(directory):
        truefile = os.path.join(directory, filename)
        if recursive and os.path.isdir(truefile):
            run(threads, processes, truefile)
            continue
        if filename.endswith(".input") and not filename==('safari.input'):
            arg = os.path.join(directory, filename).replace('.input','')
            run_command = command + " -i " + arg
            print('Running: '+filename)
            process = subprocess.Popen(run_command, shell=True)
            processes.append(process)
            #Increment our counter of running processes
            number = len(processes) + 1
            # If hit number to run, wait for a run to finish, before continuing.
            while number > threads:
                for p in processes:
                    p.poll()
                    if p.returncode != None:
                        processes.remove(p)
                        break
                number = len(processes) + 1
                time.sleep(1)
    return

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("-c", "--count", help="Number of processes")
    parser.add_argument("-d", "--dir", help="Base directory to process")
    args = parser.parse_args()
    txtnum = args.count
    rundir = args.dir
    if txtnum is None:
        txtnum = input("Number of Threads? ")
    if rundir is None:
        rundir = input("Run Directory? ")
    threads = int(txtnum)
    if rundir!='.':
        rundir = os.path.join('.',rundir)
    processes = []
    run(threads, processes, directory=rundir)
    # Wait for all remaining processes to finish before closing.
    for p in processes:
        p.wait()


"""リスト基礎
複数keyを指定してソートする場合
(sorted関数でlambdaを使用)

listのリストデータ

[説明ページ]
https://tech.nkhn37.net/python-list-sort/#i-8
"""
data = [
    [3, 20, "b"],
    [1, 20, "b"],
    [2, 10, "a"],
    [1, 10, "a"],
    [2, 20, "b"],
    [3, 10, "a"],
    [1, 30, "c"],
    [3, 30, "c"],
    [2, 30, "c"],
]

# ===== 複数keyを指定してソートする (sorted関数)
sorted_data = sorted(data, key=lambda d: (d[0], d[1]))
print(f"sorted data: {sorted_data}")


import os
import pandas as pd
import warnings
import numpy as np
import torch
from PIL import Image

from torchvision.datasets import VisionDataset
from torchvision.datasets.folder import default_loader
from torchvision.datasets.utils import check_integrity, extract_archive

from torch.utils.data import DataLoader, Dataset

class NABirds(Dataset):
    """`NABirds <https://dl.allaboutbirds.org/nabirds>`_ Dataset.
        Args:
            root (string): Root directory of the dataset.
            train (bool, optional): If True, creates dataset from training set, otherwise
               creates from test set.
            transform (callable, optional): A function/transform that  takes in an PIL image
               and returns a transformed version. E.g, ``transforms.RandomCrop``
            target_transform (callable, optional): A function/transform that takes in the
               target and transforms it.
            download (bool, optional): If true, downloads the dataset from the internet and
               puts it in root directory. If dataset is already downloaded, it is not
               downloaded again.
    """
    base_folder = 'nabirds/images'

    def __init__(self, root, train=True, transform=None):
        dataset_path = os.path.join(root, 'nabirds')
        self.root = root
        self.loader = default_loader
        self.train = train
        self.transform = transform

        image_paths = pd.read_csv(os.path.join(dataset_path, 'images.txt'),
                                  sep=' ', names=['img_id', 'filepath'])
        image_class_labels = pd.read_csv(os.path.join(dataset_path, 'image_class_labels.txt'),
                                         sep=' ', names=['img_id', 'target'])
        # Since the raw labels are non-continuous, map them to new ones
        self.label_map = get_continuous_class_map(image_class_labels['target'])
        train_test_split = pd.read_csv(os.path.join(dataset_path, 'train_test_split.txt'),
                                       sep=' ', names=['img_id', 'is_training_img'])
        data = image_paths.merge(image_class_labels, on='img_id')
        self.data = data.merge(train_test_split, on='img_id')
        # Load in the train / test split
        if self.train:
            self.data = self.data[self.data.is_training_img == 1]
        else:
            self.data = self.data[self.data.is_training_img == 0]

        # Load in the class data
        self.class_names = load_class_names(dataset_path)
        self.class_hierarchy = load_hierarchy(dataset_path)

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

    def __getitem__(self, idx):
        sample = self.data.iloc[idx]
        path = os.path.join(self.root, self.base_folder, sample.filepath)
        target = self.label_map[sample.target]
        img = self.loader(path)

        if self.transform is not None:
            img = self.transform(img)
        return img, target

def get_continuous_class_map(class_labels):
    label_set = set(class_labels)
    return {k: i for i, k in enumerate(label_set)}

def load_class_names(dataset_path=''):
    names = {}

    with open(os.path.join(dataset_path, 'classes.txt')) as f:
        for line in f:
            pieces = line.strip().split()
            class_id = pieces[0]
            names[class_id] = ' '.join(pieces[1:])

    return names

def load_hierarchy(dataset_path=''):
    parents = {}

    with open(os.path.join(dataset_path, 'hierarchy.txt')) as f:
        for line in f:
            pieces = line.strip().split()
            child_id, parent_id = pieces
            parents[child_id] = parent_id

    return parents


import random

class Pokemon():
    def __init__(self):
        self.startHP = -1
        self.startDef = -1
        self.startAtk = -1
        self.startSpA = -1
        self.startSpD = -1
        self.startSpe = -1
        self.item = "NOPOKEMON"
        self.nick = "NOPOKEMON"
        self.dexName = "NOPOKEMON"
        self.dex = -1
        self.move1 = "NOPOKEMON"
        self.move2 = "NOPOKEMON"
        self.move3 = "NOPOKEMON"
        self.move4 = "NOPOKEMON"
        self.ability = "NOPOKEMON"
        self.shiny = False
        self.gender = "None"
        self.level = 100
        self.happiness = 255
        self.nature = "Jolly"
        #self.position = 1
        self.status = "None"
        self.currentHP = 0
        self.atkStage = 0
        self.defStage = 0
        self.spaStage = 0
        self.spdStage = 0
        self.speStage = 0
        self.accStage = 0
        self.evaStage = 0
        self.critStage = 0
        self.fainted = True
        self.type1 = "NONE"
        self.type2 = "NONE"
        self.curse = False
        self.perishCount = -1
        self.taunt = False
        self.encore = False
        self.move1maxPP = -1
        self.move2maxPP = -1
        self.move3maxPP = -1
        self.move4maxPP = -1
        self.move1currentPP = -1
        self.move2currentPP = -1
        self.move3currentPP = -1
        self.move4currentPP = -1

    def determineAndSetMovesPP(self):
        move1Temp = self.move1.replace(" ", "")
        move1Temp.replace("-", "")
        #print(move1Temp)
        move2Temp = self.move2.replace(" ", "")
        move2Temp.replace("-", "")
        #print(move2Temp)
        move3Temp = self.move3.replace(" ", "")
        move3Temp.replace("-", "")
        #print(move3Temp)
        move4Temp = self.move4.replace(" ", "")
        move4Temp.replace("-", "")
        #print(move4Temp)

        move1func = getattr(Pokemon, move1Temp)
        move2func = getattr(Pokemon, move2Temp)
        move3func = getattr(Pokemon, move3Temp)
        move4func = getattr(Pokemon, move4Temp)

        move1PP = int(move1func(self).split("/")[3])
        #print(str(move1PP))
        self.setMaxPP1(move1PP)
        self.move1currentPP = move1PP

        move2PP = int(move2func(self).split("/")[3])
        #print(move2PP)
        self.setMaxPP2(move2PP)
        self.move2currentPP = move2PP

        move3PP = int(move3func(self).split("/")[3])
        #print(move3PP)
        self.setMaxPP3(move3PP)
        self.move3currentPP = move3PP

        move4PP = int(move4func(self).split("/")[3])
        #print(move4PP)
        self.setMaxPP4(move4PP)
        self.move4currentPP = move4PP

        self.setFainted(False)

    def getMove(self, moveNum):
        if moveNum == 1:
            return self.move1
        if moveNum == 2:
            return self.move2
        if moveNum == 3:
            return self.move3
        if moveNum == 4:
            return self.move4
        return "NULL"

    def getMovePrio(self, moveNum):
        if moveNum == 1:
            self.move1Prio()
        if moveNum == 2:
            self.move2Prio()
        if moveNum == 3:
            self.move3Prio()
        if moveNum == 4:
            self.move4Prio()
        return 0

    def move1Prio(self):
        moveTemp = self.move1.replace(" ", "")
        moveTemp.replace("-", "")
        move1func = getattr(Pokemon, moveTemp)
        return move1func(self).split("/")[0]
    def move2Prio(self):
        moveTemp = self.move2.replace(" ", "")
        moveTemp.replace("-", "")
        move1func = getattr(Pokemon, moveTemp)
        return move1func(self).split("/")[0]
    def move3Prio(self):
        moveTemp = self.move3.replace(" ", "")
        moveTemp.replace("-", "")
        move1func = getattr(Pokemon, moveTemp)
        return move1func(self).split("/")[0]
    def move4Prio(self):
        moveTemp = self.move4.replace(" ", "")
        moveTemp.replace("-", "")
        move1func = getattr(Pokemon, moveTemp)
        return move1func(self).split("/")[0]

    def move1Type(self):
        moveTemp = self.move1.replace(" ", "")
        moveTemp.replace("-", "")
        move1func = getattr(Pokemon, moveTemp)
        return move1func(self).split("/")[1]

    def move2Type(self):
        moveTemp = self.move2.replace(" ", "")
        moveTemp.replace("-", "")
        move1func = getattr(Pokemon, moveTemp)
        return move1func(self).split("/")[1]

    def move3Type(self):
        moveTemp = self.move3.replace(" ", "")
        moveTemp = moveTemp.replace("-", "")
        move1func = getattr(Pokemon, moveTemp)
        return move1func(self).split("/")[1]

    def move4Type(self):
        #print(self.move4)
        moveTemp = self.move4.replace(" ", "")
        #print(moveTemp)
        moveTemp.replace("-", "")
        #print(moveTemp)
        movefunc = getattr(Pokemon, moveTemp)
        return movefunc(self).split("/")[1]

    def setMaxPP1(self, amt):
        self.move1maxPP = amt
    def setMaxPP2(self, amt):
        self.move2maxPP = amt
    def setMaxPP3(self, amt):
        self.move3maxPP = amt
    def setMaxPP4(self, amt):
        self.move4maxPP = amt

    def setCurrentPP1(self, amt):
        self.move1currentPP = amt
    def setCurrentPP2(self, amt):
        self.move2currentPP = amt
    def setCurrentPP3(self, amt):
        self.move3currentPP = amt
    def setCurrentPP4(self, amt):
        self.move4currentPP = amt
    def setType1(self, newType):
        self.type1 = newType
    def setType2(self, newType):
        self.type2 = newType
    def setFainted(self, newVal):
        self.fainted = newVal
    def getFainted(self):
        return self.fainted
    def setNick(self, newNick):
        self.nick = newNick
    def setAtkStage(self, stage):
        self.atkStage = stage
    def setDefStage(self, stage):
        self.defStage = stage
    def setSpaStage(self, stage):
        self.spaStage = stage
    def setSpdStage(self, stage):
        self.spdStage = stage
    def setSpeStage(self, stage):
        self.speStage = stage
    def setAccStage(self, stage):
        self.accStage = stage
    def setEvaStage(self, stage):
        self.evaStage = stage
    def setCritStage(self, stage):
        self.critStage = stage
    def changeStage(self, stat, stage):
        if stat == 1:
            self.atkStage += stage
            if self.atkStage >= 6:
                self.atkStage = 6
            if self.atkStage <= -6:
                self.atkStage = -6
        if stat == 2:
            self.defStage += stage
            if self.defStage >= 6:
                self.defStage = 6
            if self.defStage <= -6:
                self.defStage = -6
        if stat == 3:
            self.spaStage += stage
            if self.spaStage >= 6:
                self.spaStage = 6
            if self.spaStage <= -6:
                self.spaStage = -6
        if stat == 4:
            self.spdStage += stage
            if self.spdStage >= 6:
                self.spdStage = 6
            if self.spdStage <= -6:
                self.spdStage = -6
        if stat == 5:
            self.speStage += stage
            if self.speStage >= 6:
                self.speStage = 6
            if self.speStage <= -6:
                self.speStage = -6
        if stat == 6:
            self.accStage += stage
            if self.accStage >= 6:
                self.accStage = 6
            if self.accStage <= -6:
                self.accStage = -6
        if stat == 7:
            self.evaStage += stage
            if self.evaStage >= 6:
                self.evaStage = 6
            if self.evaStage <= -6:
                self.evaStage = -6
        if stat == 8:
            self.critStage += stage
            if self.critStage >= 4:
                self.critStage = 4
            if self.critStage <= 0:
                self.critStage = 0

    def setDex(self, newDex):
        self.dex = newDex
    def setStatus(self, newStat):
        self.status = newStat
    def setPosition(self, pos):
        self.position = pos
    def getDex(self):
        return self.dex
    def setCurrentHP(self, hp):
        self.currentHP = hp
    def setName(self, newName):
        self.dexName = newName
    def setItem(self, newItem):
        self.item = newItem
    def setAbility(self, newAbil):
        self.ability = newAbil
    def setGender(self, newGender):
        self.gender = newGender
    def getGender(self):
        return self.gender
    def setLevel(self, newLevel):
        self.level = newLevel
    def setShiny(self, shinyness):
        self.shiny = shinyness
    def getShiny(self):
        return self.shiny
    def setHappiness(self, newHappiness):
        self.happiness = newHappiness
    def setHP(self, base, iv, ev):
        self.startHP = int(0.01 * (2 * base + iv + int(0.25 * ev)) * self.level) + self.level + 10
    def setHPStat(self, hp):
        self.startHP = hp
    def setNature(self, newNature):
        self.nature = newNature
    def getName(self):
        return self.dexName
    def setStats(self, base, ivSpread, evSpread):
        self.startAtk = (int(0.01 * (2 * int(base[0]) + ivSpread[1] + int(0.25 * evSpread[1])) * self.level) + 5)
        self.startDef = (int(0.01 * (2 * int(base[1]) + ivSpread[2] + int(0.25 * evSpread[2])) * self.level) + 5)
        self.startSpA = (int(0.01 * (2 * int(base[2]) + ivSpread[3] + int(0.25 * evSpread[3])) * self.level) + 5)
        self.startSpD = (int(0.01 * (2 * int(base[3]) + ivSpread[4] + int(0.25 * evSpread[4])) * self.level) + 5)
        self.startSpe = (int(0.01 * (2 * int(base[4]) + ivSpread[5] + int(0.25 * evSpread[5])) * self.level) + 5)
        #nature increases
        if self.nature == "Lonely" or self.nature == "Brave" or self.nature == "Adamant" or self.nature == "Naughty":
            self.startAtk = int(self.startAtk * 1.1)
        if self.nature == "Bold" or self.nature == "Impish" or self.nature == "Lax" or self.nature == "Relaxed":
            self.startDef = int(self.startDef * 1.1)
        if self.nature == "Timid" or self.nature == "Hasty" or self.nature == "Jolly" or self.nature == "Naive":
            self.startSpe = int(self.startSpe * 1.1)
        if self.nature == "Modest" or self.nature == "Mild" or self.nature == "Quiet" or self.nature == "Rash":
            self.startSpA = int(self.startSpA * 1.1)
        if self.nature == "Calm" or self.nature == "Gentle" or self.nature == "Sassy" or self.nature == "Careful":
            self.startSpD = int(self.startSpD * 1.1)
        #nature decreases
        if self.nature == "Bold" or self.nature == "Modest" or self.nature == "Calm" or self.nature == "Timid":
            self.startAtk = int(self.startAtk * 0.9)
        if self.nature == "Lonely" or self.nature == "Gentle" or self.nature == "Mild" or self.nature == "Hasty":
            self.startDef = int(self.startDef * 0.9)
        if self.nature == "Brave" or self.nature == "Relaxed" or self.nature == "Quiet" or self.nature == "Sassy":
            self.startSpe = int(self.startSpe * 0.9)
        if self.nature == "Adamant" or self.nature == "Impish" or self.nature == "Careful" or self.nature == "Jolly":
            self.startSpA = int(self.startSpA * 0.9)
        if self.nature == "Naughty" or self.nature == "Lax" or self.nature == "Rash" or self.nature == "Naive":
            self.startSpD = int(self.startSpD * 0.9)

    def setAttack(self, attack):
        self.startAtk = attack

    def setDefense(self, defense):
        self.startDef = defense

    def setSPA(self, spa):
        self.startSpA = spa

    def setSPD(self, spd):
        self.startSpD = spd

    def setSpe(self, spe):
        self.startSpe = spe

    def setMove(self, moveNum, moveName):
        if moveNum == 1:
            self.move1 = moveName
        elif moveNum == 2:
            self.move2 = moveName
        elif moveNum == 3:
            self.move3 = moveName
        elif moveNum == 4:
            self.move4 = moveName
        else:
            print("invalid move number")

    def curseEffect(self, val):
        self.curse = val

    #"Prio/Type/statusPhysicalSpecial/pp/power/Acc/atkChange/defChange/spaChange/spdChange/speChange/accChange/evaChange/atkChangeOpp/defChangeOpp/spaChangeOpp/spdChangeOpp/speChangeOpp/accChangeOpp/evaChangeOpp/StatusSelf/StatusOpp/extraEffect/Contact/Charging/Recharge/protected/reflectable/snatchable/mirrorMove/punch/sound/noGrav/Defrosts/Heals/ignSub/powder/Jaw/pulse/ballistic/mental/Dance"

    # def Absorb():

    '''
    Acid
    Acid Armor
    Acid Spray
    Acrobatics
    Acupressure
    Aerial Ace
    Aeroblast
    After You
    Agility
    Air Cutter
    Air Slash
    Ally Switch
    Amnesia
    '''
    def AncientPower(self):
        if random.randint(0,9) == 0:
            return "0/ROCK/Special/8/60/100/1/1/1/1/1/0/0/0/0/0/0/0/0/0/0/0/-/-/-/0/0/0/1/0/0/1/0/0/0/0/0/0/0/0/0/0/0/0"
        else:
            return "0/ROCK/Special/8/60/100/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/-/-/-/0/0/0/1/0/0/1/0/0/0/0/0/0/0/0/0/0/0/0"
    '''
    Aqua Jet
    Aqua Ring
    Aqua Tail
    Arm Thrust
    Aromatherapy
    Assist
    Assurance
    Astonish
    Attack Order
    Attract
    Aura Sphere
    Aurora Beam
    Autotomize
    Avalanche
    Barrage
    Barrier
    '''
    def BatonPass(self):
        return "0/NORMAL/Status/64/-/-/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/-/-/BatonPass/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0"
    '''
    Beat Up
    Belly Drum
    Bestow
    Bide
    Bind
    Bite
    Blast Burn
    Blaze Kick
    Blizzard
    Block
    Blue Flare
    '''
    def BodySlam(self):
        if random.randint(0,9) <= 2:
            return "0/NORMAL/Physical/24/85/100/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/-/PARALYZED/-/1/0/0/1/0/0/1/0/0/0/0/0/0/0/0/0/0/0/0"
        else:
            return "0/NORMAL/Physical/24/85/100/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/-/-/-/1/0/0/1/0/0/1/0/0/0/0/0/0/0/0/0/0/0/0"
    '''
    Bolt Strike
    Bone Club
    Bone Rush
    Bonemerang
    Bounce
    Brave Bird
    Brick Break
    Brine
    Bubble
    BubbleBeam
    Bug Bite
    Bug Buzz
    '''
    def BulkUp(self):
        return "0/FIGHTING/Status/32/-/-/1/1/0/0/0/0/0/0/0/0/0/0/0/0/0/0/-/-/-/0/0/0/0/0/1/0/0/0/0/0/0/0/0/0/0/0/0/0"
    '''
    Bulldoze
    Bullet Punch
    Bullet Seed
    Calm Mind
    Camouflage
    Captivate
    Charge
    Charge Beam
    Charm
    Chatter
    Chip Away
    Circle Throw
    Clamp
    Clear Smog
    Close Combat
    Coil
    Comet Punch
    Confuse Ray
    Confusion
    Constrict
    Conversion
    Conversion 2
    Copycat
    Cosmic Power
    Cotton Guard
    Cotton Spore
    Counter
    Covet
    Crabhammer
    Cross Chop
    Cross Poison
    '''
    def Crunch(self):
        if random.randint(0,4) == 0:
            return "0/DARK/Physical/24/80/100/0/0/0/0/0/0/0/0/0/-1/0/0/0/0/0/0/-/-/-/1/0/0/1/0/0/1/0/0/0/0/0/0/0/1/0/0/0/0"
        else:
            return "0/DARK/Physical/24/80/100/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/-/-/-/1/0/0/1/0/0/1/0/0/0/0/0/0/0/1/0/0/0/0"
    '''
    Crush Claw
    Crush Grip'''

    def Curse(self):
        if self.type1 == "GHOST" or self.type2 == "GHOST":
            return "0/GHOST/Status/16/-/-/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/-/Curse/selfCurseDmg/0/0/0/0/0/0/0/0/0/0/0/0/1/0/0/0/0/0/0"
        else:
            return "0/GHOST/Status/16/-/-/1/1/0/0/-1/0/0/0/0/0/0/0/0/0/0/0/-/-/-/0/0/0/0/0/0/0/0/0/0/0/0/1/0/0/0/0/0/0"

    '''
    Cut
    '''
    def DarkPulse(self):
        if random.randint(0,4) == 0:
            return "0/DARK/Special/24/80/100/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/-/-/Flinch/0/0/0/1/0/0/1/0/0/0/0/0/0/0/0/1/0/0/0"
        else:
            return "0/DARK/Special/24/80/100/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/-/-/-/0/0/0/1/0/0/1/0/0/0/0/0/0/0/0/1/0/0/0"
    '''
    Dark Void
    Defend Order
    Defense Curl
    Defog
    Destiny Bond
    Detect
    Dig
    Disable
    Discharge
    Dive
    Dizzy Punch
    Doom Desire
    Double Hit
    Double Kick
    Double Team
    '''
    def DoubleEdge(self):
        return "0/NORMAL/Pysical/24/120/100/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/-/-/ThirdRecoil/1/0/0/1/0/0/1/0/0/0/0/0/0/0/0/0/0/0/0"
    '''
    DoubleSlap
    Draco Meteor
    Dragon Claw
    '''
    def DragonDance(self):
        return "0/DRAGON/Status/32/-/-/1/0/0/0/1/0/0/0/0/0/0/0/0/0/0/0/-/-/-/0/0/0/0/0/1/0/0/0/0/0/0/0/0/0/0/0/0/0"
    '''
    Dragon Pulse
    Dragon Rage
    Dragon Rush
    Dragon Tail
    DragonBreath
    Drain Punch
    Dream Eater
    Drill Peck
    Drill Run
    Dual Chop
    DynamicPunch
    Earth Power
    Earthquake
    Echoed Voice
    Egg Bomb
    Electro Ball
    Electroweb
    Embargo
    Ember
    Encore
    Endeavor
    Endure
    Energy Ball
    Entrainment
    Eruption
    Explosion
    Extrasensory
    ExtremeSpeed
    Facade
    Faint Attack
    Fake Out
    Fake Tears
    False Swipe
    FeatherDance
    Feint
    Fiery Dance
    Final Gambit
    Fire Blast
    Fire Fang
    Fire Pledge
    Fire Punch
    Fire Spin
    Fissure
    Flail
    Flame Burst
    Flame Charge
    Flame Wheel
    Flamethrower
    Flare Blitz
    Flash
    Flash Cannon
    Flatter
    Fling
    Fly
    Focus Blast
    Focus Energy
    Focus Punch
    Follow Me
    Force Palm
    Foresight
    Foul Play
    Freeze Shock
    Frenzy Plant
    Frost Breath
    Frustration
    Fury Attack
    Fury Cutter
    Fury Swipes
    Fusion Bolt
    Fusion Flare
    Future Sight
    Gastro Acid
    Gear Grind'''
    def GigaDrain(self):
        return "0/GRASS/Special/16/75/100/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/-/-/GigaDrain/0/0/0/1/0/0/1/0/0/0/0/1/0/0/0/0/0/0/0"

    '''
    Giga Impact
    Glaciate
    Glare
    Grass Knot
    Grass Pledge
    GrassWhistle
    Gravity
    Growl
    Growth
    Grudge
    Guard Split
    Guard Swap
    Guillotine
    Gunk Shot
    Gust
    Gyro Ball
    Hail
    Hammer Arm
    Harden
    Haze
    Head Charge
    Head Smash
    Headbutt
    Heal Bell
    Heal Block
    Heal Order
    Heal Pulse
    Healing Wish
    Heart Stamp
    Heart Swap
    Heat Crash
    Heat Wave
    Heavy Slam
    Helping Hand
    Hex
    Hi Jump Kick
    Hidden Power
    Hone Claws
    Horn Attack
    Horn Drill
    Horn Leech
    Howl
    Hurricane
    Hydro Cannon
    Hydro Pump
    Hyper Beam
    Hyper Fang
    Hyper Voice
    Hypnosis
    Ice Ball
    Ice Beam
    Ice Burn
    Ice Fang
    Ice Punch
    Ice Shard
    Icicle Crash
    Icicle Spear
    Icy Wind
    Imprison
    Incinerate
    Inferno
    Ingrain
    Iron Defense
    Iron Head
    Iron Tail
    Judgement
    Jump Kick
    Karate Chop
    Kinesis
    Knock Off
    Last Resort
    Lava Plume
    Leaf Blade
    Leaf Storm
    Leaf Tornado
    Leech Life'''
    def LeechSeed(self):
        return "0/GRASS/Status/16/-/90/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/-/Seeded/-/0/0/0/1/1/0/1/0/0/0/0/0/0/0/0/0/0/0/0"

    '''
    Leer
    Lick
    Light Screen
    Lock-On
    Lovely Kiss
    Low Kick
    Low Sweep
    Lucky Chant
    Lunar Dance
    Luster Purge
    Mach Punch
    Magic Coat
    Magic Room
    Magical Leaf
    Magma Storm
    Magnet Bomb
    Magnet Rise
    Magnitude
    Me First
    Mean Look
    Meditate
    Mega Drain
    Mega Kick
    Mega Punch
    Megahorn
    Memento
    Metal Burst
    Metal Claw
    Metal Sound
    Meteor Mash
    Metronome
    Milk Drink
    Mimic
    Mind Reader
    Minimize
    Miracle Eye
    Mirror Coat
    Mirror Move
    Mirror Shot
    Mist
    Mist Ball
    Moonlight
    Morning Sun
    Mud Bomb
    Mud Shot
    Mud Sport
    Mud-Slap
    Muddy Water
    Nasty Plot
    Natural Gift
    Nature Power
    Needle Arm
    Night Daze
    Night Shade
    Night Slash
    Nightmare
    Octazooka
    Odor Sleuth
    '''
    def OminousWind(self):
        if random.randint(0,9) == 0:
            return "0/GHOST/Special/8/60/100/1/1/1/1/1/0/0/0/0/0/0/0/0/0/0/0/-/-/-/0/0/0/1/0/0/1/0/0/0/0/0/0/0/0/0/0/0/0"
        else:
            return "0/GHOST/Special/8/60/100/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/-/-/-/0/0/0/1/0/0/1/0/0/0/0/0/0/0/0/0/0/0/0"
    '''
    Outrage
    Overheat
    Pain Split
    Pay Day
    Payback
    Peck
    Perish Song
    Petal Dance
    Pin Missile
    Pluck
    Poison Fang
    Poison Gas
    Poison Jab
    Poison Sting
    Poison Tail
    PoisonPowder
    Pound
    Powder Snow
    Power Gem
    Power Split
    Power Swap
    Power Trick'''
    def PowerWhip(self):
        return "0/GRASS/Physical/16/120/85/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/-/-/-/1/0/0/1/0/0/1/0/0/0/0/0/0/0/0/0/0/0/0"

    '''
    Present
    Protect
    Psybeam
    Psych Up
    Psychic
    Psycho Boost
    Psycho Cut
    Psycho Shift
    Psyshock
    Psystrike
    Psywave
    Punishment
    Pursuit
    Quash
    Quick Attack
    Quick Guard
    Quiver Dance
    Rage
    Rage Powder
    Rain Dance
    Rapid Spin
    Razor Leaf
    Razor Shell
    Razor Wind
    Recover
    Recycle
    Reflect
    Reflect Type
    Refresh
    Relic Song
    Rest
    Retaliate
    Return
    Revenge
    Reversal
    Roar
    Roar of Time
    Rock Blast
    Rock Climb
    Rock Polish
    Rock Slide
    Rock Smash
    Rock Throw
    Rock Tomb
    Rock Wrecker
    Role Play
    Rolling Kick
    Rollout
    Roost
    Round
    Sacred Fire
    Sacred Sword
    Safeguard
    Sand Tomb
    Sand-Attack
    Sandstorm
    Scald
    Scary Face
    Scratch
    Screech
    Searing Shot
    Secret Power
    Secret Sword
    Seed Bomb
    Seed Flare
    Seismic Toss
    Selfdestruct
    Shadow Ball
    Shadow Claw
    Shadow Force
    Shadow Punch
    Shadow Sneak
    Sharpen
    Sheer Cold
    Shell Smash
    Shift Gear
    Shock Wave
    Signal Beam
    '''
    def SilverWind(self):
        if random.randint(0,9) == 0:
            return "0/BUG/Special/8/60/100/1/1/1/1/1/0/0/0/0/0/0/0/0/0/0/0/-/-/-/0/0/0/1/0/0/1/0/0/0/0/0/0/0/0/0/0/0/0"
        else:
            return "0/BUG/Special/8/60/100/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/-/-/-/0/0/0/1/0/0/1/0/0/0/0/0/0/0/0/0/0/0/0"
    '''
    Simple Beam
    Sing
    Sketch
    Skill Swap
    Skull Bash
    Sky Attack
    Sky Drop
    Sky Uppercut
    Slack Off
    Slam
    Slash
    Sleep Powder
    Sleep Talk
    Sludge
    Sludge Bomb
    Sludge Wave
    Smack Down
    SmellingSalt
    Smog
    SmokeScreen
    Snarl
    Snatch
    Snore
    Soak
    Softboiled
    SolarBeam
    SonicBoom
    Spacial Rend
    Spark
    Spider Web
    Spike Cannon
    Spikes
    Spit Up
    Spite
    Splash
    Spore
    Stealth Rock
    Steamroller
    Steel Wing
    Stockpile
    Stomp
    Stone Edge
    Stored Power
    Storm Throw
    Strength
    String Shot
    Struggle
    Struggle Bug
    Stun Spore
    Submission
    Substitute
    Sucker Punch
    Sunny Day
    Super Fang
    Superpower
    Supersonic
    Surf
    Swagger
    Swallow
    Sweet Kiss
    Sweet Scent
    Swift
    Switcheroo
    Swords Dance
    Synchronoise
    Synthesis
    Tackle
    Tail Glow
    Tail Slap
    Tail Whip
    Tailwind
    Take Down
    Taunt
    Techno Blast
    Teeter Dance
    Telekinesis
    Teleport
    Thief
    Thrash
    Thunder
    Thunder Fang
    '''
    def ThunderWave(self):
        return "0/ELECTRIC/Status/32/-/90/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/-/PARALYZED/-/0/0/0/1/1/0/1/0/0/0/0/0/0/0/0/0/0/0/0"
    '''
    ThunderPunch
    ThunderShock
    Thunderbolt
    Tickle
    Torment
    Toxic
    Toxic Spikes
    Transform
    Tri Attack
    Trick
    Trick Room
    Triple Kick
    Trump Card
    Twineedle
    Twister
    U-turn
    Uproar
    V-create
    Vacuum Wave
    Venoshock
    ViceGrip
    Vine Whip
    Vital Throw
    Volt Switch
    Volt Tackle
    Wake-Up Slap
    Water Gun
    Water Pledge
    Water Pulse
    Water Sport
    Water Spout
    Waterfall
    Weather Ball
    Whirlpool
    Whirlwind
    Wide Guard
    Wild Charge
    Will-O-Wisp
    Wing Attack
    Wish
    Withdraw
    Wonder Room
    Wood Hammer
    Work Up
    Worry Seed
    Wrap
    Wring Out
    X-Scissor
    Yawn
    Zap Cannon
    Zen Headbutt '''

def teamString(team):
    ans = ""
    for mon in team:
        ans += str(mon.startHP) + "/"
        ans += str(mon.startAtk) + "/"
        ans += str(mon.startDef) + "/"
        ans += str(mon.startSpA) + "/"
        ans += str(mon.startSpD) + "/"
        ans += str(mon.startSpe) + "/"
        ans += mon.item + "/"
        ans += mon.nick + "/"
        ans += mon.dexName + "/"
        ans += str(mon.dex) + "/"
        ans += mon.move1 + "/"
        ans += mon.move2 + "/"
        ans += mon.move3 + "/"
        ans += mon.move4 + "/"
        ans += mon.ability + "/"
        if (mon.shiny):
            ans += "True" + "/"
        else:
            ans += "False" + "/"
        ans += mon.gender + "/"
        ans += str(mon.level) + "/"
        ans += str(mon.happiness) + "/"
        ans += mon.nature + "/"
        ans += mon.status + "/"
        ans += str(mon.currentHP) + "/"
        ans += str(mon.atkStage) + "/"
        ans += str(mon.defStage) + "/"
        ans += str(mon.spaStage) + "/"
        ans += str(mon.spdStage) + "/"
        ans += str(mon.speStage) + "/"
        ans += str(mon.accStage) + "/"
        ans += str(mon.evaStage) + "/"
        #print(mon.fainted)
        if (mon.fainted):
            ans += "True" + "/"
        else:
            ans += "False" + "/"
        ans += mon.type1 + "/"
        ans += mon.type2 + "/"
        ans += str(mon.curse) + "/"
        ans += str(mon.move1maxPP) + "/"
        ans += str(mon.move2maxPP) + "/"
        ans += str(mon.move3maxPP) + "/"
        ans += str(mon.move4maxPP) + "/"
        ans += str(mon.move1currentPP) + "/"
        ans += str(mon.move2currentPP) + "/"
        ans += str(mon.move3currentPP) + "/"
        ans += str(mon.move4currentPP) + "/"
        ans += str(mon.critStage) + "\n"
    return ans

def teamStringSplit(teams):
    return teams.split("//split//")

def teamsStringCombine(team1, team2):
    return team1 + "//split//" + team2

def teamUnstring(teamStringForm):

    pokemon1 = Pokemon()
    pokemon2 = Pokemon()
    pokemon3 = Pokemon()
    pokemon4 = Pokemon()
    pokemon5 = Pokemon()
    pokemon6 = Pokemon()
    ans = [pokemon1, pokemon2, pokemon3, pokemon4, pokemon5, pokemon6]
    #print(teamStringForm)
    splitByMon = teamStringForm.split("\n")
    #print(splitByMon)
    i = 0
    for mon in ans:
        slashed = splitByMon[i].split("/")
        mon.setHPStat(int(slashed[0]))
        mon.setAttack(int(slashed[1]))
        mon.setDefense(int(slashed[2]))
        mon.setSPA(int(slashed[3]))
        mon.setSPD(int(slashed[4]))
        mon.setSpe(int(slashed[5]))
        mon.setItem(slashed[6])
        mon.setNick(slashed[7])
        mon.setName(slashed[8])
        mon.setDex(int(slashed[9]))
        mon.setMove(1, slashed[10])
        mon.setMove(2, slashed[11])
        mon.setMove(3, slashed[12])
        mon.setMove(4, slashed[13])
        mon.setAbility(slashed[14])
        mon.setShiny("True" == (slashed[15]))
        mon.setGender(slashed[16])
        mon.setLevel(int(slashed[17]))
        mon.setHappiness(int(slashed[18]))
        mon.setNature(slashed[19])
        mon.setStatus(slashed[20])
        mon.setCurrentHP(int(slashed[21]))
        mon.setAtkStage(int(slashed[22]))
        mon.setDefStage(int(slashed[23]))
        mon.setSpaStage(int(slashed[24]))
        mon.setSpdStage(int(slashed[25]))
        mon.setSpeStage(int(slashed[26]))
        mon.setAccStage(int(slashed[27]))
        mon.setEvaStage(int(slashed[28]))
        if slashed[29] == "True":
            mon.setFainted(True)
        else:
            mon.setFainted(False)
        mon.setType1(slashed[30])
        mon.setType2(slashed[31])
        mon.curseEffect(slashed[32])
        mon.setMaxPP1(slashed[33])
        mon.setMaxPP2(slashed[34])
        mon.setMaxPP3(slashed[35])
        mon.setMaxPP4(slashed[36])
        mon.setCurrentPP1(slashed[37])
        mon.setCurrentPP2(slashed[38])
        mon.setCurrentPP3(slashed[39])
        mon.setCurrentPP4(slashed[40])
        mon.setCritStage(int(slashed[41]))

        i += 1
    return ans


from crome_cgg.case_studies.repair.goals import goals
from crome_cgg.case_studies.repair.world import world
from crome_cgg.cgg import Cgg, Link
from crome_contracts.contract import Contract
from crome_cgg.goal import Goal
from crome_cgg.goal.operations.composition import g_composition
from crome_cgg.goal.operations.quotient import g_quotient
from crome_cgg.library import Library
from crome_logic.patterns.robotic_movement import Patrolling
from crome_logic.specification.temporal import LTL

w = world

cgg = Cgg(goals)

print(cgg)

l1 = Goal(
    id="patrol_l1_l2",
    description="Keep visiting l1 and l2",
    contract=Contract(LTL(Patrolling(["l1", "l2"]), w.typeset)),
    world=w,
)

l2 = Goal(
    id="patrol_l1_l2_l3_l4",
    description="Keep visiting l1 and l2",
    contract=Contract(LTL(Patrolling(["l1", "l2", "l3", "l4"]), w.typeset)),
    world=w,
)

library = Library({l1, l2})

leaves = cgg.leaves

candidate_goals = set()
for goal in leaves:
    if library.covers(goal):
        candidate_goals.add(goal)
print(
    f"Candidate goals which are covered by the library:\n{[g.id for g in list(candidate_goals)]}"
)

refined_goals = set()

for goal in leaves:
    refinement = library.search_refinement(goal)
    if refinement is not None:
        print(f"{refinement.id}\trefines\t{goal.id}")
        """We attach the refinement to the existing goal"""
        cgg.add_edge(goal, refinement, Link.refinement)
        refined_goals.add(goal)

print(f"There are {len(refined_goals)} goals refined")

print(
    f"There are still {len(candidate_goals - refined_goals)} goals that are covered by the library "
    f"but are have no refinement"
)

candidate_goals = set()
for goal in leaves - refined_goals:
    if library.covers(goal):
        candidate_goals.add(goal)

print(
    f"Candidate goals which are covered by the library:\n{[g.id for g in list(candidate_goals)]}"
)
leaves_dict = cgg.leaves_dict

print(f"Library goal '{l2.id}' covers CGG leaf '{leaves_dict['night_patrolling'].id}'")
assert not l2 <= leaves_dict["night_patrolling"]

quotient = g_quotient(l2, leaves_dict["night_patrolling"])
print(f"The quotient is: \n'{quotient}'")

composition = g_composition({quotient, leaves_dict["night_patrolling"]})
print(f"Their composition is: \n'{composition}'")

assert composition <= leaves_dict["night_patrolling"]
print(
    f"Library goal '{l2.id}' composed with the quotient refines the CGG leaf '{leaves_dict['night_patrolling'].id}'"
)

print("Searching for refinements of the quotient...")
print("No refinement has been found...")

print(
    "Modifying existing goal of CGG such that the current library goal can refine it, using separation and merging"
)


import tensorflow as tf
from  sklearn.datasets import load_boston

data = load_boston()

import pandas as pd
df = pd.DataFrame(data.data)

df_ = pd.DataFrame(data.target)
df__ =pd.concat([df,df_],axis=1)
print(df__)

model =tf.keras.Sequential()
model.add(tf.keras.layers.Dense(10,input_shape=(13,),activation=tf.keras.activations.relu))
model.add(tf.keras.layers.Dense(5,activation=tf.keras.activations.relu))
model.add(tf.keras.layers.Dense(1))

'''

梯度衰减
https://blog.csdn.net/Light2077/article/details/106629697?utm_medium=distribute.pc_relevant.none-task-blog-baidujs-1

  return initial_learning_rate * decay_rate ^ (step / decay_steps)

'''
# 学习率衰减
exponential_decay = tf.keras.optimizers.schedules.ExponentialDecay(
                        initial_learning_rate=0.1, decay_steps=1000, decay_rate=0.96,staircase=True)

model.compile(optimizer=tf.keras.optimizers.Adam(exponential_decay),loss=tf.keras.losses.mse)
history = model.fit(data.data,data.target,epochs=300)

pre = model.predict(df__.iloc[0:10,0:-1])

print(pre)

print(df__.iloc[0:10,-1])