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

"""
Simulate the "Abbey of crime" environment.

Each episode is making a single action (doing nothing is an action) .
"""

# core modules
import random
import math
import json
import time
import datetime
import os
from pathlib import Path
from threading import Thread
import gzip
import shutil

# 3rd party modules
import gym
import numpy as np
from gym import spaces
from google.cloud import storage

import logging

# AbadIA2 dependencies
import requests

def get_chance(x):
    """Get probability that a banana will be sold at price x."""
    e = math.exp(1)
    return (1.0 + e) / (1. + math.exp(x + 1))

class AbadiaEnv2(gym.Env):
    """
    Define a Abadia2 environment.

    The environment defines which actions can be taken at which point and
    when the agent receives which reward.
    """

    def __init__(self):
        self.__version__ = "0.0.7"
        print("AbadiaEnv2 - Version {}".format(self.__version__))

        self.url    = "http://localhost:4477"
        self.server = "http://localhost"
        self.port   = "4477"
        self.num_episodes   = 100
        self.num_steps      = 1500
        self.gsBucket       = None

        self.gameName       = ""
        self.actionsName    = ""
        self.checkpointName = None
        self.modelName      = None
        self.valueModelName = None
        self.initValueModelName = None
        self.dump_path      = "games/now/"
        self.gameId = datetime.datetime.now().strftime('%y%m%d_%H%M%S_%f')
        self.checkpointSec  = 1
        self.storage_client = None
        self.eventsGame     = []
        self.eventsAction   = []
        self.totalReward    = 0.0
        self.verbose        = 0
        self.playing        = False

        # Define what the agent can do
        # 0 -> STEP FORWARD
        # 1 -> RIGHT
        # 2 -> LEFT
        # 3 -> DOWN
        # 4 -> GET

        self.action_space = spaces.Discrete(9)

        # json from the dump state of the episode

        self.json_dump = {}

        self.action_mode = 1

        self.actions_list_2 = ("abadIA/game/current/actions/UP",
                             "abadIA/game/current/actions/RIGHT",
                             "abadIA/game/current/actions/LEFT",
                             "abadIA/game/current/actions/DOWN",
                             "cmd/N",
                             "cmd/_"
                             )
        self.actions_list = ("N", "NE", "E", "SE", "S", "SW", "W", "NW", "NOP")

        self.obsequium = -1
        self.reward = 0
        self.porcentaje = -1
        self.haFracasado = False
        self.prevPantalla = -1
        self.rejilla = []
        self.prev_ob = dict()
        self.estaGuillermo= False
        self.room = np.zeros([20,20,3], np.int)

        self.curr_step = -1
        self.is_game_done = False

        self.Personajes = {
            "Guillermo":  {},
            "Adso":       {},
            "Abad":       {},
            "Malaquias":  {},
            "Berengario": {},
            "Severino":   {},
            "Jorge":      {},
            "Bernardo":   {}
        }

        self.listaPersonajes = ("Guillermo", "Adso", "Abad", "Malaquias", "Berengario",
            "Severino", "Jorge", "Bernardo")

        self.Visited = np.zeros([512, 512])

        # Observation is the position of Guillermo and the information of the room
        X = np.array([0, 256])
        Y = np.array([0, 256])
        O = np.array([0,   4])

        high = np.array([np.inf] * 15)  # useful range is -1 .. +1, but spikes can be higher
        self.observation_space = spaces.Box(-high, high)

        # Store what the agent tried
        self.curr_episode = -1
        self.action_episode_memory = []

        now = datetime.datetime.now()
        self._seed(time.mktime(now.timetuple()))
        logging.basicConfig(format='%(asctime)s:%(levelname)s:%(message)s', datefmt='%d-%m-%y %H:%M:%S',
                            level=logging.INFO)

        # helper to normalize paths to positions
        #   1
        # 2   0
        #   3

        self.path2Pos = {
            "0N": "LEFT:UP:UP",
            "1N": "UP:UP",
            "2N": "RIGHT:UP:UP",
            "3N": "RIGHT:RIGHT:UP:UP",

            "0NE": "UP:UP:LEFT:UP:UP",
            "1NE": "UP:UP:RIGHT:UP:UP",
            "2NE": "RIGHT:UP:UP:RIGHT:UP:UP",
            "3NE": "RIGHT:RIGHT:UP:UP:RIGHT:UP:UP",

            "0E": "UP:UP",
            "1E": "RIGHT:UP:UP",
            "2E": "RIGHT:RIGHT:UP:UP",
            "3E": "LEFT:UP:UP",

            "0SE": "UP:UP:RIGHT:UP:UP",
            "1SE": "RIGHT:UP:UP:RIGHT:UP:UP",
            "2SE": "RIGHT:RIGHT:UP:UP:RIGHT:UP:UP",
            "3SE": "UP:UP:LEFT:UP:UP",

            "0S": "RIGHT:UP:UP",
            "1S": "RIGHT:RIGHT:UP:UP",
            "2S": "LEFT:UP:UP",
            "3S": "UP:UP",

            "0SW": "RIGHT:UP:UP:RIGHT:UP:UP",
            "1SW": "RIGHT:RIGHT:UP:UP:RIGHT:UP:UP",
            "2SW": "UP:UP:LEFT:UP:UP",
            "3SW": "UP:UP:RIGHT:UP:UP",

            "0W": "RIGHT:RIGHT:UP:UP",
            "1W": "LEFT:UP:UP",
            "2W": "UP:UP",
            "3W": "RIGHT:UP:UP",

            "0NW": "LEFT:UP:UP:LEFT:UP:UP",
            "1NW": "UP:UP:LEFT:UP:UP",
            "2NW": "UP:UP:RIGHT:UP:UP",
            "3NW": "RIGHT:RIGHT:UP:UP:RIGHT:UP:UP"

        }

    def set_url(self):
        self.url = self.server + ":" + self.port

    def check2dict(self, line):

        pre = "core_"
        output = {}
        for line in line.split("\n"):
            # print(line)
            res = line.split("// ")

            if (len(res) == 2):
                value = res[0]
                key = res[1]
                if (value == ""):
                    pre = key.replace(" ", "_") + "_"
                else:
                    output[pre + key] = int(value)

            # print("value ({}) key ({})".format(value, pre + key))
        # print(json.dumps(output))
        # logging.info(output)
        return output

    # TODO JT refactoring and eliminate this function
    def sendReset(self):
        self.sendCmd(self.url, "abadIA/game/current/actions/SPACE", mode='POST')
        # sleep(1)
        self.sendCmd(self.url, "abadIA/game/current/actions/SPACE", mode='POST')
        return self.sendCmd(self.url, "abadIA/game", mode="POST")

    def sendCmd(self, url, command, type="json", mode="GET"):
        cmd = "{}/{}".format(url, command)
        try:
            if mode == "GET":
                r = requests.get(cmd)
            if mode == "POST":
                r = requests.post(cmd)

            if (type == "json"):
                headers = {'accept': 'application/json'}
            else:
                headers = {'accept': 'text/x.abadIA+plain'}
        except:
            logging.error("Vigasoco comm error")
            return None
        headers = {'accept': 'text/x.abadIA+plain'}

        cmdDump = "{}/abadIA/game/current".format(self.url)
        core = requests.get(cmdDump, headers=headers)
        # logging.info(core.text)
        core_dict = self.check2dict(core.text)

        headers = {'accept': 'application/json'}
        cmdDump = "{}/abadIA/game/current".format(url)
        r = requests.get(cmdDump, headers= headers)

        if (type == "json"):
            tmp = r.json()
            tmp['core'] = core_dict

            if r.status_code == 599:
                tmp['haFracasado'] = True
            return tmp
        else:
            return r.text

    def sendMultiCmd(self, path):
        logging.info("Path: %s Cmds: %s" % (path,  self.path2Pos[path]))
        cmds = self.path2Pos[path].split(":")
        for step in cmds:
            self.sendCmd(self.url, "abadIA/game/current/actions/{}".format(step), mode='POST')

        headers = {'accept': 'text/x.abadIA+plain'}
        cmdDump = "{}/abadIA/game/current".format(self.url)
        core = requests.get(cmdDump, headers=headers)
        # logging.info(core.text)
        core_dict = {"version": "v7"}
        core_dict = self.check2dict(core.text)

        headers = {'accept': 'application/json'}
        cmdDump = "{}/abadIA/game/current".format(self.url)
        r = requests.get(cmdDump, headers=headers)
        tmp = r.json()
        tmp['core'] =  core_dict
        if r.status_code == 599:
            tmp['haFracasado'] = True
        return tmp

    def step(self, action):
        """
        The agent takes a step in the environment.

        Parameters
        ----------
        action : int

        Returns
        -------
        ob, reward, episode_over, info : tuple
            ob (object) :
                an environment-specific object representing your observation of
                the environment.
            reward (float) :
                amount of reward achieved by the previous action. The scale
                varies between environments, but the goal is always to increase
                your total reward.
            episode_over (bool) :
                whether it's time to reset the environment again. Most (but not
                all) tasks are divided up into well-defined episodes, and done
                being True indicates the episode has terminated. (For example,
                perhaps the pole tipped too far, or you lost your last life.)
            info (dict) :
                 diagnostic information useful for debugging. It can sometimes
                 be useful for learning (for example, it might contain the raw
                 probabilities behind the environment's last state change).
                 However, official evaluations of your agent are not allowed to
                 use this for learning.
        """

        try:
            if (action >=8 ):
                ob = self.sendCmd(self.url, self.actions_list[action], mode="POST")
            else:
                ori = str(self.Personajes['Guillermo']['orientacion'])
                ob = self.sendMultiCmd(ori + self.actions_list[action])
        except Exception as e:
            logging.error("Communication Error: I cannot send the CMDs {}".format(e))
            logging.error("Check if the game engine is UP")
            self.game_is_done = True
            return self.prev_ob, 0, self.game_is_done, {}

        # print("ob -> {}".format(ob)) # ['obsequium']))

        # extracting all the values from the json
        # first personajes

        self._get_personajes_info(ob)

        self.obsequium    = int(ob['obsequium'])
        self.porcentaje   = int(ob['porcentaje'])
        self.bonus        = int(ob['bonus'])
        self.numPantalla  = int(ob['numPantalla'])
        self.dia          = int(ob['dia'])
        self.momentoDia   = int(ob['momentoDia'])
        self.haFracasado  = ob['haFracasado']
        self.rejilla      = ob['Rejilla']

        # print(self.rejilla)

        # we need to check is make sense finish it
        # if self.is_game_done or self.porcentaje == 100:
        #   raise RuntimeError("Episode is done")
        self.curr_step += 1
        self._take_action(action)

        ob['jugada'] = self.curr_step
        ob['gameId'] = self.gameId

        # reward = self._get_reward()

        reward = 0
        self.eventsAction = []
        # TODO JT we need to check, that pass to another room
        # not just stay all the time between rooms to get the reward

        if self.estaGuillermo:
            if (self.prevPantalla == -1):
                self.prevPantalla = int(ob['numPantalla'])
            else:
                if (self.prevPantalla != int(ob['numPantalla'])):
                    # reward += 0.03
                    # logging.info("----------")
                    # logging.info("reward by screen change !!!!! {} !=  {}".format(self.prevPantalla, int(ob['numPantalla'])))
                    # logging.info("Personajes: {}".format(self.Personajes))
                    # # logging.info("ob: {}".format(ob))
                    # logging.info("----------")
                    # self.add_event("NewRoom", "prev {} curr {}".format(self.prevPantalla, int(ob['numPantalla'])), 0.001)
                    self.prevPantalla = int(ob['numPantalla'])
                    self.save_game_checkpoint()

        # # If there is an obsequium change, it will be rewarded pos/neg
        # if len(self.prev_ob) > 0 and int(self.prev_ob['obsequium']) > 0:
            # # reward for incrementing the obsequium: > 0 +50 / < 0 -30
            # incr_obsequium = self.obsequium - int(self.prev_ob['obsequium'])
            # if incr_obsequium > 0:
                # reward += (50 * incr_obsequium) / 10000
                # self.add_event("IncrObsequium", "Obsequium {} Incr {}".format(self.prev_ob['obsequium'],incr_obsequium), (50 * incr_obsequium) / 10000)

            # if incr_obsequium < 0:
                # reward += (30 * incr_obsequium) / 10000
                # self.add_event("DecrObsequium", "Obsequium {} Decr {}".format(self.prev_ob['obsequium'], incr_obsequium),(30 * incr_obsequium) / 10000)

        # reward for incrementing the bonus: >0 +500
        # if len(self.prev_ob) > 0 and int(self.prev_ob['bonus']) > 0:
            # incr_bonus = self.bonus - int(self.prev_ob['bonus'])
            # if incr_bonus > 0:
                # reward += (500 * incr_bonus) / 10000
                # self.add_event("Bonus", "prev {} curr {}".format(self.bonus, int(self.prev_ob['bonus'])), (500 * incr_bonus) / 10000)

        # we check if Guillermo change his position. Positive reward if yes, negative if no
        # if action == 0:
        # if len(self.prev_ob) > 0 and len(self.prev_ob['Personajes']) > 0:
            # prev = self.dataPersonaje(self.prev_ob, "Guillermo")
            # curr = self.dataPersonaje(ob, "Guillermo")
            # if (prev['posX'] != curr['posX']) or (prev['posY'] != curr['posY']):
                # logging.info("se ha movido: {},{} -> {},{}".format(prev['posX'], prev['posY'],
                                                        # curr['posX'], curr['posY']))
                # reward += 0.001

        # TODO: check this self.eventsGame.extend(self.eventsAction)
        # if the game is over, we just finish the game and reward is -1000
        # if we completed the game, we finish and the reward is 5000
        # the percentage must be variable to help the AI to learn
        # with variable explanatory/explotation

        if (self.obsequium < 29):
            logging.info("GAME OVER by lack of Obsequium {}        ".format(self.obsequium))
            self.sendCmd(self.url, "/abadIA/game", mode='POST', type='raw')
            self.game_is_done = True
            self.haFracasado = True
            reward = -1

        if (self.haFracasado == True):
            logging.info("GAME OVER")
            self.sendCmd(self.url, "/abadIA/game", mode='POST', type='raw')
            self.game_is_done = True
            reward = -1

        if (self.porcentaje >= 90):
            self.game_is_done = True
            logging.info("FUCKING YEAH GAME ALMOST DONE")
            logging.info("FUCKING YEAH GAME ALMOST DONE")
            logging.info("FUCKING YEAH GAME ALMOST DONE")
            logging.info("FUCKING YEAH GAME ALMOST DONE")
            logging.info("FUCKING YEAH GAME ALMOST DONE")
            reward = 1

        # if no reward we penalized it
        # if reward == 0:
            # logging.info("***** No reward, penalizing it")
            # reward = -0.005

        # if self.obsequium > 0:
        #    reward = reward * float((self.obsequium / self.obsequium)*0.5)
        # if self.porcentaje > 0:
        #    reward = reward * float(((self.porcentaje * 0.5) / self.porcentaje)+1)

        if (self.wallMovs[action] == 1):
            logging.info("***** Invalid move against Wall, penalizing it")
            reward = -0.00901

        if (self.perMovs[action] == 1):
            logging.info("***** Invalid move against a Character, penalizing it")
            reward = -0.00902

        ###########################
        # New Experimental Reward #
        ###########################

        reward = float( ((self.porcentaje + 1) / 10000) * self.obsequium / 31)

        self.reward       = reward
        self.totalReward += reward
        ob['reward']      = reward
        ob['totalReward'] = self.totalReward
        logging.info("reward: {} tr: {} action: {} ".format(reward, self.totalReward, action))

        # adding more information for debugging: valid moves, vectors, predictions, etc.
        ob['valMovs']            = self.valMovs.tolist()
        ob['wallMovs']           = self.wallMovs.tolist()
        ob['perMovs']            = self.perMovs.tolist()
        ob['predictions']        = self.calculated_predictions
        ob['final']              = self.final_predictions
        ob['vector']             = self.vector_predictions
        ob['action_predictions'] = self.action_predictions
        ob['action_type']        = self.action_type

        # we make a copy for the current observation in order to calculate
        # the reward for the next state

        self.ob = ob
        self.prev_ob = ob

        # JT chequear si esto está bien, no parece que este devolviendo bien el estado siguiente!!!

        return ob, reward, self.game_is_done, {}

    def _get_personajes_info(self, ob):
        # print ("ob personajes -> {} ", ob['Personajes']['Personaje'][0])
        self.estaGuillermo = False
        for persona in self.listaPersonajes[:]:
            self.Personajes[persona] = {}
        for personaje in ob['Personajes']:
            if (len(personaje) == 1):
                break
            # persona = self.listaPersonajes[int(personaje['id'])]
            # datos = self.Personajes[persona]
            # for key, value in personaje.items():
                #if key != "id" or key != "fil":
                # datos[key] = value
            self.Personajes[personaje['nombre']] = personaje

            if int(personaje['id']) == 0:
                self.estaGuillermo = True

        return self.estaGuillermo

    # check is make sense do it for special state

    def normalizaVisited(self, x, y):
        bordes = []
        for X in range(x-1, x+2):
            for Y in range(y-1, y+2):
                if (self.Visited[X,Y] < 0):
                    bordes.append(1)
                else:
                    bordes.append(0)
        # print("bordes {}".format(bordes))
        return bordes

    def stateVector(self):
        x, y, ori    = self.personajeByName('Guillermo')
        ax, ay, aori = self.personajeByName('Adso')

        vector = np.append([x, y, ori, ax, ay, aori],self.normalizaVisited(x,y))
        # print("vector {}".format(vector))
        return vector.reshape(1,15)

    def _take_action(self, action):
        self.action_episode_memory[self.curr_episode].append(action)

        game_is_done = (self.obsequium <= 0)

        # remaining_steps = self.TOTAL_TIME_STEPS - self.curr_step
        # time_is_over = (remaining_steps <= 0)
        # throw_away = time_is_over and not self.is_banana_sold
        # if throw_away:
            # self.is_banana_sold = False # abuse this a bit
            # self.price = 0.0

    def _get_reward(self):
        """Reward is about how complete is the game"""
        if self.is_game_done:
            return self.price - 1
        else:
            return 0.0

    def reset(self):
        """
        Reset the state of the environment and returns an initial observation.

        Returns
        -------
        observation (object): the initial observation of the space.
        """
        self.gameId      = datetime.datetime.now().strftime('%y%m%d_%H%M%S_%f')
        self.gameName    = "abadia_game_{}.json".format(self.gameId)
        self.actionsName = "abadia_actions_{}.json".format(self.gameId)

        self.curr_episode += 1
        self.curr_step     = 1

        self.eventsGame   = []
        self.eventsAction = []
        self.totalReward  = 0.0
        self.predictions  = []

        self.action_episode_memory.append([])
        # self.is_game_done = False
        self.game_is_done = False

        logging.info('-----> RESET the GAME')
        ob = self.sendReset()
        logging.info('reset status') # {}'.format(ob))
        logging.info('-----> DONE')
        logging.info('-----> INIT dumps files: START ...')
        self.init_dumps_files()
        logging.info('-----> INIT dumps files: DONE')
        # time.sleep(5)
        if self._get_personajes_info(ob):
            logging.info('Esta Guillermo')
        return ob

    def render(self, mode='human', close=False):
        logging.info('state info: {}'.format(self))
        return

    def _get_state(self):
        """Get the observation."""
        # ob = [self.TOTAL_TIME_STEPS - self.curr_step]
        logging.info("--------> I wil got the initial state with Guillermo")
        tooboring = 0
        while True:
            ob = self.sendCmd(self.url, "/abadIA/current/game", mode='GET', type='json')
            # logging.info("{}".format(ob))
            tooboring += 1
            if self._get_personajes_info(ob):
                logging.info("getting the characters from Dump")
                break
            else:
                logging.info("getting the characters from ob") # :{}".format(ob))
                logging.info("Guillermo is not present yet, waiting")
                if tooboring % 10 == 0:
                    logging.info("Getting Boring ...")
                    if tooboring <= 10:
                        self.sendCmd(self.url, "start")
                    else:
                        self.sendCmd(self.url, "fin")
                    # self.sendCmd(self.url, "cmd/B")
                    # self.sendCmd(self.url, "cmd/A")
                    time.sleep(1)
                time.sleep(2)
        return ob

    def _seed(self, seed):
        random.seed(seed)
        np.random.seed

    # "planta": "0", "sonidos": ["0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"], "frases": [], "Personajes": {"Personaje": [{"id": "0", "nombre": "Guillermo", "posX": "137", "posY": "168", "altura": "0", "orientacion": "0", "objetos": "32"}, {"id": "1", "nombre": "Adso", "posX": "134", "posY": "168", "altura": "0", "orientacion": "1", "objetos": "32"}]}, "Objetos": {"ListaObjetos": []}
    def get_commons(self):
        commons = dict()
        commons.update({'timestamp': "{}".format(datetime.datetime.now()), 'numDia': int(self.ob['dia'])})
        commons.update({'momentoDia': int(self.ob['momentoDia']), 'obsequium': int(self.ob['obsequium'])})
        x = int(self.Personajes['Guillermo']['posX'])
        y = int(self.Personajes['Guillermo']['posY'])
        pantallaHex = "%1X%1X" % (x >> 4, y >> 4)
        commons.update({'numPantalla': int(self.ob['numPantalla']), 'pantallaHex': pantallaHex})
        commons.update({'planta': int(self.ob['planta']), 'guillermoPosX': x, 'guillermoPosY': y})
        commons.update({'bonus': int(self.ob['bonus']), 'porcentaje': int(self.ob['porcentaje'])})
        return commons

    def init_google_store_bucket(self):
        storage_client = storage.Client()
        self.google_storage_bucket = storage_client.get_bucket(self.gsBucket)

    def download_blob(self, source_blob_name, destination_file_name):
        blob = self.google_storage_bucket.blob(source_blob_name)
        directory = os.path.dirname(destination_file_name)
        if not os.path.exists(directory):
            os.makedirs(directory)
        blob.download_to_filename(destination_file_name)

        logging.info('Blob {} downloaded to {}.'.format(
            source_blob_name,
            destination_file_name))

    def upload_blob(self, source_file_name, destination_blob_name):
        """Uploads a file to the bucket."""
        blob = self.google_storage_bucket.blob(destination_blob_name)
        blob.upload_from_filename(source_file_name)

        logging.info('File {} uploaded to {}.'.format(
            source_file_name,
            destination_blob_name))

    def add_event(self, name, des, reward):
        data = {'name': name, 'des': des, 'reward': reward, 'totalReward': self.totalReward, 'version': 1}
        data.update(self.get_commons())

        self.eventsAction.append(data)
        logging.info("events {}".format(self.eventsAction))

    def save_game(self):
        self.fdGame.write("{}{}\"gameId\":\"{}\", \"totalSteps\":{}, \"obsequium\":{}, \"porcentaje\":{}, \"bonus\":{}, "
                          .format("[", "{", self.gameId, self.curr_step, self.obsequium, self.porcentaje, self.bonus))

        self.fdGame.write("\"totalReward\": \"{}\", "
                          .format("%.4f" % self.totalReward))

        self.fdGame.write("\"events\":{}"
                .format(json.dumps(self.eventsGame)))

        self.fdGame.write("{}\n".format("}]"))
        self.fdGame.flush()
        # self.fdGame.close()

        if (not self.fdActions.closed):
            logging.info("flushing and closing {} before exit".format(self.actionsName))
            self.fdActions.flush()
            self.fdActions.close()

        if (self.gsBucket != None):
            logging.info("Uploading Game: {} to GCP".format(self.dump_path + "/" + self.gameName))
            t = Thread(target=self.upload_blob, args=(self.dump_path + "/" + self.gameName,
                                                      self.dump_path + "/" + self.gameName))
            t.start()

            # compressing the file
            logging.info("Gziping ---> {}".format(self.dump_path + "/" + self.actionsName))
            with open(self.dump_path + "/" + self.actionsName, 'rb') as f_in, gzip.open(self.dump_path + "/" + self.actionsName + '.gz', 'wb') as f_out:
                shutil.copyfileobj(f_in, f_out)

            logging.info("Uploading Actions: {} to GCP".format(self.dump_path + "/" + self.actionsName + ".gz"))
            t = Thread(target=self.upload_blob, args=(self.dump_path + "/" + self.actionsName + ".gz",
                             self.dump_path + "/" + self.actionsName + ".gz"))
            t.start()
            logging.info("Deleting ---> {}".format(self.dump_path + "/" + self.actionsName))
            os.remove(self.dump_path + "/" + self.actionsName)

    def save_action(self, state, action, reward, nextstate):
        s1 = state.copy()
        s2 = nextstate.copy()

        string = "{}{}\"action\":{}\"state\":{},\"action\":{},\"reward\":{},\"nextstate\":{}{}{}\n".format("[", "{", "{", json.dumps(s1), action, reward, json.dumps(s2), "}", "}]")
        self.fdActions.write(string)
        self.fdActions.flush()

    def visited_snap_load(self):
        nameVisitedSnap = "snapshoots/current-visited"

        # for speed up the games if the visited  exist locally
        # we download an updated version just a 10% of the time

        if self.gsBucket != None and np.random.randint(10) <= 1 and not os.path.exists(nameVisitedSnap):
            logging.info("Downloading Visited from GCP")
            try:
                self.download_blob(nameVisitedSnap, nameVisitedSnap)
            except:
                logging.info("File {} not exist at bucket {}".format(nameVisitedSnap, self.gsBucket))

        if os.path.exists(nameVisitedSnap) and os.path.getsize(nameVisitedSnap) > 0:
            fvisitedsnap = open(nameVisitedSnap, "rb+")
            self.Visited = np.load(fvisitedsnap)
        else:
            fvisitedsnap = open(nameVisitedSnap, "wb+")
            self.Visited = np.zeros([512, 512])
            np.save(fvisitedsnap, self.Visited)
            fvisitedsnap.flush()
            fvisitedsnap.close()

            if (self.gsBucket != None):
                logging.info("Uploading to GCP")
                self.upload_blob(nameVisitedSnap, nameVisitedSnap)

    def visited_snap_save(self):
        nameVisitedSnap = "snapshoots/current-visited"

        fvisitedsnap = open(nameVisitedSnap, "wb+")
        np.save(fvisitedsnap, self.Visited)
        fvisitedsnap.flush()
        fvisitedsnap.close()

        if (self.gsBucket != None):
            logging.info("Uploading visited to GCP")
            t = Thread(target=self.upload_blob, args=(nameVisitedSnap, nameVisitedSnap))
            t.start()

    def reset_fin_partida(self):
        self.sendCmd(self.url, "abadIA/game/current/actions/SPACE", mode='POST')
        ob = self.sendCmd(self.url, "abadIA/game", mode="POST")

    def init_dumps_files(self):

        # check is directory exist, if not we will create it
        now = datetime.datetime.now()
        self.dump_path = now.strftime('games/%Y%m%d')
        path = Path(self.dump_path)
        path.mkdir(parents=True, exist_ok=True)

        # create the game and actions files
        self.fdGame    = open(self.dump_path + "/" + self.gameName, "w")
        self.fdActions = open(self.dump_path + "/" + self.actionsName, "w")

    def save_game_checkpoint(self):

        checkpoint = self.sendCmd(self.url, "/abadIA/game/current", mode='GET', type="raw")
        if (checkpoint is None):
            logging.error("I cannot save the checkpoint game file. Probably because I cannot connect with the game server ")
            return
        now = datetime.datetime.now()
        self.dump_path = now.strftime('games/%Y%m%d')
        path = Path(self.dump_path)
        path.mkdir(parents=True, exist_ok=True)

        # create the checkpoint file
        self.checkpointTmpName  = "abadia_checkpoint_{}_{}".format(self.gameId, self.checkpointSec)
        self.checkpointSec     += 1
        self.checkpointTmpName += "_{}_{}_{}_{}_{}.checkpoint".format(self.dia, self.momentoDia,
                                                self.numPantalla, self.obsequium, np.round(self.porcentaje,2))

        self.fdCheckpoint = open(self.dump_path + "/" + self.checkpointTmpName, "w")
        self.fdCheckpoint.write(checkpoint)
        self.fdCheckpoint.flush()

        if (self.gsBucket != None):
            logging.info("Uploading {} to GCP".format(self.dump_path + '/' + self.checkpointTmpName))
            t = Thread(target=self.upload_blob, args=(self.dump_path + '/' + self.checkpointTmpName,
                             self.dump_path + '/' + self.checkpointTmpName))
            t.start()
        # else:
            # logging.error("Not saving it to the local filesystem")

    def load_game_checkpoint(self, name):
        logging.info("voy a abrir el fichero ({})".format(name))

        if (self.gsBucket != None):
            logging.info("Downloading Checkpoint {} from GCP".format(name))
            try:
                self.download_blob(name, name)
                self.fdCheckpoint = open(name, "r")
                checkpoint = self.fdCheckpoint.read()
                requests.put(self.url+"/abadIA/game/current", data=checkpoint)
            except:
                logging.error("*** ErrorFile: {} not exist at bucket {}".format(name, self.gsBucket))
        else:
            logging.error("Not Loading {} from local filesystem.".format(name))

        time.sleep(2)
        return self._get_state()

    def personajeByName(self, name):
        # TODO JT: we need to check that there are values for this personaje
        if (name in self.Personajes) and ('posX' in self.Personajes[name]):
            return int(self.Personajes[name]['posX']), int(self.Personajes[name]['posY']), int(self.Personajes[name]['orientacion'])
        else:
            # logging.info("No hay {}: {}".format(name, self.Personajes))
            return 0, 0, 0

    def dataPersonaje(self, ob, name):
        notfound = {}
        for persona in ob['Personajes']:
            if (persona['nombre'] == name):
                return persona
        return notfound

    def pintaRejilla(self, width, height):
        w = int(width / 2)
        h = int(height / 2)
        yRejilla = 0
        xRejilla = 0

        # TODO: to display all the characters, now only Guillermo and Adso
        # pers = {}
        # for per in env.Personajes:
        #    datos = {'x': per['posX'], 'y': per['posY']}
        #   pers.update(per['id']:datos)
        #

        x, y, ori           = self.personajeByName('Guillermo')
        adsoX, adsoY, adsoO = self.personajeByName('Adso')
        abadX, abadY, abadO = self.personajeByName('Abad')

        logging.info("\x1b[HGuillermo {},{} Adso {},{} Abad {},{} Obsequium:{} Porcentaje:{} Reward:{} TR:{} V:{}".format(x, y, adsoX, adsoY,
                             abadX, abadY, self.obsequium, self.porcentaje, np.round(self.reward, 6), np.round(self.totalReward, 6), np.round(self.predictions, 4)))

        logging.info("+---+" + "-" * (w * 2) + "+" + "-" * 24 + "+" + "-" * 48 + "+")

        for yy in range(y - h, y + h):
            ss = "|%3d|" % yy
            for xx in range(x - w, x + w):
                if (xx == x and yy == y):
                    if ori == 0:
                        ss += ">"
                    if ori == 3:
                        ss += "V"
                    if ori == 1:
                        ss += "^"
                    if ori == 2:
                        ss += "<"
                else:
                    character = False
                    if (xx == adsoX and yy == adsoY):
                        ss += "a"
                        character = True
                    if (xx == abadX and yy == abadY):
                        ss += "A"
                        character = True

                    if not character:
                        if (self.Visited[xx, yy] == 0):
                            ss += "·"
                        else:
                            if (self.Visited[xx, yy] > 0):
                                ss += " "
                            else:
                                ss += "#"

            ss += "|"
            if yRejilla < 24:
                for xx in range(0, 24):
                    if (self.rejilla[yRejilla][xx] == 0):
                        ss += " "
                    else:
                        if (self.rejilla[yRejilla][xx] >= 16):
                            ss += "P"
                        else:
                            ss += "#"

            ss += "|"
            if yRejilla < 24:
                for xx in range(0, 24):
                    if (self.rejilla[yRejilla][xx] == 0):
                        ss += "  "
                    else:
                        ss += "{}".format(format(self.rejilla[yRejilla][xx], '2x'))
            yRejilla += 1
            ss += "|"
            logging.info(ss)

        logging.info("+" + "-" * (w * 2) + "+" + "-" * 24 + "+" + "-" * 48 + "+")


