# -*- coding: utf-8 -*-

import re
import numpy as np
from datetime import datetime
from matplotlib import pyplot as plt

from .utils import rgb_dist, detect_consecutive_false, to_gray
from .utils import str_to_num_rank, num_to_str_rank
from .colors import BEIGE, GRAY, DGRAY, LGRAY, GREEN, BLACK
from .classifiers import LabelClassifier, CaptionJaClassifier, CaptionEnClassifier

class Graph:
    image = None
    def __init__(self, image):
        self.image = image

    def plot(self, show=True):
        if self.image is None: return
        plt.imshow(self.image)
        if show: plt.show()

    def get_num_grids(self):
        """
        Detect the number of gird lines
        """
        im = self.image
        if im is None or im.shape[0] < 1 or im.shape[1] < 1:
            return None

        thres_dist = 0.1
        thres_frac = 0.9
        mostly_gray = (rgb_dist(im, GRAY) < thres_dist)  | \
                      (rgb_dist(im, DGRAY) < thres_dist) | \
                      (rgb_dist(im, LGRAY) < thres_dist)

        frac = np.mean(mostly_gray, axis=1)
        gray_index = (frac > thres_frac).nonzero()[0]

        if len(gray_index) == 0: return 0
        return 1 + np.sum(np.diff(gray_index) > 1)

    def get_line_index(self):
        """
        Detect line position in the graph image

        Returns
          numpy array of the same length as the image's width
        """

        im = self.image
        if im is None or im.shape[0] < 1 or im.shape[1] < 1:
            return np.empty(0)

        # compute distance from green, black, gray and find the
        # cells that are closest to green
        dist_green = rgb_dist(im, GREEN)
        thres_dist = 0.35

        # change distance of cells for enough from green to 1
        # later, if colwise minimum is 1,
        # then the column is regarded as having no line
        dist_green[dist_green > thres_dist] = 1.0

        min_dist = np.min(dist_green, axis=0)
        has_line = np.where(min_dist < 1.0)[0]

        out = np.empty(im.shape[1])
        out[:] = np.nan
        for j in has_line:
            min_index = np.where(dist_green[:,j] == min_dist[j])[0]
            out[j] = np.mean(min_index)
            #out[j] = np.average(np.arange(im.shape[0]),\
            #                    weights=1.0-dist_green[:,j])

        return out

# this is shared by all instances of Yaxis
label_classifier = LabelClassifier()

class Yaxis:
    image = None
    nlabels = None

    def __init__(self, image):
        self.image = image
        self.classifier = label_classifier

    def plot(self, show=True):
        if self.image is None: return
        plt.imshow(self.image)
        if show: plt.show()

    def get_rank_range(self, positions):
        """
        Returns the min and max of y-axis labels

        Args
          positions: expected indices of labels.

        Returns
          tuple of strings such as (2k, 1d)
        """
        label_list = self.get_label_list(positions)
        ranks = ['' if l is None else self.classifier.predict(l) \
                 for l in label_list]
        #print(len(label_list))
        #print(ranks)

        # look for the max rank from the top
        max_rank = None
        i = 0
        while i < len(ranks):
            if ranks[i] == '':
                i += 1
                continue
            n = str_to_num_rank(ranks[i])
            if not np.isnan(n):
                max_rank = num_to_str_rank(n+i)
                break
            i += 1
        if max_rank is None: return ()

        # look for the min rank from the bottom
        min_rank = None
        i = 0
        while i < len(ranks):
            j = len(ranks)-i-1
            if ranks[j] == '':
                i += 1
                continue
            n = str_to_num_rank(ranks[j])
            if not np.isnan(n):
                min_rank = num_to_str_rank(n-i)
                break
            i += 1
        if min_rank is None: return ()

        return (min_rank, max_rank)

    def get_label_list(self, positions):
        """
        make Y-axis labal data

        Args
          positions: expected indices of labels.

        Returns
          list of (list of 2d-arrays) or None, where (i,j) element indicates
          the j-th letter of i-th label.
          (r, c) element of the 2d-array is the gray scale of cell (r,c)
        """
        image = self.image
        if image is None: return []
        if image.size == 0: return []

        thres_dist = 0.1
        thres_frac = 0.95

        def is_background(arr):
            dist = rgb_dist(arr, BEIGE)
            frac = np.mean(dist < thres_dist)
            return frac >= thres_frac

        # extract labels rows
        # start from position and expand the area up and down
        # until we hit background
        labels = []
        index_checked = [False] * image.shape[0]
        for p in positions:
            index_to_check = [p]
            i1 = image.shape[0]
            i2 = -1
            while len(index_to_check) > 0:
                i = index_to_check.pop()
                index_checked[i] = True

                flg = is_background(image[i])
                if not flg:
                    # new non-background is found so exand the area
                    i1 = min(i1, i)
                    i2 = max(i2, i)

                    if i-1 >= 0 and not index_checked[i-1]:
                        index_to_check.append(i-1)
                    if i+1 < image.shape[0] and not index_checked[i+1]:
                        index_to_check.append(i+1)
            if i1 <= i2:
                #print(i1, i2)
                labels.append(image[i1:(i2+1)])
            else:
                labels.append(None)

        # split labels into letters
        def split_to_letters(label):
            if label is None: return None
            dist = rgb_dist(label, BEIGE)
            frac = np.mean(dist < thres_dist, axis=0)
            is_background = (frac >= thres_frac)
            #start = np.where(np.logical_and(
            #    np.logical_not(is_background),
            #    np.append(True, is_background[0:-1])))[0]
            #end = np.where(np.logical_and(
            #    np.logical_not(is_background),
            #    np.append(is_background[1:], True)))[0] + 1
            start, end = detect_consecutive_false(is_background)
            return [label[:, a:b] for a,b in zip(start, end)]
        letters = [split_to_letters(label) for label in labels]

        # convert to gray scale
        for j in range(len(letters)):
            if letters[j] is None: continue
            for k in range(len(letters[j])):
                letters[j][k] = to_gray(letters[j][k], BEIGE, GRAY)

        return letters

    def extract_letters(self):
        """
        extract all sub images of letters

        Returns
          list of numpy arrays of shape (nrow, ncol)
          each element is the gray scale of the cell
        """
        image = self.image
        if image is None: return []
        if image.size == 0: return []

        thres_dist = 0.1
        thres_frac = 0.95

        dist = rgb_dist(image, BEIGE)
        is_beige = (dist < thres_dist)

        # identify rows of labels
        frac = np.mean(is_beige, axis=1)
        is_bg_row = (frac >= thres_frac)
        #row1 = np.where(np.logical_and(
        #    np.logical_not(is_bg_row),
        #    np.append(True, is_bg_row[0:-1])))[0]
        #row2 = np.where(np.logical_and(
        #    np.logical_not(is_bg_row),
        #        np.append(is_bg_row[1:], True)))[0] + 1
        row1, row2 = detect_consecutive_false(is_bg_row)

        def split_letters(i1, i2):
            frac = np.mean(is_beige[i1:i2], axis=0)
            is_bg_col = (frac >= thres_frac)
            #start = np.where(np.logical_and(
            #    np.logical_not(is_bg_col),
            #    np.append(True, is_bg_col[0:-1])))[0]
            #end = np.where(np.logical_and(
            #    np.logical_not(is_bg_col),
            #    np.append(is_bg_col[1:], True)))[0] + 1
            start, end = detect_consecutive_false(is_bg_col)
            return [image[i1:i2, a:b] for a,b in zip(start, end)]

        out = [split_letters(a,b) for a,b in zip(row1, row2)]
        # flatten
        out = sum(out, [])

        # convert to gray scale
        out = [to_gray(o, BEIGE, GRAY) for o in out]
        return out

# classifiers shared by all instances
caption_ja_classifier = CaptionJaClassifier()
caption_en_classifier = CaptionEnClassifier()