# Formulation with the multiplier on the curve
from dolfin import *
from xii import *
from weak_bcs.utils import block_form, MMSData, H1_norm, L2_norm, matrix_fromHs
from xii.linalg.matrix_utils import identity_matrix
from hsmg.hseig import Hs0Norm
from block.algebraic.petsc import LU, AMG
from block import block_mat, block_vec
import numpy as np

def setup_mms(params):
    '''Manufactured solution from notes'''

    u3d = Expression('sin(4*pi*x[0])*sin(4*pi*x[1])', degree=4)
    f3d = Expression('(32*pi*pi)*sin(4*pi*x[0])*sin(4*pi*x[1])', degree=4)

    f1d = Expression('pi*pi*sin(pi*x[2])', degree=4)
    u1d = Expression('sin(pi*x[2])', degree=4)

    p = Expression('0', degree=4)  # The multiplier

    return MMSData(solution=[u3d, u1d, p],
                   rhs=[(f3d, f1d, u1d), (u3d, u1d, p)],
                   subdomains=[], normals=[])

def setup_problem(n, mms, params):
    '''Coupled 3d-1d with 1d Lagrange multiplier'''
    # NOTE: inborg distinguishes between parallel and not parallel hmin
    omega = UnitCubeMesh(n, n, n)

    A, B = np.array([0.5, 0.5, 0]), np.array([0.5, 0.5, 1])
    gamma = StraightLineMesh(A, B, n)

    # The poisson problem
    V3 = FunctionSpace(omega, 'CG', 1)
    V1 = FunctionSpace(gamma, 'CG', 1)
    Q = FunctionSpace(gamma, 'CG', 1)

    W = [V3, V1, Q]

    u3, u1, p = map(TrialFunction, W)
    v3, v1, q = map(TestFunction, W)

    assert params.radius in (0.25, 0.5)

    # The size of averaging square is 0.5
    alen = params.radius
    avg_shape = SquareRim(lambda x: np.array([alen/2, alen/2, x[-1]]), degree=10)

    # Setup bounding curve
    Pi_u3, Pi_v3 = (Average(f, gamma, avg_shape) for f in (u3, v3))

    # Cell integral of Qspace
    dx_ = Measure('dx', domain=gamma)
    avg_len = Constant(4*alen)
    avg_area = Constant(alen**2)

    a = block_form(W, 2)
    # Subdomains
    a[0][0] = inner(grad(u3), grad(v3))*dx
    a[1][1] = avg_area*inner(grad(u1), grad(v1))*dx
    # Coupling
    a[0][2] = avg_len*inner(Pi_v3, p)*dx_
    a[1][2] = -avg_len*inner(v1, p)*dx
    a[2][0] = avg_len*inner(Pi_u3, q)*dx_
    a[2][1] = -avg_len*inner(u1, q)*dx

    # Right hand sides and dirichlet data for the unknowns
    (f3, f1, fI), (g3, g1, gI) = mms.rhs
    # Linear part
    L = block_form(W, 1)
    L[0] = inner(f3, v3)*dx

    # Account for reduction from volume to line
    avg_shape = Square(lambda x: np.array([0.25, 0.25, x[-1]]), degree=10)
    # NOTE: Avg only works with functions so need to interpolate it
    V3h = FunctionSpace(omega, 'CG', 2)
    f1h = interpolate(f1, V3h)
    L[1] = avg_area*inner(Average(f1h, gamma, avg_shape), v1)*dx_

    L[2] = avg_len*inner(-fI, q)*dx

    # Homog everywhere
    V3_bcs = [DirichletBC(V3, g3, 'on_boundary')]
    V1_bcs = [DirichletBC(V1, g1, 'on_boundary')]
    Q_bcs = [DirichletBC(Q, gI, 'on_boundary')]
    # Group
    bcs = [V3_bcs, V1_bcs, Q_bcs]
    # No bcs
    A, b = map(ii_assemble, (a, L))
    # With bcs
    A, b = apply_bc(A, b, bcs)

    return A, b, W