class Caption:
    image = None

    def __init__(self, image):
        self.image = image
        self.classifier_ja = caption_ja_classifier
        self.classifier_en = caption_en_classifier

    def plot(self, show=True):
        if self.image is None: return
        plt.imshow(self.image)
        if show: plt.show()

    def extract_letters(self):
        """
        extract all sub images of letters

        Returns
          list of numpy arrays of shape(nrow,ncol)
          each element is an image array.
          if asgray: each element is (nrow, ncol) shape
          otherwise: each element is (nrow, ncol, channel) shape
        """
        image = self.image
        if image is None: return []
        if image.size ==0: return []

        thres_dist = 0.3
        thres_frac = 1.0

        dist = rgb_dist(image, BEIGE)
        is_beige = (dist < thres_dist)

        # find rows that have non-background
        not_bg_row = (np.mean(is_beige, axis=1) < thres_frac)
        if not np.any(not_bg_row): return []  # all background
        # the first and last index of non-background
        index = not_bg_row.nonzero()[0]
        i1 = index[0]
        i2 = index[-1]

        # split into letters
        frac = np.mean(is_beige[i1:(i2+1)], axis=0)
        is_bg_col = (frac >= thres_frac)
        start, end = detect_consecutive_false(is_bg_col)

        out = [image[i1:(i2+1), a:b] for a,b in zip(start, end)]

        # to gray scale
        for i in range(len(out)):
            out[i] = to_gray(out[i], BEIGE, GRAY)

        return out

    def get_time_range(self):
        letter_array_list = self.extract_letters()

        # Try Japanese parser first
        title = self.classifier_ja.predict(letter_array_list)
        #print(title)
        r = re.findall(r'(\d{2}/\d{2}/\d{2})(\d{1,2}:\d{1,2}){0,1}', title)
        if len(r) >= 2:
            def to_datetime(s):
                if s[1] == '':
                    return datetime.strptime(s[0], '%y/%m/%d')
                else:
                    return datetime.strptime(s[0] + ' ' + s[1], '%y/%m/%d %H:%M')
            out = [to_datetime(s) for s in r]
            return tuple(out)

        # if Japanese parser does not work, try English parser
        title = self.classifier_en.predict(letter_array_list)
        #print(title)
        r = re.findall(r'([A-Z05][A-Za-z0-9]{2})(\d{1,2}).(\d{4})', title)
        if len(r) >= 2:
            def to_datetime(s):
                a,b,c = s
                #print(a, b, c)
                for key in self.classifier_en.conversions:
                    a = a.replace(key, self.classifier_en.conversions[key])
                #print(a, b, c)
                if not (a in ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', \
                              'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']):
                    return None
                return datetime.strptime(a + ' ' + b + ' ' + c, '%b %d %Y')
            out = [to_datetime(s) for s in r[0:2]]
            if out[0] is None or out[1] is None: return()
            return tuple(out)
        return ()


import pytorch_lightning
from pytorch_lightning.trainer.trainer import Trainer
from pytorch_lightning.tuner.tuning import Tuner
from pytorch_lightning.callbacks import ModelCheckpoint, EarlyStopping
from dataset import PetsDataModule

# from model import ResnetTest
from model_mixup import ResnetTest
import config as Config

data_module = PetsDataModule(
    Config.DATA_DIR_BASE,
    Config.BATCH_SIZE,
    Config.NUM_WORKERS)

model = ResnetTest(
    num_classes=data_module.get_num_classes())

checkpoint_callback = ModelCheckpoint(dirpath="./checkpoints", save_top_k=5, monitor="val_accuracy", mode="max")
early_stop_callback = EarlyStopping(monitor="val_accuracy", min_delta=0.001, patience=25, verbose=True, mode="max")

trainer = Trainer(
    accelerator="gpu",
    devices=1,
    enable_checkpointing=True,
    # precision=16,
    callbacks=[checkpoint_callback, early_stop_callback])

# Pick point based on suggestion
# tuner = Tuner(trainer)
# lr_finder = tuner.lr_find(model, datamodule=data_module, min_lr=1e-08, max_lr=1e-3, num_training=250)
# new_lr = lr_finder.suggestion()
# print("new lr: ", new_lr)
# model.learning_rate = new_lr

trainer.fit(
    model,
    datamodule=data_module,
    ckpt_path="./checkpoints/epoch=126-step=93853-v1.ckpt")

trainer.test(
    model,
    datamodule=data_module)


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

#aqui se importa la libreria numpy, para poder aplicar sus funciones en las matrices
import numpy as np
#se importa la libreria os para realizar operaciones dependiente del Sistema Operativo
import os

# en esta parte se hacen condiciones para comparar el nombre sel sistema operativo,
#y asi poder definir el valor de la variable var que es el nombre de la funcion de limpieza de la consola
if os.name == "posix":
    #si la condicion anterior se cumple la variable var es igual a clear
    var = "clear"
elif os.name == "ce" or os.name == "nt" or os.name == "dos":
    # en caso de que cualquiera de las 3 condiciones de cumplan el valor de ver será cls
    var = "cls"

#esta es una funcion para validar que el numero recibido como parametro sea un entero
def OKI(n):
    #se usa try except para controlar el error y asi el programa no se detenga
    try:
        #intenta convertir el valor a entero
        n=int(n)
    except:
        #si falla al convertir, esta funcion se vuelve a llamar a sí misma para repetir el proceso
        n=OKI(input("Caracter no valido: "))
    #se retorna el valor convertido a entero
    return n

#funcion para validar un valor de tipo float
def OK(n):
    try:
        #intenta convertirel valor a un valor flotante
        n=float(n)
    except:
        # en caso de fallar lo anreior, esta funcion se vuelva a llamar a sí misma, y se repite el proceso
        n=OK(input("Caracter no valido: "))
    #se retorna el valor convertido a un valor flotante
    return n

#funcion que valida que el valor del parametro recibido sea una 's' o una 'n'
def ns(c):
    # ciclo que se ejecuta mientras el valor ingresado ses diferente de una 's' y una 'n'
    while c!=("s") and c!=("n"):
        #imprime un caracter
        print(chr(7));
        #vuelve a pedir el dato
        c=input("Escribe solo \'n\' o \'s\' según su opción: ").lower()
    #retorna el valor de c
    return(c)

#funcion que valida que el valor recibido como parametro sea una 'N' o una 'M'
def val(tp):
    #ciclo que se repite meintras el valor ingresado sea diferente de 'N' y 'N'
    while tp!="N" and tp!="M":
        #vuelve a capturar el dato
        tp=input("Introduzca \'N\' para dato numérico y \'M\' para matriz: ").upper()
    #retorna el valor
    return tp

#FUNCIÓN DE TIPO DE DATO
def dato():
    #llama a la funcion val enviandole el valor capturado
    tipo_dato=val(input("Tipo de dato: ").upper())
    #si el valor es 'M'
    if tipo_dato=="M":
        #llama a la funcion crea_matriz y  le envia los valores fil y col
        matr=crea_matriz(fil,col)
    else:
        #sino llama a la funcion OK
        matr=OK(input("Introduce número: "))
    # en base a las condiciones, retorna una matriz o un valor numerico
    return matr

#FUNCIÓN PARA DEFINIR MATRIZ
def crea_matriz(fil,col):
    #imprime un salto de linea
    print("")
    #inicializa las variables en -1
    f=-1;c=-1
    #crea un vector vacio para las filas
    e_fil=[]
    #ciclo que recorre el rango de las filas
    for f in range(fil):
        #crea un vector vacio para las columnas
        e_col=[]
        #incrementa f
        f+=1
        #ciclo que recorre el rango de las columnas
        for c in range(col):
            #increnta c
            c+=1
            #captura un numero,y lo valida con la funcion OK
            valor=OK(input('Introduzca el componente (%d,%d): '%(f,c)))
            #agrega el dato al vector de columnas
            e_col.append(valor)
        #agrega el vector de columnas al vector de fulas
        e_fil.append(e_col)
        #usa la funcion de numpy para crear uns mstriz con la lista bidimensional e_fil
        matri=np.array(e_fil,float)
    #retorna la matriz
    return matri

#ciclo para mostrar el menu de opciones
while True:
    #se imprimen las opciones
    print("          CALCULADORA DE MATRICES          ")
    print("""***********TABLA DE OPERADORES***********
*****************************************
SUMA                           OPERADOR "+"
RESTA                          OPERADOR "-"
MULTIPLICACIÓN                 OPERADOR "*"
FINALIZAR CALCULO              OPERADOR "C"
DATO MATRIZ                    OPERANDO "M"
DATO NÚMERO                    OPERANDO "N"
*****************************************
*******************************************\n""")
    #captura la variable fil, validandola con al funcion OKI
    fil=OKI(input("Indique número de filas: "))
    #captura la variable col, validandola con al funcion OKI
    col=OKI(input("Indique número de columnas: "))
    #en e guarda el valor de fil
    e=fil
    #inicializa f y c en -1
    f=-1;c=-1
    #crea una matriz con la funcion crea_matriz de tamaño fil*col
    acum=crea_matriz(fil,col)
    #imprime la matriz
    print("\nRESULTADO")
    print(acum,"\n")
    #ciclo para la parte de las operaciones
    while True:
        #captura el operador
        oper=input("Introduzca operador: ")
        #ciclo que se repite mientras la variable oper sea diferente de un +-* y C
        while oper!="+" and oper!="-" and oper!="*" and oper!="C":
            #vuelve a capturar el operador hasta que sea valido
            oper=input("Introduzca un operador válido: ")
        #si es +
        if oper=="+":
            #llama a la funcion dato y el valor retornado ya sea una matroz o un valor numerico lo guarda en matr
            matr=dato()
            #hace la operacion de suma
            acum=acum+matr
        #si es un -
        elif oper=="-":
            #llama a la funcion dato y el valor retornado ya sea una matroz o un valor numerico lo guarda en matr
            matr=dato()
            #realiza la operacion de resta
            acum=acum-matr
        #si es un *
        elif oper=="*":
            #llama a la funcion val para validar el tipo de dato
            tipo_dato=val(input("Tipo de dato: ").upper())
            #su el tipo de dato es 'M'
            if tipo_dato=="M":
                #guarda el calor de col en fil
                fil=col
                #captura el numero de columnas y lo valida con la funcion OKI
                col=OKI(input("Introduce número de columnas: "))
                #crea una matriz fil*col
                matr=crea_matriz(fil,col)
                #llama ala funcion del producto de puntos de numpy, y el valor retornado lo guarda en acum
                acum=np.dot(acum,matr)
                #guarda e en fil
                fil=e
            #sino
            else:
                #captura un numero
                matr=OK(input("Introduce número: "))
                #hace la operacion de multiplicacion de una matriz po un numero
                acum=acum*matr
        #si la opcion es diferente de 'C'
        if oper!="C":
            #muestra la matriz resultante
            print("\nRESULTADO")
            print(acum,"\n")
        #sino es niguna opcion
        else:
            #rompe el ciclo y continua con la flujo del programa
            break
    #captura una opcion y la valida con la  funcion ns
    conti=ns(input("¿Reiniciar cálculos?: ").lower())
    #si es n
    if conti=="n":
        #rompe el ciclo y termina la ejecucion
        break
    #continua la ejecicion y se repite todo el proceso
    #reinicia la variable matr
    matr=0
    #limpia la consola
    os.system(var)

# en general el programa cuenta con un menu de operaciones de mtrices, al inicio se crea una matriz de fil*col, se intrducen sus elementos
#se puede realizar operaciones como suma, resta y multiplicacion, ya sea con otra matriz o con un valor numerico
#en el menu contamos con la opcion de repetir calculos con nuevas matrices o tambien podemos finalizar para cerrar el programa.


# Grid Strategy
import asyncio
import json
from typing import Dict, Any, List
from datetime import datetime
from random import randint
from bisect import bisect_left
from multiprocessing import Process

from api.base_api import OrderType, Direction
from api.binance.binance_api import BinanceApi
from api.exchange import ExchangeidSymbolidAPI
from db.cache import RedisHelper
from base.consts import RedisKeys, BinanceWebsocketUri
from base.config import grid_logger as logger
import websockets
import pandas as pd
import click

from util.time_util import TimeUtil

DEBUG = True

class BinanceGridRobotV2(object):
    def __init__(self, exchange_api: BinanceApi, info: Dict[str, Any], info_key: str, trade_key: str, pair_key: str,
                 price_key: str):
        self.info = info
        self.exchange_api: BinanceApi = exchange_api
        self.redis = RedisHelper()

        # TODO: generate all price at init phrase
        self.all_prices: List[float] = []

        # keep digits same as exchange
        self.digits: int = self.exchange_api.symbol.price_precision

        # redis key related from above
        self.info_key: str = info_key
        self.trade_key: str = trade_key
        self.pair_key: str = pair_key
        self.price_key: str = price_key

        self.task_table = {
            "price": self.update_price,
            "order": self.keep_orders,
        }

        logger.info(
            f"successful init {self.exchange_api.api.exchange} grid robot,info is:\n {info}\n redis keys are {self.info_key, self.trade_key, self.pair_key, self.price_key} ")

    async def cancel(self, order_id: str, price: str):
        try:
            order_detail = self.redis.hget(redis_key=self.trade_key, key=price)
            if order_detail and order_detail != "H" and order_detail != "OnGoing":
                result = await self.exchange_api.cancel_order(client_order_id=order_detail)
                if result:
                    self.redis.hdel(redis_key=self.trade_key, key=price)
                else:
                    logger.warning(f"撤单失败:{price}-{order_detail}")
                    self.redis.hdel(redis_key=self.trade_key, key=price)
            else:
                logger.error(f"没有在redis中找到这个订单{price}-{order_id}-{order_detail}")
        except Exception as e:
            self.redis.hdel(redis_key=self.trade_key, key=price)
            logger.error(f"撤单请求异常，{e}")

    async def buy(self, price, order_id: str = None):
        price = round(price, self.digits)
        try:
            result = await self.trade(direction=Direction.OPEN_LONG, price=price, order_id=order_id)
            if result['status'] != "NEW":
                logger.error(f"买单过期，{result}")
            return result
        except Exception as e:
            logger.error(f"下单失败:{e}")
            return None

    async def sell(self, price, amount: int = 0, order_id: str = None):
        result = None
        retry = 3
        while not result and retry > 0:
            try:
                result = await self.trade(direction=Direction.CLOSE_LONG, price=price, amount=amount, order_id=order_id)
            except Exception as e:
                logger.error(f"卖单下单失败")
            retry -= 1
            await asyncio.sleep(0.5)
        return result

    async def trade(self, direction: str, price: float, amount: int = 0, order_id: str = None):
        try:
            info = self.redis.get(redis_key=self.info_key)
            if not amount:
                amount = info["order_amount"]

            # 平多的时候不限制 maker only
            if direction == Direction.CLOSE_LONG:
                order_type = OrderType.LIMIT
            else:
                order_type = OrderType.MAKER if info["maker_only"] else OrderType.LIMIT

            if not order_id:
                order_id = f"G_F_{randint(1, 10 ** 8)}_{price}"

            result = await self.exchange_api.create_order(
                amount=amount,
                order_type=order_type,
                direction=direction,
                price=price,
                client_oid=order_id,
                order_resp_type="RESULT"
            )
            return result

        except Exception as e:
            logger.error(f"下单失败{direction},{price}:{e}")
            return None

    async def update_buy_orders(self):
        """update buy orders

        """
        order_infos = await self.exchange_api.get_symbol_orders()
        if order_infos.shape[0]:
            self.buy_orders = {x['clientOrderId']: float(x['price']) for x in
                               order_infos[order_infos.side == "BUY"].to_dict(orient='records')}
            self.current_buy_prices = [float(x['price']) for x in
                                       order_infos[order_infos.side == "BUY"].to_dict(orient='records')]
        else:
            logger.warning("没有在交易所发现有任何挂单")
            self.buy_orders = {}
            self.current_buy_prices = []

    def generate_prices_up(self, start_price: float, number: int, info) -> List[float]:
        """ generate price from down to up

        Args:
            start_price: up price
            number: length of price list

        Returns:
            price list

        """
        prices: List[float] = []
        percent = info["grid_percent"]
        while number > 0:
            prices.append(round(start_price, self.digits))
            start_price *= (1 + percent)
            number -= 1
        return prices

    def generate_prices(self, start_price: float, number: int, info) -> List[float]:
        """ generate price from up to down

        Args:
            start_price: up price
            number: length of price list

        Returns:
            price list

        """
        prices: List[float] = []
        percent = info["grid_percent"]
        while number > 0:
            prices.append(round(start_price, self.digits))
            start_price /= (1 + percent)
            number -= 1
        return prices

    async def update_orders(self, price):
        """ update buy order on rising market
        1. make new orders with current price
        2. cancel old orders

        Args:
            price: current price

        """
        if not price:
            logger.warning(f"更新订单价格为 0")
            return
        info = self.redis.get(self.info_key)

        # 一开始生成好所有的格子信息

        # TODO：修改成5000
        number = 5000

        # number = 10
        price = info['middle_price']

        upper_prices = self.generate_prices_up(start_price=price, number=number, info=info)
        down_prices = self.generate_prices(start_price=price, number=number, info=info)
        self.all_prices = sorted(list(set(upper_prices + down_prices)))
        self.grid_percent = info["grid_percent"]
        self.middle_price = info["middle_price"]

    async def cancel_buy_orders(self, useful_order_ids: List[str]):
        """

        Args:
            useful_order_ids: order ids to preserve

        """
        await self.update_buy_orders()
        cancel_orders = []
        cancel_price = []

        for k, v in self.buy_orders.items():
            if k not in useful_order_ids:
                cancel_orders.append(k)
                cancel_price.append(v)
                # 删除掉redis里面的key
                self.redis.hdel(redis_key=self.trade_key, key=v)

        logger.info(f"开始撤单:{cancel_orders},保留单:{useful_order_ids}")
        await asyncio.gather(
            *[self.exchange_api.cancel_order(client_order_id=order_id) for order_id in cancel_orders]
        )

    async def update_price(self):
        stream_names = [
            f"{self.exchange_api.symbol.symbol.lower()}@aggTrade"
        ]

        uri = BinanceWebsocketUri.__dict__[
                  self.exchange_api.symbol.market_type] + f"/stream?streams={'/'.join(stream_names)}"

        subscribe = {
            "method": "SUBSCRIBE",
            "params": stream_names,
            "id": 1
        }

        while 1:
            try:
                async with websockets.connect(uri) as ws:
                    await ws.send(json.dumps(subscribe))
                    logger.info(f"成功连接到{uri},开始更新价格")
                    while 1:
                        data = json.loads(await asyncio.wait_for(ws.recv(), timeout=25))
                        if data.get("data"):
                            self.redis.set(redis_key=self.price_key, value=float(data["data"]["p"]))
                            logger.debug(f"更新价格成功: {data['data']['p']}")
                        else:
                            logger.warning(f"发现异常数据:{data}")
            except Exception as e:
                logger.error(f"连接断开，正在重连……{e}", exc_info=True)

    async def keep_orders(self):
        """整理订单
        初始化:
            挂最开始的几个单, 记录挂单ID
        运行中：
            1 (优化)，获取当前的挂单对比是否都在目前内存的挂单里面
            1. 判断目前的几个挂单是否有成交的，如果有，挂上对应的卖单, 并记录对应的持仓信息
            2. 根据当前的价格，计算新的挂单，和目前内存里面的挂单/持仓比较，确认需要挂哪几个 撤哪几个。
            3 同时发送撤单和挂单的请求
            4 sleep一下
        """
        logger.info("3s后，开始整理订单")
        await asyncio.sleep(3)

        # 在最开始预设置价格为0
        current_price = 0

        # 当前的挂单信息
        current_buy_orders_info: Dict[float:str] = {}
        # 当前的持仓信息
        current_holding_info: Dict[float:str] = {}

        while True:
            try:
                # 每次循环获取最新的价格
                new_price = self.redis.get(redis_key=self.price_key)
                # 每次循环获取最新的网格设置
                info = self.redis.get(redis_key=self.info_key)

                # 初始化, 最开始启动的时候，记录价格
                if current_price == 0:
                    logger.warning(f"第一次循环，设置最初的格子,清空redis,撤了挂单和持仓,debug:{DEBUG}")

                    if DEBUG:
                        # 开始的时候撤销所有的挂单
                        order_infos = await self.exchange_api.get_symbol_order()
                        for order in order_infos:
                            if order['clientOrderId'].startswith("G_F"):
                                await self.exchange_api.cancel_order(client_order_id=order['clientOrderId'])

                        # 开始时候平仓
                        long_amount, _, _ = await self.exchange_api.get_symbol_position_short_long()
                        if long_amount > 0:
                            await self.exchange_api.create_order(
                                amount=long_amount,
                                direction=Direction.CLOSE_LONG,
                                order_type=OrderType.MARKET,
                            )

                    # 生成所有的格子
                    await self.update_orders(price=new_price)

                    order_prices_index = bisect_left(a=self.all_prices, x=float(new_price))
                    # 生成当前应该有的挂单信息
                    order_prices = [x for x in self.all_prices[:order_prices_index]][-int(info["max_buy_order_size"]):]
                    order_results = await asyncio.gather(
                        *[
                            self.buy(price=p) for p in order_prices
                        ]
                    )
                    amount = info["order_amount"]
                    # 记录当前的挂单信息
                    current_buy_orders_info = {
                        x["price"]: {
                            "order_id": x["clientOrderId"],
                            "amount": int(amount)
                        } for x in order_results
                    }
                    # 记录当前的价格
                    current_price = new_price
                    logger.info(f"最开始的挂单为:{current_buy_orders_info}")
                else:
                    logger.info(
                        f"开始整理订单,new_price:{new_price},upper bound:{round(new_price * (1 + info['grid_percent']), self.digits)},current order:{current_buy_orders_info} holding {current_holding_info}")

                    exchange_open_orders = await self.exchange_api.get_symbol_orders()
                    exchange_open_orders_df = pd.DataFrame(exchange_open_orders)
                    if exchange_open_orders_df.shape[0] > 0:
                        exchange_open_buy_orders_df = exchange_open_orders_df[exchange_open_orders_df['side'] == "BUY"]
                    else:
                        exchange_open_buy_orders_df = pd.DataFrame()

                    exchange_buy_orders = {x['price']: x['clientOrderId']
                                           for x in exchange_open_buy_orders_df.to_dict(orient="records")}

                    logger.info(f"开始检查卖单...")
                    # 检查有没有卖单成交了
                    for price in list(current_holding_info):
                        order_id = current_holding_info[price]
                        order_df = exchange_open_orders_df[exchange_open_orders_df["clientOrderId"] == order_id]
                        if not order_df.shape[0]:
                            logger.info(f'发现卖单成交,补一个买单{price}')
                            del current_holding_info[price]

                    logger.info(f"开始检查买单...")
                    # 检查有没有之前的买单成交了
                    for price in list(current_buy_orders_info):
                        order_id = current_buy_orders_info[price]["order_id"]
                        order_df = exchange_open_buy_orders_df[exchange_open_buy_orders_df["clientOrderId"] == order_id]
                        if not order_df.shape[0]:
                            buy_price = round(float(price), self.digits)
                            sell_price = round(float(buy_price) * (1 + info["grid_percent"]), self.digits)
                            logger.info(f"有买单成交:{buy_price}，补一个卖单:{sell_price}")
                            # TODO: make it at same time
                            sell_order_results = await self.sell(price=sell_price,
                                                                 amount=current_buy_orders_info[price]["amount"])
                            if sell_order_results:
                                current_holding_info[buy_price] = sell_order_results["clientOrderId"]
                            else:
                                logger.error(f"没有成功补上卖单,buy price:{buy_price}")

                    # 重新对齐内存里面的挂单信息
                    current_buy_orders_info = {
                        float(x['price']): {
                            'order_id': x['clientOrderId'],
                            'amount': int(x['amount'])
                        } for x in exchange_open_buy_orders_df.to_dict(orient="records")
                        if x['clientOrderId'].startswith("G_F")
                    }

                    # 如果修改了格子的比例/中位价，重新生成格子
                    if self.grid_percent != info["grid_percent"] or self.middle_price != info["middle_price"]:
                        # 生成所有的格子
                        logger.info(f"发现格子信息改了:{info}")
                        await self.update_orders(price=current_price)

                    order_prices_index = bisect_left(a=self.all_prices, x=float(new_price))
                    # 生成当前应该有的挂单信息
                    should_order_prices = [x for x in self.all_prices[:order_prices_index] if
                                           not current_holding_info.get(x)][-int(info["max_buy_order_size"]):]
                    order_prices = [x for x in should_order_prices if not current_buy_orders_info.get(x)]

                    # 撤掉多余的单
                    cancel_order_id = [order_id for price, order_id in exchange_buy_orders.items() if
                                       float(price) not in should_order_prices]
                    cancel_order_id.extend(
                        [
                            x['clientOrderId'] for x in exchange_open_buy_orders_df[
                            exchange_open_buy_orders_df.duplicated(subset=['price'])].to_dict(orient="records")
                        ]
                    )
                    if len(cancel_order_id) > 0:
                        logger.info(f"发现需要撤的单子:{cancel_order_id},open buy orders{exchange_buy_orders}")
                        await asyncio.gather(
                            *[
                                self.exchange_api.cancel_order(client_order_id=order_id) for order_id in cancel_order_id
                            ]
                        )
                        # 在内存挂单里面把撤掉的单子删了
                        for price in list(current_buy_orders_info):
                            info = current_buy_orders_info[price]
                            if info['order_id'] in cancel_order_id:
                                del current_buy_orders_info[price]

                    if len(order_prices) > 0:
                        order_results = await asyncio.gather(
                            *[
                                self.buy(price=p) for p in order_prices
                            ]
                        )
                        order_results_info = {
                            float(x["price"]): {
                                "order_id": x["clientOrderId"],
                                "amount": x["origQty"]
                            }
                            for x in order_results
                        }
                        current_buy_orders_info.update(
                            order_results_info
                        )
                        logger.info(f"下单成功:{order_results_info},当前挂单信息:{current_buy_orders_info}")

                # 每次循环休息一秒♨
                await asyncio.sleep(0.5)
            except Exception as e:
                logger.error(f"管理订单出错:{e}")
                await asyncio.sleep(1)

    async def main(self, task: str):
        await asyncio.gather(
            self.task_table[task]()
        )

class FutureGridStrategy(object):
    """Robot For Grid Strategy
    """

    def setup_test_data(self, info_key: str):
        """ test handler for generate test data
        """
        info = {
            "api_id": 32,
            # BTC
            # "symbol_id": 765,
            # ETH
            "symbol_id": 768,
            "order_amount": 1,
            "middle_price": 1800,
            "grid_percent": 0.001,
            # "grid_percent": 0.002,
            # "grid_percent": 0.003,
            "max_buy_order_size": 2,
            "maker_only": True,
            "start_time": TimeUtil.format_time(datetime.now()),
            "start_money": None,
        }

        self.redis.set(redis_key=info_key, value=info)

    def __init__(self, info_key: str, trade_key: str, pair_key: str, price_key: str, mode: str = "test"):
        self.redis = RedisHelper()

        # TODO: delete me
        if mode == "test":
            self.setup_test_data(info_key=info_key)

        #  info data
        info = self.redis.get(info_key)

        self.exchange_api: BinanceApi = ExchangeidSymbolidAPI(symbol_id=info["symbol_id"], api_id=info["api_id"])
        logger.info(
            f"successfully init exchange api {self.exchange_api.api.exchange}-{self.exchange_api.symbol.symbol}")
        if self.exchange_api.api.exchange == BinanceApi.EXCHANGE:
            self.robot = BinanceGridRobotV2(exchange_api=self.exchange_api, info=info, price_key=price_key,
                                            info_key=info_key, pair_key=pair_key, trade_key=trade_key)

            # 设置开始的资金
            info = self.redis.get(redis_key=info_key)
            if not info.get("start_money"):
                info['start_money'] = asyncio.run(self.robot.exchange_api.get_symbol_balance())["equity"]
                self.redis.set(redis_key=info_key, value=info)

    def run(self, task: str):
        asyncio.run(self.robot.main(task))

def run_task(task: str, info_key, pair_key, trade_key, price_key, mode):
    strategy = FutureGridStrategy(
        info_key=info_key,
        price_key=price_key,
        pair_key=pair_key,
        trade_key=trade_key,
        mode=mode
    )
    strategy.run(task)

@click.command()
@click.argument("task")
def start_grid(task):
    logger.info(f"开始运行:{task}")
    tasks = [
        "price", "order"
    ]
    if task == "test":
        info_key = RedisKeys.TEST_GRID_STRATEGY_FUTURE_INFO
        price_key = RedisKeys.TEST_GRID_STRATEGY_FUTURE_PRICE
        pair_key = RedisKeys.TEST_GRID_STRATEGY_FUTURE_ORDER_PAIR
        trade_key = RedisKeys.TEST_GRID_STRATEGY_FUTURE_TRADE
        mode = "test"
    elif task == "btc":
        info_key = RedisKeys.GRID_STRATEGY_FUTURE_INFO
        price_key = RedisKeys.GRID_STRATEGY_FUTURE_PRICE
        pair_key = RedisKeys.GRID_STRATEGY_FUTURE_ORDER_PAIR
        trade_key = RedisKeys.GRID_STRATEGY_FUTURE_TRADE
        mode = "btc"
    else:
        # 特殊处理单任务的情况
        DEBUG = True
        if DEBUG:
            info_key = RedisKeys.TEST_GRID_STRATEGY_FUTURE_INFO
            price_key = RedisKeys.TEST_GRID_STRATEGY_FUTURE_PRICE
            pair_key = RedisKeys.TEST_GRID_STRATEGY_FUTURE_ORDER_PAIR
            trade_key = RedisKeys.TEST_GRID_STRATEGY_FUTURE_TRADE
            mode = "test"
        else:
            info_key = RedisKeys.GRID_STRATEGY_FUTURE_INFO
            price_key = RedisKeys.GRID_STRATEGY_FUTURE_PRICE
            pair_key = RedisKeys.GRID_STRATEGY_FUTURE_ORDER_PAIR
            trade_key = RedisKeys.GRID_STRATEGY_FUTURE_TRADE
            mode = "btc"

        strategy = FutureGridStrategy(
            info_key=info_key,
            price_key=price_key,
            pair_key=pair_key,
            trade_key=trade_key,
            mode=mode
        )
        strategy.run(task)
        # 直接退出
        return

    # 正常情况
    running_tasks = []

    for task in tasks:
        p = Process(args=(task, info_key, pair_key, trade_key, price_key, mode), target=run_task)
        p.start()
        running_tasks.append(p)

    for running_task in running_tasks:
        running_task.join()

if __name__ == '__main__':
    start_grid()


from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import *
from selenium.webdriver.support.select import Select
from selenium.webdriver.common.action_chains import ActionChains
import os
from os import path
import time

class Bot():
    def __init__(self):
        """set ressources urls"""
        self.path = path.abspath(os.curdir) #folder path
        self.bg_remover = "https://removal.ai/"
        self.upscaler = "https://www.upscale.media/upload"
        self.img_suffix = (".jpeg",".png",".jpg")

    def remove_bg(self):
        options = webdriver.ChromeOptions()
        for img in os.listdir():
            if img.lower().endswith(self.img_suffix):
                print(f"removing bg for: {img}")
                with webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options) as driver:
                    driver.maximize_window()
                    wait = WebDriverWait(driver, timeout=30, poll_frequency=1, ignored_exceptions=[ElementNotVisibleException,ElementNotSelectableException,NoSuchElementException])
                    driver.get(self.bg_remover)
                    form = driver.find_element(By.CLASS_NAME, "form-control")
                    form.send_keys(f"{self.path}/{img}")
                    btn = wait.until(EC.element_to_be_clickable((By.PARTIAL_LINK_TEXT,"Download")))
                    btn.click()
                    time.sleep(5)
                os.remove(img)

    def upscale(self):
        options = webdriver.ChromeOptions()
        for img in os.listdir():
            if img.lower().endswith(self.img_suffix):
                print(f"processing: {img}")
                with webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options) as driver:
                    driver.maximize_window()
                    wait = WebDriverWait(driver, timeout=30, poll_frequency=1, ignored_exceptions=[ElementNotVisibleException,ElementNotSelectableException,NoSuchElementException])
                    driver.get(self.upscaler)
                    form = wait.until(EC.presence_of_element_located((By.ID, "uploadImage")))
                    form.send_keys(f"{self.path}/{img}")
                    select_element = wait.until(EC.visibility_of_element_located((By.XPATH, "/html/body/div[1]/div/div[1]/div[3]/div[2]/div/div[2]/div/div/div[3]/div[1]/div[2]/div[2]/div[1]/div[1]/div[1]/select")))
                    select = Select(select_element)
                    select.select_by_value("4x")
                    #working on toggling to enheance pic quality
                    #toggle_div = wait.until(EC.visibility_of_element_located((By.CLASS_NAME, "hIlDCJ")))
                    #toggle = toggle_div.find_element(By.TAG_NAME, "input")
                    #driver.execute_script("arguments[0].setAttribute('checked','checked')",toggle)
                    btn = wait.until(EC.element_to_be_clickable((By.XPATH,"/html/body/div[1]/div/div[1]/div[3]/div[2]/div/div[2]/div/div/div[3]/div[1]/div[2]/div[2]/div[2]/button")))
                    btn.click()
                    time.sleep(10)
                os.remove(img)