def setup_error_monitor(mms_data, params):
    '''We look at H1, H1, Hs norm'''
    # Error of the passed wh

    def get_error(wh, mms=mms_data):
        # We look at the H1 error for velocity
        u3, u1, p = mms.solution
        u3h, u1h, ph = wh

        # On a finer mesh
        Q = FunctionSpace(ph.function_space().mesh(), 'CG', 3)
        Hs = Hs0Norm(Q, s=-0.5, bcs=DirichletBC(Q, Constant(0), 'on_boundary'))

        # A U = M U Lambda
        # Hs = M * U * Lambda^{-0.5} * (M*U).T

        # e*H*e ie (e, e)_H
        e = interpolate(p, Q).vector()
        e.axpy(-1, interpolate(ph, Q).vector())

        e = np.sqrt(e.inner(Hs*e))
        # On big meshes constructing the error for interpolation space
        # is expensive so wi reduce order then
        degree_rise = 1 if u3h.function_space().dim() < 3E6 else 0
        # NOTE: the error is interpolated to P2 disc, or P1 disc
        return (H1_norm(u3, u3h, degree_rise=degree_rise),
                H1_norm(u1, u1h),
                e,
                L2_norm(p, ph))
    # Pretty print
    error_types = ('|u3|_1', '|u1|_1', '|p|_{-1/2}', '|p|_0')

    return get_error, error_types

def cannonical_inner_product(W, mms, params, AA):
    '''Inner product of alpha*H1 x beta*H1 x H-0.5'''
    V3, V1, Q = W
    # Extact Vi norms from system
    V3_inner = AA[0][0]
    V1_inner = AA[1][1]

    bcs = DirichletBC(Q, Constant(0), 'on_boundary')
    # This is what we reported in the paper
    Q_inner = matrix_fromHs(Hs0Norm(Q, s=-0.5, kappa=Constant(1.0),
                                    bcs=bcs))

    B = block_diag_mat([V3_inner, V1_inner, Q_inner])

    return B

def cannonical_riesz_map(W, mms, params, AA):
    '''Riesz map wrt. inner product of alpha*H1 x beta*H1 x H-0.5'''
    V3, V1, Q = W
    # Extact Vi norms from system
    V3_inner = AA[0][0]
    V1_inner = AA[1][1]

    bcs = DirichletBC(Q, Constant(0), 'on_boundary')
    Q_inner = Hs0Norm(Q, s=-0.5, bcs=bcs)

    mms.normals.append(Q_inner)

    B = block_diag_mat([AMG(V3_inner), AMG(V1_inner), Q_inner**-1])

    return B

def withL2_inner_product(W, mms, params, AA):
    '''Inner product of alpha*H1 x beta*H1 x H-0.5'''
    V3, V1, Q = W
    # Extact Vi norms from system
    V3_inner = AA[0][0]
    V1_inner = AA[1][1]

    p, q = TrialFunction(Q), TestFunction(Q)
    Q_inner = assemble(inner(p, q)*dx)

    B = block_diag_mat([V3_inner, V1_inner, Q_inner])

    return B

def withL2_riesz_map(W, mms, params, AA):
    '''Riesz map wrt. inner product of alpha*H1 x beta*H1 x H-0.5'''
    V3, V1, Q = W
    # Extact Vi norms from system
    V3_inner = AA[0][0]
    V1_inner = AA[1][1]
    Q_inner = AA[2][2]

    B = block_diag_mat([AMG(V3_inner), AMG(V1_inner), AMG(Q_inner)])

    return B

def just_identity(W, mms, params, AA, Z):
    '''1'''
    return identity_matrix(W)

# --------------------------------------------------------------------

# The idea now that we register the inner product so that from outside
# of the module they are accessible without referring to them by name
W_INNER_PRODUCTS = {0: cannonical_inner_product,
                    1: withL2_inner_product,
                    2: just_identity}

# And we do the same for preconditioners / riesz maps
W_RIESZ_MAPS = {0: cannonical_riesz_map,
                1: withL2_riesz_map,
                2: just_identity}

# How is the problem parametrized
PARAMETERS = ('radius', )


from trello import Webhooks, Boards, TrelloApi
from django.core.management.base import BaseCommand
from django.conf import settings

class Command(BaseCommand):
    def add_arguments(self, parser):
        parser.add_argument('--delete', action='store_true')

    def handle(self, *args, **options):
        trello = TrelloApi(settings.TRELLO_KEY, settings.TRELLO_TOKEN)
        boards = trello.members.get_board(settings.TRELLO_USER)
        for i, board in enumerate(boards):
            print(str(i).ljust(3), board['name'].ljust(40), '|', board['id'])
        selected = int(input())
        board_id = boards[selected]['id']

        if options['delete']:
            data_list = trello.members.get_token(settings.TRELLO_USER, webhooks='true')
            wh_id = None
            if data_list:
                webhooks_list = data_list[0]['webhooks']
                for wh in webhooks_list:
                    if wh['idModel'] == board_id:
                        wh_id = wh['id']
                        break
            print('Deleting webhook for:', wh_id)
            trello.webhooks.delete(wh_id)
        else:
            r = trello.webhooks.new(settings.TRELLO_CALLBACK, board_id, description='Tets')
            print('Selected board will now call this endpoint after changes:')
            print(settings.TRELLO_CALLBACK)
            print(board_id)
            print(r)


import numpy as np
import os
from random import shuffle
import csv

import matplotlib.pyplot as plt

## Data reference: https://www.kaggle.com/datasnaek/league-of-legends ####

######################### Edge feature ##########################
with open('data/HOTS/ReplayCharacters.csv', 'r') as f:
	reader = csv.reader(f)
	raw_dataset = list(reader)
data_length = len(raw_dataset)

with open('data/HOTS/Replays.csv', 'r') as f:
    reader = csv.reader(f)
    raw_mode_dataset = list(reader)
data_length = len(raw_dataset)

All_match_data = []
All_match_mmr = []
M = 5
heroes = range(84)
for i, data in enumerate(raw_dataset[1:]):
# for i, data in enumerate(raw_dataset[9365000:]):
#     print(data)
    match_idx = int(i/10)
    if i%10 == 0:
        if i != 0:
            match_mmr = match_mmr / (2*M)
            if match_mmr > 2800:
                match_data_1 = [team_1, team_2, '1']
                match_data_2 = [team_2, team_1, '0']

                flattened_1 = [val for sublist in match_data_1 for val in sublist]
                flattened_1 = [int(x) for x in flattened_1]
                flattened_2 = [val for sublist in match_data_2 for val in sublist]
                flattened_2 = [int(x) for x in flattened_2]

                if len(flattened_1) == 11:
                    All_match_data.append(flattened_1)
                    All_match_data.append(flattened_2)
                    All_match_mmr.append(match_mmr)
        team_1 = []
        team_2 = []
        match_mmr = 0

    if data[5] == '':
        match_mmr += 0
    else:
        match_mmr += int(data[5])
#         print(match_mmr)

    if data[4] == '1':
        team_1.append(int(data[2]) - 1)
#         match_data_1.insert(0, int(data[2]) - 1)
#         match_data_2.insert(-1, int(data[2]) - 1)
    else:
        team_2.append(int(data[2]) - 1)
#         match_data_1.insert(-1, int(data[2]) - 1)
#         match_data_2.insert(0, int(data[2]) - 1)

# np.random.shuffle(All_match_data)

feature = []
n_items = len(heroes)
feature.append(range(n_items))
feature.append(range(n_items))
feature.append(range(n_items))
feature = list(map(list, zip(*feature)))
GT = range(n_items)

np.savetxt(os.path.join('data/HOTS', 'HOTS.nodes'), feature)
np.savetxt(os.path.join('data/HOTS', 'HOTS.GT'), GT)
np.savetxt(os.path.join('data/HOTS', 'HOTS.edges'), All_match_data[:int(0.9*len(All_match_data))])
np.savetxt(os.path.join('data/HOTS', 'HOTS.edges_test'), All_match_data[int(0.9*len(All_match_data))+1:])

# fig = plt.figure()
# ax = plt.subplot(111)

# plt.hist(match_mmr, normed=True, bins=30)
# plt.show()

#################### Rank Centrality feature ####################
# n_iteration = 10000
# n_items = int(np.max(new_edges) + 1)
# feature = []

# score = np.ones(n_items)
# Markov_chain = np.zeros((n_items, n_items))
# adjacency = np.zeros((n_items, n_items))
# for i, datum in enumerate(new_edges):
#     idx1, idx2 = int(datum[0]), int(datum[1])
#     Markov_chain[idx1][idx2] += datum[2]
#     Markov_chain[idx2][idx1] += 1 - datum[2]
#     adjacency[idx1][idx2] += 1
#     adjacency[idx2][idx1] += 1
# degree = np.sum(adjacency, axis = 0)
# dmax = max(degree)
# count = np.sum(Markov_chain, axis = 1)
# score2 = count / degree
# Markov_chain = Markov_chain / dmax
# for i in range(n_items):
#     Markov_chain[i][i] = 1 - np.sum(Markov_chain[:, i])
# for i in range(n_iteration):
#     # if i % 1000 ==0:
#     # print(str(i) + '/' + str(n_iteration))
#     score = Markov_chain.dot(score)