if __name__=="__main__":
    "debugging code note that the bot removes the file after processing"
    bot = Bot()
    #bot.remove_bg() #uncomment and run to test
    bot.upscale() #uncomment and run to test


"""
Created on Wed Dec 19 09:19:45 2018

@author: Will
"""
#libraries
import matplotlib.pyplot as plt
import numpy
import pandas as pd
import numpy as np
from sklearn.preprocessing import OneHotEncoder, LabelEncoder
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split

#open first half
X = np.load('dna_cleaner.npy')
y = np.load('dna_clean_labels.npy')
np.where(y==2)
X = X[:1535]
y = y[:1535]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=0)
num_inputs = X.shape[0]
input_size = X.shape[1]

def initialize_parameters(input_size):
    weights = np.zeros(input_size,)
    bias = np.zeros(1)
    return (weights, bias)

weights, bias = initialize_parameters(input_size)

""" Forward propagartion """

def sigmoid(z): #creating the S shaped curve.
    s = 1/(1+np.exp(-z))
    return s

x_sigmoid = np.arange(-5, 5, .1)
y_sigmoid = sigmoid(x_sigmoid)

#plt.plot(x_sigmoid,y_sigmoid)
#plt.title('Sigmoid Function')
#plt.show()
#print(output)
#y_prediction = np.rint(output).astype(int)
#print(y_prediction)
#loss = -(y_train[0] * np.log(output) + (1-y_train[0])*np.log(1-output))
learning_rate = 0.001
#weights[0] = weights[0] + learning_rate * loss * X_train[0][0]
weights, bias = initialize_parameters(input_size)
outputs = sigmoid(np.dot(weights,X_train.T) + bias)
y_prediction = np.rint(outputs).astype(int) # this forces either 0 or 1