# dataset = new_edges
# n_iteration = 1000
# epsilon = 1e-10
# score3 = np.ones(n_items) / n_items
# n_win = np.zeros(n_items)
# adjacency = np.zeros((n_items, n_items))
# for i, datum in enumerate(dataset):
#     idx1, idx2, winloss = int(datum[0]), int(datum[1]), int(datum[2])
#     if winloss == 1:
#         n_win[idx1] += 1
#     elif winloss == 0:
#         n_win[idx2] += 1

#     adjacency[idx1][idx2] += 1
#     adjacency[idx2][idx1] += 1

# adjacency = np.array(adjacency, dtype = np.float)
# for iter_idx in range(n_iteration):
#     score_matrix = np.repeat([score3], n_items, axis = 0)
#     score_matrix = score_matrix + np.transpose(score_matrix)

#     recipro_score = adjacency / score_matrix
#     recipro_score = np.sum(recipro_score, axis = 1)
#     score3 = (n_win + epsilon*np.ones(n_items)) / recipro_score

#     # for i in range(n_items):
#     #     score3[i] = (n_win[i] + epsilon) / recipro_score[i]

# score = score / max(score)
# score2 = score2 / max(score2)
# score3 = score3 / max(score3)

# feature.append(range(n_items))
# feature.append(score)
# feature.append(score2)
# feature.append(score3)
# feature.append(range(n_items))

# feature = list(map(list, zip(*feature)))
# #################################################################
# np.savetxt(os.path.join('data/GIFGIF', 'GIFGIF.nodes'), feature)


"""
Suppose you have a long flowerbed in which some of the plots are planted and some are not. However, flowers cannot be
planted in adjacent plots - they would compete for water and both would die.

Given a flowerbed (represented as an array containing 0 and 1, where 0 means empty and 1 means not empty), and a number
n, return if n new flowers can be planted in it without violating the no-adjacent-flowers rule.

Example 1:
Input: flowerbed = [1,0,0,0,1], n = 1
Output: True
Example 2:
Input: flowerbed = [1,0,0,0,1], n = 2
Output: False
Note:
The input array won't violate no-adjacent-flowers rule.
The input array size is in the range of [1, 20000].
n is a non-negative integer which won't exceed the input array size.
"""

class canPlaceFlowers:
    def canPlaceFlowers(self, flowerbed, n):
        """
        :type flowerbed: List[int]
        :type n: int
        :rtype: bool
        """

        # handle [0], [0, 1] cases
        if len(flowerbed) <= 2 and sum(flowerbed) == 0:
            n -= 1

        # handle [0, 0, 0] case
        if len(flowerbed) == 3 and sum(flowerbed) == 0:
            n -= 2

        for idx in range(len(flowerbed) - 2):
            spots = flowerbed[idx: idx + 3]
            if idx == len(flowerbed) - 3 and spots[1] == 0 and spots[2] == 0:
                flowerbed[idx + 2] = 1
                n -= 1
            elif idx == 0 and spots[idx + 1] == 0 and spots[idx] == 0:
                flowerbed[idx] = 1
                n -= 1
            elif sum(spots) == 0:
                flowerbed[idx + 1] = 1
                n -= 1
        print(flowerbed)
        return n <= 0

    def canPlaceFlowers2(self, A, N):
        for i, x in enumerate(A):
            if (not x
                and (i == 0 or A[i-1] == 0)
                and (i == len(A)-1 or A[i+1] == 0)):
                N -= 1
                A[i] = 1
        return N <= 0

res = canPlaceFlowers().canPlaceFlowers([0, 0, 1], 1)
print(res)


import pandas as pd
import numpy as np
import common

def calculate_changeover_cost():
    man_seq = pd.read_csv('manufacture_sequence.csv')
    lines=['A1','A2','B1','B2','B3','C1']
    changeover_costs = {'A1':33536,'A2':15947,'B1':13333,'B2':13333,'B3':13333,'C1':54353.39}
    total_changeover_cost=0
    for line in lines:
        plant = line[0]
        line_no = int(line[1])
        line_seq = man_seq[(man_seq.Plant==plant) & (man_seq.Line==line_no)]
        curr_prod = None
        changes=0
        for index,row in line_seq.iterrows():
            product = row.Product_ID
            if product != curr_prod and not pd.isnull(product):
                if curr_prod != None:
                    changes += 1
                curr_prod = product
        total_changeover_cost += changes*changeover_costs[line]
    return total_changeover_cost

def calculate_production_cost():
    man_seq = pd.read_csv('manufacture_sequence.csv')
    pro_cos = pd.read_csv('production_cost.csv')
    pro_cap = pd.read_csv('production_capacity.csv')

    lines=['A1','A2','B1','B2','B3','C1']
    total_prod_cost=0
    for line in lines:
        plant=line[0]
        line_no = int(line[1])
        line_seq = man_seq[(man_seq.Plant==plant) & (man_seq.Line==line_no)]
        for month in range(37,40):
            month_seq = line_seq[(line_seq.Month==month)]
            for product,days in month_seq.groupby('Product_ID').Product_ID.count().iteritems():
                capacity = pro_cap[(pro_cap.Plant==plant)&
                    (pro_cap.Line==line_no) &(pro_cap.Product==product)].Capacity.values[0]
                pot_prod = capacity*days
                cost_per_mt = pro_cos[(pro_cos.Product_ID==product) &
                                     (pro_cos.Plant==plant)].Production_cost.values[0]
                total_prod_cost += pot_prod*cost_per_mt
    return total_prod_cost

def calculate_delivery_cost():
    shi_reg = pd.read_csv('shipping_region.csv')
    del_cos = pd.read_csv('delivery_cost.csv')
    regions=[]
    for i in range(1,19):
        regions.append('R'+str(i))
    products=[]
    for i in range(1,82):
        products.append('P'+str(i))
    total_delivery_cost=0
    for plant in ['A','B','C']:
        for region in regions:
            region_shipments = shi_reg[(shi_reg.Plant==plant) &
                (shi_reg.Region==region)].Shipping_to_region_quantity.sum()
            del_cost = del_cos[(del_cos.Plant==plant) &
                              (del_cos.Region==region)].Delivery_cost.values[0]
            total_delivery_cost += (region_shipments*del_cost)
    return total_delivery_cost

def calculate_cost():
    fixed_cost=(33536+15947+13333+13333+13333+54353.39)*90
    changeover_cost=calculate_changeover_cost()
    production_cost=calculate_production_cost()
    delivery_cost=calculate_delivery_cost()
    return fixed_cost+changeover_cost+production_cost+delivery_cost

def calculate_revenue():
    dem_pri = pd.read_csv('demand_price.csv')
    shi_reg = pd.read_csv('shipping_region.csv')
    dem_for = pd.read_csv('demand_forecast.csv')
    regions=[]
    for i in range(1,19):
        regions.append('R'+str(i))
    products=[]
    for i in range(1,82):
        products.append('P'+str(i))
    total_revenue=0
    for region in regions:
        for product in products:
            dem_price = dem_pri[(dem_pri.Product_ID==product) &
                               (dem_pri.Region==region)].Demand_price.values[0]
            act_quantity = shi_reg[(shi_reg.Region==region)&
                                  (shi_reg.Product_ID==product)].Shipping_to_region_quantity.sum()
            dem_quantity = dem_for[(dem_for.Region==region)&(dem_for.Product_ID==product)].Demand.sum()
            total_revenue += dem_price*(min(act_quantity,dem_quantity))
    return total_revenue

def get_margin_percent():
    total_revenue = calculate_revenue()
    total_cost = calculate_cost()
    print("Revenue-",total_revenue,'Cost-',total_cost)
    return ((total_revenue-total_cost)*100)/total_cost


class CircularShift:

	def __init__(self, lineManager, noiseWords):

		self._offsets = []
		self._getWordOffsets(lineManager, noiseWords)

	def getOffsets(self):
		return self._offsets

	def _getWordOffsets(self, lineManager, noiseWords = None):

		i = 0
		while i < lineManager.getLineCount():

			if lineManager.getLineLength(i) == 0:
				i+=1
				continue

			last_char = ''
			offset_index = 0
			k = 0
			word = ''
			while k < lineManager.getLineLength(i):

				currentChar = lineManager.getChar(i, k)

				if currentChar == ' ' and last_char == ' ':
					k += 1
					continue
				elif currentChar == ' ' and last_char != ' ':
					if word.lower() not in noiseWords:
						self._offsets.append([i, offset_index])
					word = ''
				elif currentChar != ' ' and last_char != ' ':
					word += currentChar
				else:
					word += currentChar.lower()
					offset_index = k

				last_char = currentChar
				k += 1

			if last_char != ' ':
				if word.lower() not in noiseWords:
						self._offsets.append([i, offset_index])
			i+=1


import heapq
import random

class TabuSearch:

    def __init__(self, tenure = 0, lower_tenure = None, upper_tenure = None, tenure_iteration = None,
                 candidatesNumber = 1, maxIterations = 0, neighborhood_probability = 1, max_repetition = None,
                 cost = None, initialSolution = []):

        self.matrix = [[0 for x in range(len(initialSolution))] for y in range(len(initialSolution))]
        self.lower_tenure = lower_tenure
        self.upper_tenure = upper_tenure
        self.tenure_iteration = tenure_iteration
        if self.lower_tenure is None or self.upper_tenure is None:
            self.tenure = tenure
        else:
            self.tenure = random.randint(self.lower_tenure, self.upper_tenure)
        self.cost = cost
        self.maxIterations = maxIterations
        self.solution = initialSolution.copy()
        self.value = self.cost(self.solution)
        self.candidatesNumber = candidatesNumber
        self.neighborhood_probability = neighborhood_probability
        self.max_repetition = max_repetition

        self.bestSolution = self.solution.copy()
        self.bestValue = self.value

    def selectCandidate(self, candidates):
        selectedCandidate = None
        for candidate in candidates:
            swap = candidate["swap"]
            if ((self.matrix[swap[0]][swap[1]] == 0
                and (self.max_repetition is None
                or self.matrix[swap[1]][swap[0]] < self.max_repetition))
                or candidate["cost"] < self.bestValue):
                selectedCandidate = candidate.copy()
                break

        for x in range(len(self.solution)):
            for y in range(x + 1, len(self.solution)):
                if self.matrix[x][y] > 0:
                    self.matrix[x][y] -= 1

        self.matrix[swap[0]][swap[1]] = self.tenure
        self.matrix[swap[1]][swap[0]] += 1

        self.solution[swap[0]], self.solution[swap[1]] = self.solution[swap[1]], self.solution[swap[0]]
        newValue = self.cost(self.solution)
        self.value = newValue

    def candidateCost(self, candidate):
        return candidate["cost"]

    def getCandidates(self):

        candidates = []

        for i in range(len(self.solution)):
            for j in range(i + 1, len(self.solution)):
                if random.random() < self.neighborhood_probability:
                    tempSolution = self.solution.copy()
                    tempSolution[i], tempSolution[j] = tempSolution[j], tempSolution[i]
                    cost = self.cost(tempSolution)
                    candidates.append({
                        "swap": sorted([i, j]),
                        "cost": cost
                    })

        return heapq.nsmallest(self.candidatesNumber, candidates, key=self.candidateCost)

    def search(self):
        iteration = 0

        while iteration < self.maxIterations:

            if self.tenure_iteration is not None and iteration % self.tenure_iteration == 0:
                self.tenure = random.randint(self.lower_tenure, self.upper_tenure)

            candidates = self.getCandidates()
            self.selectCandidate(candidates)

            if self.value < self.bestValue:
                self.bestSolution, self.bestValue = self.solution.copy(), self.value

            iteration += 1

        print("Best Solution: ", self.bestSolution)
        print("Best value: ", self.bestValue)
        return self.bestSolution


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

#Dataset code copied from https://github.com/utkuozbulak/pytorch-custom-dataset-examples
#model code copied from https://github.com/DeepLearnPhysics/pytorch-uresnet
import numpy as np
import os

import torch
import torch.nn as nn
from torch.utils.data.sampler import SubsetRandomSampler
import os

import torch.optim as optim
from torch.optim import lr_scheduler

import argparse
from networks.resnet_example import resnet18
from utils.data_loaders import CathodeSimData
import traceback
import yaml

def yaml_load(config):
    with open(config) as stream:
        param = yaml.safe_load(stream)
    return param

if torch.cuda.is_available():
    device = 'cuda'
else:
    device = 'cpu'
list_of_gpus = range(torch.cuda.device_count())
device_ids = range(torch.cuda.device_count())
os.environ["CUDA_VISIBLE_DEVICES"] = str(list_of_gpus).strip('[]').replace(' ', '')

best_acc = 0  # best test accuracy
start_epoch = 0  # start from epoch 0 or last checkpoint epoch

def adjust_learning_rate(optimizer, epoch, lr):
    """Sets the learning rate to the initial LR decayed by 10 every 20 epochs"""
    lr = lr/np.exp(epoch/10)
    for param_group in optimizer.param_groups:
        param_group['lr'] = lr

# Training
def train(trainloader, epoch):
    # print('\nEpoch: %d' % epoch)
    net.train()
    train_loss = 0
    correct = 0
    total = 0
    for batch_idx, (inputs, targets, energies) in enumerate(trainloader):
        # print(inputs.shape)
        inputs, targets = inputs.to(device), targets.to(device)
        optimizer.zero_grad()
        outputs = net(inputs)
        loss = criterion(outputs, targets)
        loss.backward()
        optimizer.step()

        train_loss += loss.item()
        _, predicted = outputs.max(1)
        total += targets.size(0)
        correct += predicted.eq(targets).sum().item()

        print(batch_idx, '/', len(trainloader), 'Loss: %.3f | Acc: %.3f%% (%d/%d)'
            % (train_loss/(batch_idx+1), 100.*correct/total, correct, total))
    return train_loss/len(trainloader), 100.*correct/total

def test(testloader, epoch):

    global best_acc
    net.eval()
    test_loss = 0
    correct = 0
    total = 0
    score = []

    with torch.no_grad():
        for batch_idx, (inputs, targets, energies) in enumerate(testloader):
            inputs, targets = inputs.to(device), targets.to(device)
            outputs = net(inputs)
            loss = criterion(outputs, targets)

            test_loss += loss.item()
            _, predicted = outputs.max(1)
            total += targets.size(0)
            correct += predicted.eq(targets).sum().item()
            softmax = nn.Softmax(dim=0)
            for m in range(outputs.size(0)):
                score.append([softmax(outputs[m])[1].item(), targets[m].item(), energies[m].item()])
                # score.append([outputs[m][1].item(), targets[m].item()])
            print(batch_idx, len(testloader), 'Loss: %.3f | Acc: %.3f%% (%d/%d)'
                % (test_loss/(batch_idx+1), 100.*correct/total, correct, total))

    # Save checkpoint.
    acc = 100.*correct/total

    if acc > best_acc:
        print ('Saving...')
        state = {
            'net': net.state_dict(),
            'acc': acc,
            'epoch': epoch,
        }
        if not os.path.isdir('checkpoint_sens'):
            os.mkdir('checkpoint_sens' )
        if not os.path.isdir('training_outputs'):
            os.mkdir('training_outputs')
        torch.save(state, './checkpoint_sens/ckpt_%d.t7' % epoch)
        torch.save(state, './checkpoint_sens/ckpt.t7' )
        best_acc = acc

    return test_loss/len(testloader), 100.*correct/total, score

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='PyTorch nEXO background rejection')
    parser.add_argument('--resume', '-r', action='store_true', help='resume from checkpoint')
    parser.add_argument('--start', '-s', type=int, default=0, help='start epoch')
    parser.add_argument('--config', '-f', type=str, default="baseline.yml", help="specify yaml config")

    args = parser.parse_args()
    # parameters
    config = yaml_load(args.config)
    data_name = config['data']['name']
    h5file = config['data']['h5name']
    fcsv = config['data']['csv']
    input_shape = [int(i) for i in config['data']['input_shape']]
    lr = config['fit']['compile']['initial_lr']
    batch_size = config['fit']['batch_size']
    epochs = config['fit']['epochs']

    # Data
    print('==> Preparing data..')
    nEXODataset = CathodeSimData(fcsv, h5file)
    # Creating data indices for training and validation splits:
    dataset_size = len(nEXODataset)
    indices = list(range(dataset_size))
    validation_split = .2
    split = int(np.floor(validation_split * dataset_size))
    shuffle_dataset = True
    random_seed= 40
    if shuffle_dataset :
        np.random.seed(random_seed)
        np.random.shuffle(indices)
    train_indices, val_indices = indices[split:], indices[:split]

    # Creating PT data samplers and loaders:
    train_sampler = SubsetRandomSampler(train_indices)
    validation_sampler = SubsetRandomSampler(val_indices)
    train_loader = torch.utils.data.DataLoader(nEXODataset, batch_size=batch_size, sampler=train_sampler, num_workers=2)
    validation_loader = torch.utils.data.DataLoader(nEXODataset, batch_size=batch_size, sampler=validation_sampler, num_workers=2)

    start_epoch = 0

    print('==> Building model..')
    net = resnet18(input_channels=input_shape[2])
    # Define loss function (criterion) and optimizer
    criterion = nn.CrossEntropyLoss().cuda()
    # We use SGD
    # optimizer = torch.optim.SGD(net.parameters(), lr, momentum=momentum, weight_decay=weight_decay)
    # optimizer = torch.optim.Adam(net.parameters(), lr=lr)
    optimizer = torch.optim.AdamW(net.parameters(), lr=lr, betas=(0.9, 0.999),
                                  weight_decay=1e-4, eps=1e-08, amsgrad=False)

    net = net.to(device)

    if torch.cuda.device_count() > 1:
        print("Let's use ", torch.cuda.device_count(), " GPUs!")
        net = torch.nn.DataParallel(net, device_ids=list(range(torch.cuda.device_count())))

    if args.resume and os.path.exists('./checkpoint_sens/ckpt.t7'):
        # Load checkpoint.
        print('==> Resuming from checkpoint..')
        assert os.path.isdir('checkpoint_sens'), 'Error: no checkpoint directory found!'
        if device == 'cuda':
            checkpoint = torch.load('./checkpoint_sens/ckpt.t7' )
        else:
            checkpoint = torch.load('./checkpoint_sens/ckpt.t7', map_location=torch.device('cpu') )
        net.load_state_dict(checkpoint['net'])
        best_acc = checkpoint['acc']
        start_epoch = checkpoint['epoch'] + 1

    # Numpy arrays for loss and accuracy, if resume from check point then read the previous results
    if args.resume and os.path.exists('./training_outputs/loss_acc.npy'):
        arrays_resumed = np.load('./training_outputs/loss_acc.npy', allow_pickle=True)
        y_train_loss = arrays_resumed[0]
        y_train_acc  = arrays_resumed[1]
        y_valid_loss = arrays_resumed[2]
        y_valid_acc  = arrays_resumed[3]
        test_score   = arrays_resumed[4].tolist()
    else:
        y_train_loss = np.array([])
        y_train_acc  = np.array([])
        y_valid_loss = np.array([])
        y_valid_acc  = np.array([])
        test_score   = []

    for epoch in range(start_epoch, start_epoch + epochs):
        # Set the learning rate
        adjust_learning_rate(optimizer, epoch, lr)
        iterout = "\nEpoch [%d]: "%(epoch)

        for param_group in optimizer.param_groups:
            iterout += "lr=%.3e"%(param_group['lr'])
            print(iterout)
            try:
                train_ave_loss, train_ave_acc = train(train_loader, epoch)
            except Exception as e:
                print("Error in training routine!")
                print(e.message)
                print(e.__class__.__name__)
                traceback.print_exc(e)
                break
            print("Train[%d]: Result* Loss %.3f\t Accuracy: %.3f"%(epoch, train_ave_loss, train_ave_acc))
            y_train_loss = np.append(y_train_loss, train_ave_loss)
            y_train_acc = np.append(y_train_acc, train_ave_acc)

            # Evaluate on validationset
            try:
                valid_loss, prec1, score = test(validation_loader, epoch)
            except Exception as e:
                print("Error in validation routine!")
                print(e.message)
                print(e.__class__.__name__)
                traceback.print_exc(e)
                break

            print("Test[%d]: Result* Loss %.3f\t Precision: %.3f"%(epoch, valid_loss, prec1))

            test_score.append(score)
            y_valid_loss = np.append(y_valid_loss, valid_loss)
            y_valid_acc = np.append(y_valid_acc, prec1)

            np.save('./training_outputs/loss_acc.npy', np.array([y_train_loss, y_train_acc, y_valid_loss, y_valid_acc, test_score], dtype=object))


# -*- coding: utf-8 -*-
"""
Created on Thu Feb 11 13:30:06 2016

@author: haell
"""

import numpy as np
import pylab as pl

def euler(a,b,f,y0,n):
    Y = [y0]
    for k in range(0, n-1):
        Y.append((b-a)/n*f(Y[k], X[k]) + Y[k])
    return Y

def f(y, t):
    return (-3*t / y) + (5 / t**3)

y0 = 1

X = np.linspace(0, 1, 10)
Y = euler(1, 4, f, y0, 10)
pl.plot(X, Y)


import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint

# define mixing model
def mixer(x,t,Tf,Caf):
    # Inputs (2):
    # Tf = Feed Temperature (K)
    # Caf = Feed Concentration (mol/L)
    # States (2):
    # Concentration of A (mol/L)
    Ca = x[0]
    # Parameters:
    # Volumetric Flowrate (m^3/hr)
    q = 100
    # Volume of CSTR (m^3)
    V = 100
    # Calculate concentration derivative
    dCadt = q/V*(Caf - Ca)
    return dCadt

# Initial Condition
Ca0 = 0.0
# Feed Temperature (K)
Tf = 300
# Feed Concentration (mol/L)
Caf = 1
# Time Interval (min)
t = np.linspace(0,10,100)

# Simulate mixer
Ca = odeint(mixer,Ca0,t,args=(Tf,Caf))

# Construct results and save data file
# Column 1 = time
# Column 2 = concentration
data = np.vstack((t,Ca.T)) # vertical stack
data = data.T             # transpose data
np.savetxt('data.txt',data,delimiter=',')

# Plot the results
plt.plot(t,Ca,'r-',linewidth=3)
plt.ylabel('Ca (mol/L)')
plt.legend(['Concentration'],loc='best')
plt.xlabel('Time (hr)')
plt.show()