""" Backward Propagation """

cost = (-1/num_inputs) * np.sum(y_train*np.log(outputs) + (1-y_train)*np.log(1-outputs))
dw = (1/num_inputs) * np.dot(X_train.T, (outputs-y_train).T)
db = (1/num_inputs) * np.sum(outputs-y_train)
assert weights.shape == dw.shape
weights = weights - learning_rate * dw
bias = bias - learning_rate * db

""" Building model """

def model(X_train, y_train, epochs=500, learning_rate=0.1):

    num_inputs = len(X_train)

    # Create an empty array to store predictions
    y_prediction = np.empty(num_inputs)

    weights, bias = initialize_parameters(input_size)

    for i in range(epochs):

        # Now we calculate the output
        # We're doing this for all images at the same time
        image_sums = np.dot(weights, X_train.T) + bias
        # Now we have to run each output through our activation function, then convert it to a prediction
        outputs = sigmoid(image_sums)
        # Now we have to convert the outputs to predictions
        # round it to an int
        y_prediction = np.rint(outputs).astype(int)  # this forces either 0 or 1

        # Find weight and bias changes
        dw = (1/num_inputs) * np.dot(X_train.T, (outputs-y_train).T)
        dw = np.squeeze(dw)
        db = (1/num_inputs) * np.sum(outputs-y_train)
        # Update the parameters
        # Make sure the matrices are the same size
        assert weights.shape == dw.shape
        weights = weights - learning_rate * dw
        bias = bias - learning_rate * db

    parameters = {"weights": weights,
                  "bias": bias,
                  "train_predictions": y_prediction,
                  }

    return parameters