import math
import random
#import matplotlib.pyplot as plt
import numpy as np

E=1e-8
DEBUG=False
__all__ = ['ball_in_box']

def ball_in_box(m=5, blockers=[(0.5, 0.5), (0.5, -0.5), (0.5, 0.3)]):
    """
    m is the number circles.
    n is the list of coordinates of tiny blocks.

    This returns a list of tuple, composed of x,y of the circle and r of the circle.
    """

    # The following is an example implementation.
    conditions=[(0,),(1,),(2,),(3,)] #x=1 x=-1 y=1 y=-1
    conditions.extend(list((i[0],i[1],0) for i in blockers))

    circles = []
    for p in range(0,m):
        con_len=len(conditions)
        re=[]
        for a in ((i,j,k) for i in range(0,con_len-2) for j in range (i+1,con_len-1) for k in range(j+1,con_len)):
            condition=list(conditions[t] for t in a)
            tmp=get_circle(condition)
            #print("a:",a,"  c:",tmp)
            if tmp is not None:
                re.extend(tmp)

        re=list(i[0][-1] for i in list(filter(my_validate,list((circles+[i],blockers) for i in re))))
        tmp=re[0]
        for c in re:
            if c[2]>tmp[2]:
                tmp=c
        circles.append(tmp)
        conditions.append(tmp)
        if DEBUG:
            print("re:",re,"\n")
            print("conditions:",conditions,"\n")
            print("circles:",circles,"\n")
    if DEBUG:
        draw(blockers,circles)

    return list((c[0],c[1],c[2]-E) for c in circles)

def my_validate(c):
    circles=c[0]
    blockers=c[1]
    for circle in circles:
        xmr = circle[0] - circle[2]
        xpr = circle[0] + circle[2]
        ymr = circle[1] - circle[2]
        ypr = circle[1] + circle[2]

        if (not (xmr <= 1+E and xmr >=-1-E )) \
           or (not (xpr <= 1+E and xpr >=-1-E )) \
           or (not (ymr <= 1+E and ymr >=-1-E )) \
           or (not (ypr <= 1+E and ypr >=-1-E )):
            #print("0",circle)
            return False

    # Is circle good for blockers?
    if blockers is not None and len(blockers) > 0:
        for circle in circles:
            for block in blockers:
                x = circle[0]
                y = circle[1]
                r = circle[2]
                bx = block[0]
                by = block[1]
                if math.sqrt((x - bx)**2 + (y - by)**2) -r< -E:
                    #print("1",circle)
                    return False

    # Is circle good for each other?
    i=0
    for circle1 in circles[:-1]:
        i+=1
        for circle2 in circles[i:]:
            x1 = circle1[0]
            y1 = circle1[1]
            r1 = circle1[2]
            x2 = circle2[0]
            y2 = circle2[1]
            r2 = circle2[2]
            if math.sqrt((x1 - x2)**2 + (y1 - y2)**2) -(r1 + r2)<-E:
                #print("math:",math.sqrt((x1 - x2)**2 + (y1 - y2)**2),'  ',r1 + r2)
                #print("2",circle)
                return False
    # all good
    return True
'''
def draw(blockers,circles):
    fig=plt.figure()
    ax=fig.gca()
    plt.xlim((-1,1))
    plt.ylim((-1,1))

    for i in blockers:
        plt.scatter(i[0],i[1],color='', marker='o', edgecolors='g', s=20)
    for i in circles:
        if len(i)==1:
            continue
        circle = plt.Circle((i[0], i[1]), i[2], color='r',fill=False)
        ax.add_artist(circle)
    plt.show()
'''
'''
    构建一个圆
    返回值为（x,y,r）
    condition=【（），（），（）】，其中元组为 圆(x,y,r)
    PS：直线抽象成圆
'''
def get_circle(condition):
    len_con=list(len(i) for i in condition)

    if len_con[0]==1 and len_con[1]==1 and len_con[2]==1:
        return get_circle_three_line(condition)

    if len_con[0]==1 and len_con[1]==1:
        x=condition[2][0]
        y=condition[2][1]
        r=condition[2][2]

        if condition[0][0]==0 and condition[1][0]==1:
            return get_circle_two_line_1(condition)
        if condition[0][0]==2 and condition[1][0]==3:
            tmp=[]
            tmp.extend(condition[:-1])
            tmp.append((y,x,r))
            re=get_circle_two_line_1(tmp)
            return list((i[1],i[0],i[2]) for i in re)

        if condition[0][0]==0 and condition[1][0]==2: #x=1,y=1
            return get_circle_two_line_2(condition)
        if condition[0][0]==0 and condition[1][0]==3: #x=1,y=-1
            tmp=[]
            tmp.extend(condition[:-1])
            tmp.append((x,-y,r))
            re=get_circle_two_line_2(tmp)
            if re is not None:
                return list((i[0],-i[1],i[2]) for i in re)
        if condition[0][0]==1 and condition[1][0]==2: #x=-1,y=1
            tmp=[]
            tmp.extend(condition[:-1])
            tmp.append((-x,y,r))
            re=get_circle_two_line_2(tmp)
            if re is not None:
                return list((-i[0],i[1],i[2]) for i in re)
        if condition[0][0]==1 and condition[1][0]==3: #x=-1,y=-1
            tmp=[]
            tmp.extend(condition[:-1])
            tmp.append((-x,-y,r))
            re=get_circle_two_line_2(tmp)
            if re is not None:
                return list((-i[0],-i[1],i[2]) for i in re)
        return None
    if len_con[0]==1 :
        x0=condition[1][0]
        y0=condition[1][1]
        r0=condition[1][2]
        x1=condition[2][0]
        y1=condition[2][1]
        r1=condition[2][2]

        if condition[0][0]==0:  #x=1
            return get_circle_one_line(condition)
        if condition[0][0]==1:  #x=-1
            tmp=[condition[0]]
            tmp.extend([(-x0,y0,r0),(-x1,y1,r1)])
            re=get_circle_one_line(tmp)
            if re is not None:
                return list((-i[0],i[1],i[2]) for i in re)
        if condition[0][0]==2:  #y=1
            tmp=[condition[0]]
            tmp.extend([(y0,x0,r0),(y1,x1,r1)])
            re=get_circle_one_line(tmp)
            if re is not None:
                return list((i[1],i[0],i[2]) for i in re)
        if condition[0][0]==3:  #y=-1
            tmp=[condition[0]]
            tmp.extend([(-y0,x0,r0),(-y1,x1,r1)])
            re=get_circle_one_line(tmp)
            if re is not None:
                return list((i[1],-i[0],i[2]) for i in re)
        return None
    return get_circle_zero_line(condition)

def get_circle_three_line(condition):
    return [(0.0,0.0,1.0)]

def get_circle_two_line_1(condition):
    a1=condition[2][0]
    b1=condition[2][1]
    r1=condition[2][2]
    derta=(r1+1)**2-a1**2
    y_0=b1+derta**0.5
    y_1=b1-derta**0.5
    return [(0,y_0,1),(0,y_1,1)]

def get_circle_two_line_2(condition):
    a1=condition[2][0]
    b1=condition[2][1]
    r1=condition[2][2]

    b=-2*(a1+b1-r1-1)
    c=a1**2+b1**2-(r1+1)**2
    derta=b**2-4*c
    if math.fabs(derta)<E:
        x=-b/2
        return [(x,x,1-x)]
    if derta>0:
        x_0=(-b+derta**0.5)/2
        x_1=(-b-derta**0.5)/2
        return [(x_0,x_0,1-x_0),(x_1,x_1,1-x_1)]

    return None

def get_circle_one_line(condition):
    a1=condition[1][0]
    b1=condition[1][1]
    r1=condition[1][2]
    a2=condition[2][0]
    b2=condition[2][1]
    r2=condition[2][2]

    m1=2*(r1+1-a1)
    n1=a1**2-(r1+1)**2+b1**2
    m2=2*(r2+1-a2)
    n2=a2**2-(r2+1)**2+b2**2

    if math.fabs(m1-m2)<E:
        if math.fabs(2*b1*m2-2*b2*m1)<E:
            return None
        y_0=(n1*m2-n2*m1)/(2*b1*m2-2*b2*m1)
        x_0=-(n1+y_0**2-2*b1*y_0)/m1
        return [(x_0,y_0,1-x_0)]
    a=m2-m1
    b=-(2*b1*m2-2*b2*m1)
    c=(n1*m2-n2*m1)
    derta=b**2-4*a*c
    if math.fabs(derta)<E:
        y_0=-b/2.0/a
        x_0=-(n1+y_0**2-2*b1*y_0)/m1
        return [(x_0,y_0,1-x_0)]
    if derta>0:
        y_0=(-b+derta**0.5)/2.0/a
        x_0=-(n1+y_0**2-2*b1*y_0)/m1
        y_1=(-b-derta**0.5)/2.0/a
        x_1=-(n1+y_1**2-2*b1*y_1)/m1
        return [(x_0,y_0,1-x_0),(x_1,y_1,1-x_1)]
    return None

def get_circle_zero_line(condition):
    a1 = condition[0][0]
    b1 = condition[0][1]
    r1 = condition[0][2]
    a2 = condition[1][0]
    b2 = condition[1][1]
    r2 = condition[1][2]
    a3 = condition[2][0]
    b3 = condition[2][1]
    r3 = condition[2][2]

    'm1*x+n1*y+p1*r+q1=0'
    m1 = 2 * (a1 - a2)
    n1 = 2 * (b1 - b2)
    p1 = 2 * (r1 - r2)
    q1 = a2 ** 2 - a1 ** 2 + b2 ** 2 - b1 ** 2 + r1 ** 2 - r2 ** 2
    m2 = 2 * (a1 - a3)
    n2 = 2 * (b1 - b3)
    p2 = 2 * (r1 - r3)
    q2 = a3 ** 2 - a1 ** 2 + b3 ** 2 - b1 ** 2 + r1 ** 2 - r3 ** 2

    if math.fabs(n1*m2-n2*m1)<E:
        if math.fabs(p1*m2-p2*m1)<E:
            if math.fabs(p1 * n2 - p2 * n1) < E:
                return None
            else:
                r0 = -float(q1 * n2 - q2 * n1) / (p1 * n2 - p2 * n1)
                if math.fabs(m1) < E:
                    y0 = -float(p1 * r0 + q1) / n1
                    s = (r0 + r1) ** 2 - (y0 - b1) ** 2
                    if s >= 0:
                        x01 = a1 + math.sqrt(s)
                        x02 = a1 - math.sqrt(s)
                        return [(x01, y0, r0), (x02, y0, r0)]
                    elif s >= -E:
                        x0=a1
                        return [(x0, y0, r0)]
                    else:
                        return None
                else:
                    'y=ky*x+hy'
                    ky = -float(m1) / n1
                    hy = -float(p1 * r0 + q1) / n1

                    'ay**2*x+by*x+cy=0'
                    ay = ky ** 2 + 1
                    by = 2 * (ky * hy - ky * b1 - a1)
                    cy = (hy - b1) ** 2 + a1 ** 2 - (r0 + r1) ** 2
                    dertay = by ** 2 - 4 * ay * cy
                    if dertay >= 0:
                        x01 = float(-by + math.sqrt(dertay)) / (2 * ay)
                        x02 = float(-by - math.sqrt(dertay)) / (2 * ay)
                        return [(x01, ky * x01 + hy, r0), (x02, ky * x02 + hy, r0)]
                    elif math.fabs(dertay) >= -E:
                        x0 = float(-by) / (2 * ay)
                        return [(x0, ky * x0 + hy, r0)]
                    else:
                        return None
        else:
            r0=-float(q1*m2-q2*m1)/(p1*m2-p2*m1)
            if math.fabs(m1)<E:
                y0=-float(p1*r0+q1)/n1
                s=(r0+r1)**2-(y0-b1)**2
                if s>=0:
                    x01=a1+math.sqrt(s)
                    x02=a1-math.sqrt(s)
                    return [(x01,y0,r0),(x02,y0,r0)]
                elif s>=-E:
                    x0=a1
                    return [(x0,y0,r0)]
                else:
                    return None
            else:
                'x=kx*y+hx'
                kx=-float(n1)/m1
                hx=-float(p1*r0+q1)/m1

                'ax**2*y+bx*y+cx=0'
                ax=kx**2+1
                bx=2*(kx*hx-kx*a1-b1)
                cx=(hx-a1)**2+b1**2-(r0+r1)**2
                dertax=bx**2-4*ax*cx
                if dertax>=0:
                    y01 = float(-bx + math.sqrt(dertax)) / (2 * ax)
                    y02 = float(-bx - math.sqrt(dertax)) / (2 * ax)
                    return [(kx*y01+hx,y01,r0),(kx*y02+hx,y02,r0)]
                elif math.fabs(dertax)>=-E:
                    y0= float(-bx ) / (2 * ax)
                    return [(kx*y0+hx,y0,r0)]
                else:
                    return None
    else:
        'y=k1*r+h1'
        k1 = float(p1 * m2 - p2 * m1) / (n2 * m1 - n1 * m2)
        h1 = float(q1 * m2 - q2 * m1) / (n2 * m1 - n1 * m2)
        k2 = float(p1 * n2 - p2 * n1) / (n1 * m2 - n2 * m1)
        h2 = float(q1 * n2 - q2 * n1) / (n1 * m2 - n2 * m1)

        'a*r**2+b*r+c=0'
        a = k1 ** 2 + k2 ** 2 - 1
        b = 2 * (k2 * h2 + k1 * h1 - a1 * k2 - b1 * k1 - r1)
        c = a1 ** 2 + b1 ** 2 + h1 ** 2 + h2 ** 2 - 2 * a1 * h2 - 2 * b1 * h1 - r1 ** 2
        derta = b ** 2 - 4 * a * c

        '只存在一个解'
        if math.fabs(a) < E:
            r0 = -float(c) / b
            x0 = k2 * r0 + h2
            y0 = k1 * r0 + h1
            return [(x0, y0, r0)]
        '存在两个解'
        if derta >= 0:
            r01 = float(-b + math.sqrt(derta)) / (2 * a)
            r02 = float(-b - math.sqrt(derta)) / (2 * a)
            if r01 >= -E:
                x0 = k2 * r01 + h2
                y0 = k1 * r01 + h1
                return [(x0, y0, r01)]
            else:
                x0 = k2 * r02 + h2
                y0 = k1 * r02 + h1
                return [(x0, y0, r02)]
        elif derta >= -E:
            r0 = float(-b) / (2 * a)
            x0 = k2 * r0 + h2
            y0 = k1 * r0 + h1
            return [(x0, y0, r0)]
        else:
            return None

def if_line(condition):
    a1 = condition[0][0]
    b1 = condition[0][1]
    a2 = condition[1][0]
    b2 = condition[1][1]
    a3 = condition[2][0]
    b3 = condition[2][1]
    if 0==(b2-b1)*(a3-a1)-(b3-b1)*(a2-a1):
        return True
    else:
        return False

if __name__=='__main__':
    conditions=[[(0,),(1,),(2,)],
               [(1,),(2,),(3,)],

               [(0,),(1,),(0,0,0)],
               [(0,),(1,),(0.5,0.5,0.2)],
               [(2,),(3,),(0.5,0.5,0.2)],

               [(0,),(2,),(0.5,0.5,0.2)],
               [(0,),(2,),(-0.5,0.5,0.2)],
               [(0,),(3,),(0.5,0.5,0.2)],
               [(1,),(2,),(0.5,0.5,0.2)],
               [(1,),(3,),(0.5,0.5,0.2)],

               [(0,),(0.5,-0.5,0.2),(0.5,0.5,0.2)],
               [(0,),(0,0,0.3),(0.5,0.5,0.2)],
               [(1,),(0,0,0.3),(0.5,0.5,0.2)],
               [(2,),(0,0,0.3),(0.5,0.5,0.2)],
               [(3,),(0,0,0.3),(0.5,0.5,0.2)],

               [(0,0.6,0.1),(0,0,0.3),(0.5,-0.5,0.2)],
               [(0,0.6,0.1),(0,0,0.3),(0,-0.5,0.2)],
               [(0,0.6,0.3),(0,0,0.1),(0,-0.5,0.2)],  #None?
               [(0,0.5,0.2),(0,0,0.1),(0,-0.5,0.2)],
               ]
    condition=conditions[-1]
    condition=[(-0.19666666666666666, 0.1, 0.8033333333333333),(0.6592269448766501, -0.6592269448766501, 0.3407730551233499)]
    re=None
    #re=get_circle(condition)
    print(condition,re)
    if re is not None:
        condition+=re
    draw([],condition)


import csv

class Test(object):
    def __init__(self, text1, text2, score, save_path="/tmp/", filename="test.csv"):
        self.text1 = text1
        self.text2 = text2
        self.score = score
        self.save_path = save_path
        self.filename = filename

        self.save_string = [self.text1, self.text2, self.score]

        self.save_results()

    def __repr__(self):
        return '<Text 1: {}\nText 2: {}\nResult {}>'.format(self.text1, self.text2, self.score)

    def save_results(self):
        with open(self.save_path+self.filename, mode='w') as w_file:
            file_writer = csv.writer(w_file, delimiter='\t')

            file_writer.writerow(self.save_string)


import requests
from bs4 import BeautifulSoup
import re
import os

# ----------------------- 方法一：用re正在表达式解析 ---------------------------------
def re_parse_url(html):
    restr = '<li>.*?href="(.*?)".*?extiw'
    patern = re.compile(restr, re.S)
    items = re.findall(patern, html)
    print(items)

# ----------------------- 方法二：用BeautifulSoup解析库解析 ------------------------------
def parse_page_url(html):

    soup = BeautifulSoup(html, 'lxml')
    li_lists = soup.find_all(name='ul')[0].find_all(name='li')
    # print(li_lists)
    count = 0
    # temp_lists = []
    temp_dict = {}
    for li in li_lists:
        count += 1
        if count <= 8:
            a_lists = li.find_all(name='a')[0]

            a_url = "http:" + a_lists.attrs['href']
            end_word = a_url.replace('ebooks', 'cache/epub').split('/')[-1]
            end_url = a_url.replace('ebooks', 'cache/epub') + "/pg" + end_word + ".txt"
            # print(a_url)
            # temp_lists.append(end_url)
            temp_dict[end_word] = end_url
        else:
            break
        # print(a_lists.attrs['href'])
    return temp_dict

def get_page_url(main_url):
    response = requests.get(main_url)
    if response.status_code == 200:
        # print(response.text)
        return response.text
    return None
    # soup = BeautifulSoup(html, 'lxml')

def save_text(url_dicts):
    file_dir = os.path.join(os.getcwd(), 'result')
    if not os.path.exists(file_dir):
        os.mkdir(file_dir)
    for urlkey, urlvalue in url_dicts.items():
        content = get_page_url(urlvalue)
        file_path = os.path.join(file_dir, urlkey) + '.txt'
        if not os.path.exists(file_path):
            with open(file_path, 'w', encoding='utf-8') as f:
                f.write(content)
                # f.close()

def main():
    main_url = "https://www.gutenberg.org/wiki/Education"
    print("开始爬取目标URL......")
    html = get_page_url(main_url)   # 根据目标URL获得HTML
    # print(html)
    print("获取HTML成功！正在解析HTML......")
    # re_parse_url(html)    # 方法一：
    url_dicts = parse_page_url(html)    # 方法二：解析HTML，返回字典
    print("解析HTML成功！正在保存爬取的数据......")
    save_text(url_dicts)    # 保存文本
    print("数据保存成功！已完成爬取！")

if __name__ == '__main__':
    main()


# -*- coding: utf-8 -*-
import metadata.rule as rule

def check_record(records, result, event_type):

    item = dict()
    item['check_point'] = 'act_report_numbers'
    item['type'] = 'report_number'
    item['result'] = ''
    item['reason'] = {}
    item['data'] = {}

    if len(records) == 1:
        item['result'] = 'success'

    elif len(records) == 0:
        item['result'] = 'failure'
        item['reason']['number'] = 'query no data '
    else:
        item['result'] = 'failure'
        item['reason']['number'] = 'query data number was not 1'

    result['items'].append(item)
    return

def check_retry(records, result, event_type):

    item = dict()
    item['check_point'] = 'ip_retry_times'
    item['type'] = 'retry_times'
    item['result'] = ''
    item['reason'] = {}
    item['data'] = {}

    count = len(records)
    if count != 3:
        item['result'] = 'failure'
        item['reason'] = {'error': 'retry times set was 3, but was ' + str(count)}
    else:
        item['result'] = 'success'
        item['reason'] = {}

    result['items'].append(item)

def check(records, result, event_type):

    # retry case
    if event_type in ['cdn_if1_ip_retry_video', 'cdn_if1_ip_retry_channel']:
        check_retry(records, result, event_type)
        return

    check_record(records, result, event_type)
    for r in records:
        data_check(r, result, event_type)

def data_check(record, result, event_type):
    if 'if1' in event_type:
        if 'channel' in event_type:
            act = 'cdn_if1_c'
        else:
            act = 'cdn_if1_v'
    else:
        if 'channel' in event_type:
            act = 'cdn_if2_c'
        else:
            act = 'cdn_if2_v'

    item = dict()
    item['check_point'] = act
    item['type'] = 'field_check'
    item['result'] = ''
    item['reason'] = {}
    item['data'] = {}

    result['items'].append(item)

    item['data']['act'] = act
    item['data']['time'] = record['time2']

    tool = rule.CheckTool(act, event_type)
    tool.check_service(record, item['reason'])
    rule.get_data(record, item['data'])

    if len(item['reason']) == 0:
        item['result'] = 'success'
    else:
        item['result'] = 'failure'

    item2 = dict()
    item2['check_point'] = act + '_report_time'
    item2['type'] = 'report_time'
    item2['result'] = 'success'
    item2['reason'] = {}
    item2['data'] = {}
    result['items'].append(item2)

if __name__ == "__main__":
    pass


import os

max_iteraci = int(input('Zadej maximální počet iterací: '))

for _ in range(max_iteraci):
	os.system('python vygeneruj_vstup.py >> vstup.txt')
	os.system('python A.py < vstup.txt > vystupA.txt')
	os.system('python B.py < vstup.txt > vystupB.txt')
	neshoda = False
	with open('vystupA.txt') as Aout, open('vystupB.txt') as Bout:
		for line in Aout:
			if line != Bout.readline():
				print('Nalezena neshoda.')
				neshoda = True
				break
	if neshoda:
		break
else:
	print('Programy se shodují pro všech {} vstupů.'.format(max_iteraci))

input()