"""Test"""

results = model(X_train, y_train, epochs=300)
final_weights = results['weights']
final_bias = results['bias']
final_sums = np.dot(final_weights, X_test.T) + final_bias
final_outputs = sigmoid(final_sums)
test_predictions = np.rint(final_outputs).astype(int)
train_predictions = results['train_predictions']
print("Accuracy on training set: {:.2%}".format(1-np.mean(np.abs(train_predictions - y_train))))
print("Accuracy on testing set: {:.2%}".format(1-np.mean(np.abs(test_predictions - y_test))))


# coding: utf-8

__author__ = ["Samuel Joshua"]

from PIL import Image

catIm = Image.open('zophie.png')

# left, top, right -1, bottom -1`
croppedIm = catIm.crop((335, 345, 565, 560))
croppedIm.save('cropped.png')


#!/usr/bin/env python
from setuptools import setup, find_packages

required_modules = [
    "django == 1.5.1",
    "selenium == 2.33.0",
    "mock == 1.0.1",
    "south == 0.8.1",
    "MySQL-python",
    "PIL == 1.1.7"
    ]

setup(
    name="Citi Digits",
    version="0.1",
    description="",
    author="Vikash Dat",
    author_email="dat.vikash@gmail.com",
    packages=find_packages(exclude=['test']),
    install_requires=required_modules
)


import argparse
from players import PLAYERS

parser = argparse.ArgumentParser()
parser.add_argument(
    '-b',
    '--benchmark',
    action='store_true',
    dest='benchmark',
    help='execute 100 iterations')

parser.add_argument(
    '-t',
    '--tournament',
    action='store_true',
    dest='tournament',
    help='execute a tournament among all agents except random')

parser.add_argument(
    '-tr',
    '--tournament_against_random',
    action='store_true',
    dest='tournament_against_random',
    help='execute a tournament of all agents against random')

parser.add_argument(
    '-p0',
    choices=PLAYERS.keys(),
    help='selects player 0',
    required=True)
parser.add_argument(
    '-p1',
    choices=PLAYERS.keys(),
    help='selects player 1',
    required=True)

parser.add_argument('-v', '--verbose', action='count',
                    default=0, help='increase log verbosity')
parser.add_argument('-d',
                    '--debug',
                    action='store_const',
                    dest='verbose',
                    const=2,
                    help='log debug messages (same as -vv)')


import sys

sys.path.append('__modules')
from Customize_me import *
from config import Config
from get_tests import Build
from parse_arg import Parse_arg
from run_tests import Run
from output import Output

class Task():
  """
    Design pattern command. Will manage every task
    of the test_suit. You can add as many tasks as
    you want. You can then run them by calling the
    Task object
  """

  def __init__(self):
    """
      Init an empty task list
    """
    self.tasks = []

  def add(self, task):
    """
      Add a task in the task list
    """
    self.tasks.append(task)

  def __call__(self):
    """
      Run the tasks one by one
    """
    result = {}
  #  try:
    for task in self.tasks:
      result = task(result)
  #  except Exception as e:
  #    print e
  #  finally:
    return result

def main():

  # Prolog
  logo_print()
  prelude()

  # Create the task manager
  task = Task()

  # Add tasks
  task.add(Config())
  task.add(Parse_arg())
  task.add(Build())
  task.add(Run())
  task.add(Output())

  # Launch tasks
  result = task()

  # Call the
  epilog()

if __name__ == '__main__':
  main()


# The hint recommends to use a trie. However, using a trie does not necessarily
# improve the efficiency.
class WordDictionary(object):
    def __init__(self):
        """
        initialize your data structure here.
        """
        self.trie = {}

    def addWord(self, word):
        """
        Adds a word into the data structure.
        :type word: str
        :rtype: void
        """
        node = self.trie
        for x in word:
            node = node.setdefault(x, {})
        node[None] = None

    def search(self, word):
        """
        Returns if the word is in the data structure. A word could
        contain the dot character '.' to represent any one letter.
        :type word: str
        :rtype: bool
        """
        return self._search(word, 0, self.trie)

    def _search(self, word, start_index, node):
        for i in range(start_index, len(word)):
            if word[i] == '.':
                for child in node.values():
                    if child is not None and self._search(word, i + 1, child):
                        return True
                return False
            else:
                node = node.get(word[i])
                if node is None:
                    return False
        return None in node

def test():
    wd = WordDictionary()
    wd.addWord('bad')
    wd.addWord('dad')
    wd.addWord('mad')
    wd.addWord('mak')
    assert not wd.search('pad')
    assert wd.search('bad')
    assert wd.search('.ad')
    assert wd.search('b..')
    assert wd.search('.a.')
    assert not wd.search('p..')
    assert wd.search('mad')
    assert wd.search('mak')
    assert not wd.search('makf')
    assert not wd.search('ma')


from math import *

d,s  = input().split()
s_d= len(s)
i = 0
digit = 0
page_no = 0
while ((10**(s_d+i)) - int(s)) * s_d < int(d):
    if i == 0:
        digit += (10**(s_d) - int(s))*s_d
        page_no += (10**(s_d) - int(s))
    elif (((10**(s_d+i)) - (10**(s_d+i-1))) * (s_d+i) > int(d)):
        break;
    else:
        digit += ((10**(s_d+i)) - (10**(s_d+i-1))) * (s_d+i)
        page_no += ((10**(s_d+i)) - (10**(s_d+i-1)))
    i += 1

digit = int(d) - digit

if digit%(s_d+i) and digit > 0:
    print(-1)
else:
    page_no += (digit//(s_d+i))
    print(page_no)

Contests/CSEC Contests -1st-Year/1st Contest/Solutions/Printing Books.py


"""
Created on Sat Aug 18 11:32:18 2018

@author: Wesley
"""
from __future__ import print_function
import numpy as np
import pandas as pd
from sklearn.preprocessing import LabelEncoder
from sklearn import preprocessing
#invite people for the Kaggle party
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.preprocessing import StandardScaler
import warnings
#warnings.filterwarnings('ignore')
import matplotlib.pyplot as plt
from sklearn.metrics import mean_squared_error, r2_score
from sklearn.model_selection import train_test_split,GridSearchCV
from sklearn.preprocessing import Imputer
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_absolute_error
import math
from sklearn.cross_validation import StratifiedKFold
from sklearn.utils import shuffle
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression, RidgeCV, LassoCV, ElasticNetCV, ElasticNet
from xgboost import XGBRegressor
from scipy.stats import norm, skew #for some

from xgboost import XGBRegressor
from sklearn import preprocessing
from sklearn import linear_model
from sklearn import ensemble
from sklearn.svm import SVR

df_train = pd.read_csv(r"C:\House Prices Advanced Regression Techniques\train.csv", header=0)
df_pred = pd.read_csv(r"C:\House Prices Advanced Regression Techniques\test.csv", header=0)
copy_df_train = df_train.copy()
copy_df_pred = df_pred.copy()

#### Root Mean Square Logarithmic Error ###
def logRMSE(y_test, y_pred) :
    assert len(y_test) == len(y_pred)
    return np.sqrt(np.mean((np.log(1+y_pred) - np.log(1+y_test))**2))

# In[]:
# Take a look at the data
print('Training Dataset: \n',df_train.head(5))
print('Test Dataset: \n',df_pred.head(5))
print('Test Dataset Features: \n',df_pred.columns)

target = 'SalePrice'
identifier = 'Id'
balanceamento_dataset = 0
plot = 0
tam_test = 0.3
Imputation = 1 #Caso Imputation=0, usamos o metodo fillna(0) no conjunto de teste
Exclude_Object_Features = 1 #Seleciona Somente as Features Numericas para treinamento
feature_transform = 1
Norm_Features = 1 #Normalizacao das Features de X_train antes do treinamento, e de X_test e X_pred com a normalizacao de X_train para predicoes

# In[]: PERGUNTAS IMPORTANTES
print('\n O Dataset de Treino e Teste possuem as mesmas features?:',set(df_train.drop(target,1)) == set(df_pred))

# In[]: Outliers
##bivariate analysis saleprice/grlivarea
var = 'GrLivArea'
data = pd.concat([df_train[target], df_train[var]], axis=1)
if plot:
    data.plot.scatter(x=var, y=target, ylim=(0,800000));
##The two values with bigger 'GrLivArea' seem strange and they are not following the crowd. We can speculate why this is happening. Maybe they refer to agricultural area and that could explain the low price. I'm not sure about this but I'm quite confident that these two points are not representative of the typical case. Therefore, we'll define them as outliers and delete them.
##The two observations in the top of the plot are those 7.something observations that we said we should be careful about. They look like two special cases, however they seem to be following the trend. For that reason, we will keep them.
##Deletar estes dois pontos aberrantes
df_train = df_train.drop(df_train.index[df_train.sort_values(by=['GrLivArea'],ascending=False)[:2].index])
#
#
##bivariate analysis saleprice/grlivarea
var = 'TotalBsmtSF'
data = pd.concat([df_train[target], df_train[var]], axis=1)
if plot:
    data.plot.scatter(x=var, y=target, ylim=(0,800000));
##Deletar um Ponto Aberrante
df_train = df_train[~(df_train['TotalBsmtSF'] > 3000)]

# In[]: Dealing with missing data
train_Id = df_train[identifier]
pred_Id = df_pred[identifier]
train_target = df_train[target]
### Merge Train and Prediction Dataset into df_merge. Drop 'Id' and 'SalePrice' columns before merge
df_merge = pd.concat([df_train.drop([target,identifier],1),df_pred.drop(identifier,1)],axis=0)
qualitative_features = [f for f in df_merge.dropna().columns if df_merge.dropna().dtypes[f] == 'object'] #Lista de Features Qualitativas.
quantitative_features = [f for f in df_merge.dropna().columns if df_merge.dropna().dtypes[f] != 'object'] #Lista de Features Qualitativas.

# Numeric Features
print('\nIs there any NaN value of numeric features in the dataset before Imputing?:',df_merge[quantitative_features].isnull().sum().any())
df_merge[quantitative_features].isnull().sum().sort_values(ascending=False)
df_merge['LotFrontage'] = df_merge['LotFrontage'].fillna(0)
df_merge['GarageYrBlt'] = df_merge['GarageYrBlt'].fillna(0)
df_merge['MasVnrArea'] = df_merge['MasVnrArea'].fillna(0)

for i in quantitative_features:
    df_merge[i] = df_merge[i].fillna(df_merge[i].mean())
print('\nIs there any NaN value of numeric features in the dataset after Imputing?:',df_merge[quantitative_features].isnull().sum().any())

# Non-Numeric Features
print('\nIs there any NaN value of numeric features in the dataset before Imputing?:',df_merge[qualitative_features].isnull().sum().any())
df_merge[qualitative_features].isnull().sum().sort_values(ascending=False)
df_merge['PoolQC'] = df_merge['PoolQC'].fillna('None')
df_merge['MiscFeature'] = df_merge['MiscFeature'].fillna('None')
df_merge['Alley'] = df_merge['Alley'].fillna('None')
df_merge['BsmtQual'] = df_merge['BsmtQual'].fillna('None')
df_merge['BsmtCond'] = df_merge['BsmtCond'].fillna('None')
df_merge['BsmtExposure'] = df_merge['BsmtCond'].fillna('None')
df_merge['BsmtFinType1'] = df_merge['BsmtFinType1'].fillna('None')
df_merge['BsmtFinType2'] = df_merge['BsmtFinType2'].fillna('None')
df_merge['FireplaceQu'] = df_merge['FireplaceQu'].fillna('None')
df_merge['GarageType'] = df_merge['GarageType'].fillna('None')
df_merge['GarageFinish'] = df_merge['GarageFinish'].fillna('None')
df_merge['GarageCond'] = df_merge['GarageCond'].fillna('None')
df_merge['GarageQual'] = df_merge['GarageQual'].fillna('None')
df_merge['Fence'] = df_merge['Fence'].fillna('None')
df_merge['MasVnrType'] = df_merge['MasVnrType'].fillna('None')
df_merge["Functional"] = df_merge["Functional"].fillna("Typ")
df_merge.drop('Utilities',axis=1,inplace=True)
last_qlfeat = ['MSZoning','KitchenQual','Exterior2nd','Exterior1st','Electrical','SaleType']
qualitative_features = [f for f in df_merge.dropna().columns if df_merge.dropna().dtypes[f] == 'object'] #Lista de Features Qualitativas.
quantitative_features = [f for f in df_merge.dropna().columns if df_merge.dropna().dtypes[f] != 'object'] #Lista de Features Qualitativas.

for i in last_qlfeat:# Mode for the rest features
    df_merge[i] =  df_merge[i].fillna(df_merge[i].mode()[0])

print('\nIs there any NaN value  in the dataset after Imputing and get_dummies?:',df_merge.isnull().sum().any())

# Imputation and Feature Labeling of Categorical Variables With Dummies
df_merge = pd.get_dummies(data=df_merge, columns=qualitative_features)

# Feature Transform
train_target = np.log1p(train_target)

# In[]: Normalization
if Norm_Features:
    max_pesos = df_merge.max(axis=0)
    df_merge.loc[:,max_pesos != 0] = df_merge.loc[:,max_pesos != 0]/max_pesos[max_pesos != 0]

print('\n Is there any null value in the df_merge?:',df_merge.isnull().sum().any())

# In[]: Restore df_train and df_pred
df_train = df_merge[:len(df_train)]
df_train[target] = train_target
df_pred = df_merge[len(df_train):]

# In[]: Division X_train/X_test
df_train = shuffle(df_train) #shuffle data before division
train_target = df_train[target] # Just for code readibility
predictors = df_train.drop([target], axis=1)
X_train, X_test, y_train, y_test = train_test_split(predictors,
                                                    train_target,
                                                    train_size=1-tam_test,
                                                    test_size=tam_test,
                                                    random_state=0)
X_pred = df_pred

# In[]: Lasso Model
lasso = LassoCV(alphas = [0.0001, 0.0003, 0.0006, 0.001, 0.003, 0.006, 0.01, 0.03, 0.06, 0.1,
                          0.3, 0.6, 1, 3, 6, 10, 30, 60, 100],
                max_iter = 50000, cv = 10)
lasso.fit(X_train, y_train)
alpha = lasso.alpha_
print("Best alpha :", alpha)

print("Try again for more precision with alphas centered around " + str(alpha))
lasso = LassoCV(alphas = [alpha * .6, alpha * .65, alpha * .7, alpha * .75, alpha * .8,
                          alpha * .85, alpha * .9, alpha * .95, alpha, alpha * 1.05,
                          alpha * 1.1, alpha * 1.15, alpha * 1.25, alpha * 1.3, alpha * 1.35,
                          alpha * 1.4],
                max_iter = 50000, cv = 10)
lasso.fit(X_train, y_train)
alpha = lasso.alpha_
print("Best alpha :", alpha)

y_train_las = lasso.predict(X_train)
y_test_las = lasso.predict(X_test)
las_prediction = lasso.predict(X_pred)

# In[]: Ridge Model
ridge = RidgeCV(alphas = [0.0001, 0.0003, 0.0006, 0.001, 0.003, 0.006, 0.01, 0.03, 0.06, 0.1,
                          0.3, 0.6, 1, 3, 6, 10, 30, 60, 100])
ridge.fit(X_train, y_train)
alpha = ridge.alpha_
print("Best alpha :", alpha)

print("Try again for more precision with alphas centered around " + str(alpha))
ridge = RidgeCV(alphas = [alpha * .6, alpha * .65, alpha * .7, alpha * .75, alpha * .8, alpha * .85,
                          alpha * .9, alpha * .95, alpha, alpha * 1.05, alpha * 1.1, alpha * 1.15,
                          alpha * 1.25, alpha * 1.3, alpha * 1.35, alpha * 1.4],
                cv = 10)
ridge.fit(X_train, y_train)
alpha = ridge.alpha_
print("Best alpha :", alpha)

y_train_rdg = ridge.predict(X_train)
y_test_rdg = ridge.predict(X_test)
rdg_prediction = ridge.predict(X_pred)

# In[]: XGBoost
xgb_model = XGBRegressor()

##### GRID SEARCH XGB #####
params = {'n_estimators':[1000],'learning_rate':[0.01,0.05],
'max_depth':[3,5]}
grid = GridSearchCV(xgb_model, params)
grid.fit(X_train, y_train)
y_train_gridXGB = grid.best_estimator_.predict(X_train)
y_test_gridXGB = grid.best_estimator_.predict(X_test)
gridXGB_prediction = grid.best_estimator_.predict(X_pred)
##### GRID SEARCH XGB #####

xgb_model = XGBRegressor(n_estimators=10000, learning_rate=0.05)

xgb_model.fit(X_train, y_train, early_stopping_rounds=5,
             eval_set=[(X_test, y_test)], verbose=False)

y_train_xgb = xgb_model.predict(X_train)
y_test_xgb = xgb_model.predict(X_test)
xgb_prediction = xgb_model.predict(X_pred)

# In[]: ElasticNet Model
#elnr = ElasticNet(alpha=0.001,l1_ratio=0.3,max_iter=3000,n_jobs=-1)

elnr = ElasticNetCV(l1_ratio=[0.2,0.65],alphas=[0.001,0.005],n_jobs=-1,max_iter=3000)

elnr.fit(X_train,y_train)

y_train_eln = elnr.predict(X_train)
y_test_eln = elnr.predict(X_test)
eln_prediction = elnr.predict(X_pred)

# In[]: Plots and Results
if feature_transform:
    y_train = np.expm1(y_train)
    y_test = np.expm1(y_test)

    y_train_las = np.expm1(y_train_las)
    y_test_las = np.expm1(y_test_las)
    las_prediction = np.expm1(las_prediction)

    y_train_rdg = np.expm1(y_train_rdg)
    y_test_rdg = np.expm1(y_test_rdg)
    rdg_prediction = np.expm1(rdg_prediction)

    y_train_xgb = np.expm1(y_train_xgb)
    y_test_xgb = np.expm1(y_test_xgb)
    xgb_prediction = np.expm1(xgb_prediction)

    y_train_gridXGB = np.expm1(y_train_gridXGB)
    y_test_gridXGB = np.expm1(y_test_gridXGB)
    gridXGB_prediction = np.expm1(gridXGB_prediction)

    y_train_eln = np.expm1(y_train_eln)
    y_test_eln = np.expm1(y_test_eln)
    eln_prediction = np.expm1(eln_prediction)
else:
    pass
feature_transform=0

df_resultado_treinamento = pd.DataFrame(
        {'x_train':list(X_train.values),
         'y_train':list(y_train),
         'y_train_lasso':y_train_las,
         'y_train_ridge':y_train_rdg,
         'y_train_xgb':y_train_xgb,
         'y_train_gridXGB':y_train_gridXGB,
         'y_train_eln':y_train_eln,
                })

df_resultado_val = pd.DataFrame(
        {'x_val':list(X_test.values),
         'y_val':list(y_test),
         'y_test_lasso':y_test_las,
         'y_test_ridge':y_test_rdg,
         'y_test_xgb':y_test_xgb,
         'y_test_gridXGB':y_test_gridXGB,
         'y_test_eln':y_test_eln
                })

plt.figure(1)
#plt.subplot(3, 1, 2)
df_resultado_treinamento = df_resultado_treinamento.sort_values('y_train',ascending=1)
plt.plot(list(df_resultado_treinamento['y_train']),'r-.',label='y_train')
plt.plot(list(df_resultado_treinamento['y_train_lasso']),'g-.',label='LassoTrain')
plt.plot(list(df_resultado_treinamento['y_train_ridge']),'y-.',label='RidgeTrain')
plt.plot(list(df_resultado_treinamento['y_train_xgb']),'k-.',label='XGB')
plt.legend()
#plt.xlabel('time (s)')
#plt.ylabel('Undamped')

#Plot Validacao
#plt.subplot(3, 1, 3)
plt.figure(2)
df_resultado_val = df_resultado_val.sort_values('y_val',ascending=1)
plt.plot(list(df_resultado_val['y_val']),'r-.',label='y_test')
plt.plot(list(df_resultado_val['y_test_lasso']),'g-.',label='LassoTest')
plt.plot(list(df_resultado_val['y_test_ridge']),'y-.',label='RidgeTest')
plt.plot(list(df_resultado_val['y_test_xgb']),'k-.',label='XGB')
plt.legend()
plt.show()

## Avaliacao do modelo
print("\nLasso logRMSE on Training set :", logRMSE(y_train,y_train_las))
print("Ridge logRMSE on Training set :", logRMSE(y_train,y_train_rdg))
print("XGB logRMSE on Training set :", logRMSE(y_train,y_train_xgb))
print("gridXGB logRMSE on Training set :", logRMSE(y_train,y_train_gridXGB))

print("\nLasso logRMSE on Test set :", logRMSE(y_test,y_test_las))
print("Ridge logRMSE on Test set :", logRMSE(y_test,y_test_rdg))
print("XGB logRMSE on Test set :", logRMSE(y_test,y_test_xgb))
print("gridXGB logRMSE on Training set :", logRMSE(y_test,y_test_gridXGB))

print("eln logRMSE on Test set :", logRMSE(y_test,y_test_eln))

print("StackedModel logRMSE on Test set :", logRMSE(y_test,(y_test_xgb+y_test_rdg+y_test_las + y_test_gridXGB
                                                            +y_test_eln)/(len(df_resultado_val.columns)-2)))

# In[]: Write to csv
df_saida = pd.DataFrame(
        {identifier:pred_Id,
        target: (xgb_prediction + las_prediction + rdg_prediction + gridXGB_prediction
                   +eln_prediction  )/(len(df_resultado_val.columns)-2)
                })

df_saida.to_csv(r'C:\House Prices Advanced Regression Techniques/answer.csv',index=False)


from gnr.web.gnrbaseclasses import BaseComponent

class TestHandler(BaseComponent):
    testOnly=False
    def windowTitle(self):
        return 'Test: %s' % self.__module__.__doc__ or 'unnamed'

    def testHandler(self, pane):
        self.testHandler_headers(pane)

        #pane.div(height='12px',width='12px',position='absolute',top='2px',right='2px',background='red',nodeId='rpcpulser',opacity=0)
        title = pane.div(width='900px', text_align='center', color='gray', font_size='20pt')
        title.span(self.__module__.__doc__ or '...missing docline in module...')
        pane = pane.div(width='900px')
        self.testHandler_loop(pane)

    def testHandler_headers(self, pane):
        header = pane.div(width='900px', margin='5px')
        header.div('Dojo version :', float='left', margin_top='7px', color='gray')
        pane.data('gnr.dojo_version', '1.5')
        mdiv = header.dropdownbutton(label='^gnr.dojo_version', float='left')
        m = mdiv.menu(action='SET gnr. dojo_version=$1.label')
        m.menuline('1.1')
        m.menuline('1.5')
        pane.data('gnr.dojo_theme', 'claro')
        mdiv = header.dropdownbutton(label='^gnr.dojo_theme', float='right', margin_right='10px', padding_top='1px',
                                     padding_bottom='1px')
        header.div('Dojo theme :', float='right', margin_top='7px', color='gray')
        m = mdiv.menu(action='SET gnr.dojo_theme=$1.label')
        m.menuline('Claro')
        m.menuline('Tundra')
        m.menuline('Soria')

    def testHandler_loop(self, pane):
        test_to_do = [n for n in dir(self) if n.startswith('test_')]
        test_to_do.sort()
        for test_name in test_to_do:
            if self.testOnly and not self.testOnly in test_name:
                continue
            test_handler = getattr(self, test_name)
            element = pane.div(border='1px solid gray', margin='5px', datapath='test.%s' % test_name)
            h = element.div()
            h.a('Source', href='', float='right', onclick='alert("ggg")', color='white', font_size='10px',
                margin_right='5px', margin_top='3px', style='cursor:pointer')
            h.div(test_handler.__doc__ or test_name, background_color='gray', color='white', padding='3px')

            element = element.div(padding='5px')
            test_handler(element)

class TestHandlerBase(TestHandler):
    def main_root(self, root, **kwargs):
        self.testHandler(root)

class TestHandlerFull(TestHandler):
    def main(self, root, **kwargs):
        self.testHandler(root)


import scrapy

class Dmoz(scrapy.Spider):
    name = "dmoz"
    # allowed_domain=["weibo.cn"]
    start_urls = ["http://www.liaoxuefeng.com"]

    def parse(self, response):
        print("开始执行parse方法")
        filename = response.body
        print(filename)

        with open('filename', 'w',encoding='utf-8') as f:
            f.write(str(response.body))


import sys
import collections
import math

dx = [0, 0, -1, 1]
dy = [1, -1, 0, 0]

R, C, T = map(int, sys.stdin.readline().split(" "))

arr = []

# 배열값 입력하는 부분
for j in range(R):
    nums = list(map(int, sys.stdin.readline().split(" ")))
    arr.append(nums)

second = 0 # 확산시간 정의

# 개념 : 방향을 싱히좌우로 변할 수 있도록 만들고, i + 1 번째 값을 temp에 저장하고, i + 1 에 i 값을 넣기
# 오 : 1 왼 : 2 상 : 3 하 : 4

#  반시계방향으로 도는함수
def reverseTimeDir(dot):
    count = 0 # 도는 횟수
    global newArr, dust
    y, x = dot
    width = C # 가로길이
    height = y + 1 # 세로길이
    transY, transX = dot
    if(transX == C - 1):
        transY -= 1
        dir = 3
    else:
        transX += 1
        dir = 1
    temp = newArr[transY][transX]
    while(True):
        if(count == 2 * width + 2 * (height - 2) - 2):
            dust -= temp
            break

        # 모서리 부분 처리
        if(transX == C - 1 and transY == y): # 오른쪽에서 위쪽으로 방향바꾸는 구간
            dir = 3
        elif(transX == C - 1 and transY == 0): # 위쪽에서 왼쪽으로 방향을 바꾸는 구간
            dir = 2
        elif(transX == 0 and transY == 0): # 왼쪽에서 아래로 방향을 바꾸는 구간
            dir = 4
        elif(transX == 0 and transY == y): # 아래에서 오른쪽으로 방향을 바꾸는 구간
            dir = 1

        # 구간별 arr값 변경 진행
        if(dir == 1): # 오른쪽
            temp, newArr[transY][transX + 1] = newArr[transY][transX + 1], temp
            transX += 1
            if(count == 0):
                newArr[transY][transX - 1] = 0
        elif(dir == 2): # 왼쪽
            temp, newArr[transY][transX - 1] = newArr[transY][transX - 1], temp
            transX -= 1
            if(count == 0):
                newArr[transY][transX + 1] = 0
        elif(dir == 3): # 상
            temp, newArr[transY - 1][transX] = newArr[transY - 1][transX], temp
            transY -= 1
            if(count == 0):
                newArr[transY + 1][transX] = 0
        elif(dir == 4): # 하
            temp, newArr[transY + 1][transX] = newArr[transY + 1][transX], temp
            transY += 1
            if(count == 0):
                newArr[transY - 1][transX] = 0

        # 실행횟수 카운트
        count += 1

# 시계방향으로 도는 함수
def timeDir(dot):
    count = 0 # 도는 횟수
    global newArr, dust
    y, x = dot
    width = C # 가로길이
    height = R - y # 세로길이
    transY, transX = dot
    if(transX == R - 1):
        transY += 1
        dir = 4
    else:
        transX += 1
        dir = 1
    temp = newArr[transY][transX]
    while(True):
        if(count == 2 * width + 2 * (height - 2) - 2):
            dust -= temp
            break

        # 모서리 부분 처리
        if(transX == C - 1 and transY == y): # 오른쪽에서 아래로 방향바꾸는 구간
            dir = 4
        elif(transX == C - 1 and transY == R - 1): # 아래에서 왼쪽으로 방향바꾸는 구간
            dir = 2
        elif(transX == 0 and transY == R - 1): # 왼쪽에서 위로 방향바꾸는 구간
            dir = 3
        elif(transX == 0 and transY == y): # 위에서 오른쪽으로 방향 바꾸는 구간
            dir = 1

        # 구간별 arr값 변경 진행
        if(dir == 1): # 오른쪽
            temp, newArr[transY][transX + 1] = newArr[transY][transX + 1], temp
            transX += 1
            if(count == 0):
                newArr[transY][transX - 1] = 0
        elif(dir == 2): # 왼쪽
            temp, newArr[transY][transX - 1] = newArr[transY][transX - 1], temp
            transX -= 1
            if(count == 0):
                newArr[transY][transX + 1] = 0
        elif(dir == 3): # 상
            temp, newArr[transY - 1][transX] = newArr[transY - 1][transX], temp
            transY -= 1
            if(count == 0):
                newArr[transY + 1][transX] = 0
        elif(dir == 4): # 하
            temp, newArr[transY + 1][transX] = newArr[transY + 1][transX], temp
            transY += 1
            if(count == 0):
                newArr[transY - 1][transX] = 0

        # 실행횟수 카운트
        count += 1

def BFS(dots):
    global newArr
    q = collections.deque(dots)
    while q:
        count = 0
        y, x, dust = q.popleft()
        for i in range(4):
            newX = x + dx[i]
            newY = y + dy[i]
            if(newX >= 0 and newX < C and newY >= 0 and newY < R and arr[newY][newX] != -1):
                newArr[newY][newX] += dust // 5
                count += 1
        newArr[y][x] = dust - (dust // 5 * count) + newArr[y][x]
    for s in airDot:
        y, x = s[0], s[1]
        newArr[y][x] = -1

airDot = [] # 콩기청정기의 위치

dust = 0 # 미세먼지의 양

# 첫 먼지양 체크하기 (시간복잡도 때문에 처음 한번만 실행하고, 이후로는 먼지가 정화되는 수를 체크하여 빼는 형식으로 계산할 예정)
for s in arr:
    for k in s:
        if(k > 0):
            dust += k

while(second < T):
    if(second == 0):
        dots = [] # 미세먼지가 들어있는 좌표의 모음
        for j in range(R):
            for i in range(C):
                if(arr[j][i] == -1):
                    airDot.append((j,i))
                # 배열의 값이 -1인경우는 공기청정기, 0인경우는 미세먼지가 없는 경우이기에
                elif(arr[j][i] > 0):
                    dots.append((j, i, arr[j][i]))
    else:
        dots = [] # 미세먼지가 들어있는 좌표의 모음
        for j in range(R):
            for i in range(C):
                # 배열의 값이 -1인경우는 공기청정기, 0인경우는 미세먼지가 없는 경우이기에
                if(arr[j][i] > 0):
                    dots.append((j, i, arr[j][i]))

    newArr = []
    # 새로운 배열 생성 0으로 초기화된
    for s in arr:
        nums = []
        for i in range(C):
            nums.append(0)
        newArr.append(nums)

    BFS(dots)

    # 공기청정기 작동 실행
    reverseTimeDir(airDot[0])
    timeDir(airDot[1])
    second += 1

    # 바뀐 배열값을 원래배열에 저장
    for i in range(R):
        for j in range(C):
            arr[i][j] = newArr[i][j]

print(dust)

백준/Gold/17144. 미세먼지 안녕！/미세먼지 안녕！.py


from rest_framework import serializers
from project.models import Project,FundApplyLog,\
    RefundApplyLog,InvoiceApplyLog,OperatorLog,ProjectInvestDataModel

class ProjectListSerializer(serializers.ModelSerializer):
    state_des = serializers.CharField(source='get_state_display', read_only=True)
    settleway_des = serializers.CharField(source='get_settleway_display', read_only=True)
    platformname = serializers.CharField(source='platform', read_only=True)
    profit = serializers.DecimalField(decimal_places=2,max_digits=10,read_only=True)
    topay_amount= serializers.DecimalField(decimal_places=2,max_digits=10,read_only=True)
    contact = serializers.CharField(source="contact.uname",read_only=True)
    audituser = serializers.CharField(source="audituser.uname",read_only=True)
    #apply_man = serializers.CharField(source="apply_man.uname",read_only=True)

    class Meta:
        model = Project
        fields = '__all__'
        read_only_fields = ('id','settleway_des','consume','state_des', 'time','profit','topay_amount')

class ProjectSerializer(serializers.ModelSerializer):
    #contact = serializers.CharField(source="contact.uname",read_only=True)

    class Meta:
        model = Project
        fields = '__all__'

class  FundApplyLogSerializer(serializers.ModelSerializer):
    #project = serializers.CharField(source="project.id",read_only=True)
    class Meta:
        model = FundApplyLog
        fields = '__all__'

class  FundApplyLogListSerializer(serializers.ModelSerializer):
    project = serializers.CharField(source="project.id",read_only=True)
    projectname = serializers.CharField(source="project.name",read_only=True)
    audit_man = serializers.CharField(source="audit_man.uname",read_only=True)
    apply_man = serializers.CharField(source="apply_man.uname",read_only=True)

    class Meta:
        model = FundApplyLog
        fields = '__all__'

class  RefundApplyLogSerializer(serializers.ModelSerializer):
    class Meta:
        model = RefundApplyLog
        fields = '__all__'

class  RefundApplyLogListSerializer(serializers.ModelSerializer):
    project = serializers.CharField(source="project.id", read_only=True)
    projectname = serializers.CharField(source="project.name",read_only=True)
    audit_man = serializers.CharField(source="audit_man.uname",read_only=True)
    apply_man = serializers.CharField(source="apply_man.uname",read_only=True)

    class Meta:
        model = RefundApplyLog
        fields = '__all__'

class  InvoiceApplyLogSerializer(serializers.ModelSerializer):
    class Meta:
        model = InvoiceApplyLog
        fields = '__all__'

class  InvoiceApplyLogListSerializer(serializers.ModelSerializer):
    project = serializers.CharField(source="project.id", read_only=True)
    projectname = serializers.CharField(source="project.name",read_only=True)
    audit_man = serializers.CharField(source="audit_man.uname",read_only=True)
    apply_man = serializers.CharField(source="apply_man.uname",read_only=True)

    class Meta:
        model = InvoiceApplyLog
        fields = '__all__'

class  OperatorLogSerializer(serializers.ModelSerializer):
    oman = serializers.CharField(source='oman.uname',read_only=True)
    otime = serializers.DateTimeField(format="%Y-%m-%d",read_only=True)

    class Meta:
        model = OperatorLog
        fields = '__all__'

class  ProjectInvestDataSerializer(serializers.ModelSerializer):
    projectname = serializers.CharField(source="project.name",read_only=True)
    audit_time = serializers.DateTimeField(format="%Y-%m-%d",read_only=True)
    audit_man = serializers.CharField(source="audit_man.uname",read_only=True)

    class Meta:
        model = ProjectInvestDataModel
        fields = '__all__'


import pandas as pd
import numpy as np
import streamlit as st
from scipy.spatial import distance

# Función para cargar el dataset
@st.cache_resource
def load_data():
    url = "https://raw.githubusercontent.com/pansolans/Similar/main/Colotto_api_septok_conlogos.xlsx"
    return pd.read_excel(url)
    st.cache_resource

def calculate_mahalanobis_distance(Datos_Ejercicio_4, name):
    regularization_factor = 1e-4
    cov_matrix = Datos_Ejercicio_4.drop(columns="Name").cov()
    regularized_cov_matrix = cov_matrix + np.eye(cov_matrix.shape[0]) * regularization_factor
    inv_cov = np.linalg.inv(regularized_cov_matrix)

    player_data_df = Datos_Ejercicio_4[Datos_Ejercicio_4["Name"] == name].drop(columns="Name")
    player_data = player_data_df.values[0]
    sim = Datos_Ejercicio_4.apply(lambda row: distance.mahalanobis(row.drop("Name").values, player_data, inv_cov), axis=1)
    return sim

def export_to_excel(df, file_name):
    df.to_excel(file_name, index=False)

def main():
    df = load_data()

    st.sidebar.header("Pampa Fútbol Analytics")
    st.sidebar.header("Filtros")

    cols_to_select = list(range(23,166))
    selected_vars = st.sidebar.multiselect("Seleccionar variables:", options=df.columns[cols_to_select].tolist())
    competition_ids = st.sidebar.multiselect("Seleccionar competitionId:", options=df["competitionId"].unique().tolist())
    season_ids = st.sidebar.multiselect("Seleccionar season:", options=df["season"].unique().tolist())
    pos_principales = st.sidebar.multiselect("Seleccionar Pos_principal:", options=df["Pos_principal"].unique().tolist())
    min_minutes, max_minutes = st.sidebar.slider("Seleccionar rango de minutesOnField:", int(df["minutesOnField"].min()), int(df["minutesOnField"].max()), (int(df["minutesOnField"].min()), int(df["minutesOnField"].max())))

    if not selected_vars or not competition_ids or not season_ids or not pos_principales:
        st.warning("Por favor, selecciona opciones en todos los filtros para continuar.")
        return

    filtered_df = df[
        (df["competitionId"].isin(competition_ids)) &
        (df["season"].isin(season_ids)) &
        (df["Pos_principal"].isin(pos_principales)) &
        (df["minutesOnField"] >= min_minutes) &
        (df["minutesOnField"] <= max_minutes)
    ]

    name = st.sidebar.selectbox("Seleccionar Jugador:", options=[None] + filtered_df["Jugador"].unique().tolist())
    if not name:
        st.warning("Por favor, selecciona un jugador para continuar.")
        return

    if st.sidebar.button("Búsqueda"):
        Datos_Ejercicio_4 = filtered_df[selected_vars]
        Datos_Ejercicio_4["Name"] = filtered_df["Jugador"]
        Datos_Ejercicio_4.fillna(0, inplace=True)

        sim = calculate_mahalanobis_distance(Datos_Ejercicio_4, name)

        sim = pd.DataFrame(sim, columns=["similitud"])
        sims95 = sim["similitud"].quantile(0.95)
        sim["similitud_2"] = 100 - (sim["similitud"] / sims95) * 100
        sim["Name"] = Datos_Ejercicio_4["Name"].values
        sim = sim[["Name", "similitud", "similitud_2"]]
        sim.columns = ["Name", "Dist_Euc_OP_Norm_mah", "Sim_Euc_OP_Norm_mah"]

        sim_sorted = sim.sort_values(by="Sim_Euc_OP_Norm_mah", ascending=False)
        sim_filtered = sim_sorted[["Name", "Sim_Euc_OP_Norm_mah"]]
        merged_df = pd.merge(sim_filtered, filtered_df[["Jugador", "Edad", "urlImagen.y", "equipoActual_nombre", "urlImagen.x", "competitionId", "minutesOnField"]], left_on="Name", right_on="Jugador", how="left")
        st.session_state.merged_df = merged_df
        st.session_state.displayed_df = None

    st.header("Jugadores Similares")

    min_age, max_age = st.slider("Minutos jugados:", int(df["minutesOnField"].min()), int(df["minutesOnField"].max()), (int(df["minutesOnField"].min()), int(df["minutesOnField"].max())))
    post_search_competition_ids = st.multiselect("Seleccionar competitionId para filtrar la tabla:", options=st.session_state.merged_df["competitionId"].unique().tolist())

    if st.session_state.merged_df is not None:
        filtered_by_age = st.session_state.merged_df[(st.session_state.merged_df["minutesOnField"] >= min_age) & (st.session_state.merged_df["minutesOnField"] <= max_age)]

        if post_search_competition_ids:
            filtered_by_age = filtered_by_age[filtered_by_age["competitionId"].isin(post_search_competition_ids)]

        st.session_state.displayed_df = filtered_by_age.head(20)  # Almacena solo los primeros 20 registros

        for index, row in st.session_state.displayed_df.iterrows():
            col1, col2, col3 = st.columns([1,3,1])
            if isinstance(row["urlImagen.y"], str):
                col1.image(row["urlImagen.y"], width=50)
            if isinstance(row["urlImagen.x"], str):
                col2.image(row["urlImagen.x"], caption=row["Name"], width=100)
            col3.markdown(f"Edad: {int(row['Edad'])}", unsafe_allow_html=True)
            col3.markdown(f"Equipo: {row['equipoActual_nombre']}", unsafe_allow_html=True)
            col3.markdown(f"Similitud: {row['Sim_Euc_OP_Norm_mah']:.2f}", unsafe_allow_html=True)
            col3.markdown(f"Minutos: {row['minutesOnField']}", unsafe_allow_html=True)

    # Botón para exportar a Excel
    if st.session_state.displayed_df is not None:
        if st.button('Exportar a Excel'):
            file_name = 'jugadores_similares.xlsx'  # Define el nombre del archivo aquí
            export_to_excel(st.session_state.displayed_df, file_name)
            st.success(f'Archivo exportado como {file_name}')

if __name__ == "__main__":
    main()