import datetime
import json
import os

import requests
from rest_framework import status
from rest_framework.generics import ListAPIView
from rest_framework.response import Response
from django.core import serializers

from annual_reports.models import IncomeStatement
from annual_reports.serializers import IncomeStatementSerializer, BalanceSheetStatementSerializer, CashFlowStatementSerializer
from annual_reports.models import BalanceSheetStatement, CashFlowStatement
from indicators.models import Indicator

class ListIncomeStatements(ListAPIView):
    serializer_class = IncomeStatementSerializer
    queryset = IncomeStatement.objects.all()

    def get(self, request, *args, **kwargs):
        symbol_id = Indicator.objects.filter(symbol=kwargs['symbol']).first().id
        income_statements = IncomeStatement.objects.filter(symbol=symbol_id).all()

        if income_statements.count() == 0:
            self.fetch_financial_statements(kwargs['symbol'], symbol_id)
            income_statements = IncomeStatement.objects.filter(symbol=symbol_id).all()

        return Response(status=status.HTTP_200_OK, data=IncomeStatementSerializer(income_statements, many=True).data)

    @staticmethod
    def fetch_financial_statements(symbol, symbol_id):
        req_income_statement = requests.get(
            f'{os.environ.get("ANNUAL_REPORTS_URL")}income-statement/{symbol}?apikey={os.environ.get("ANNUAL_REPORTS_API_KEY")}')
        req_balance_sheet = requests.get(
            f'{os.environ.get("ANNUAL_REPORTS_URL")}balance-sheet-statement/{symbol}?apikey={os.environ.get("ANNUAL_REPORTS_API_KEY")}')
        req_cash_flow = requests.get(
            f'{os.environ.get("ANNUAL_REPORTS_URL")}cash-flow-statement/{symbol}?apikey={os.environ.get("ANNUAL_REPORTS_API_KEY")}')

        for income, balance, cash in zip(req_income_statement.json(), req_balance_sheet.json(), req_cash_flow.json()):

            indicator = Indicator.objects.filter(id=symbol_id).first()
            income['symbol'] = indicator
            balance['symbol'] = indicator
            cash['symbol'] = indicator

            for key, value in income.items():
                try:
                    dt = datetime.datetime.strptime(value.split()[0], '%Y-%m-%d').date()
                    income[key] = dt
                except Exception as e:
                    pass

            for key, value in balance.items():
                try:
                    dt = datetime.datetime.strptime(value.split(' ')[0], '%Y-%m-%d').date()
                    balance[key] = dt
                except Exception as e:
                    pass

            for key, value in cash.items():
                try:
                    dt = datetime.datetime.strptime(value.split()[0], '%Y-%m-%d').date()
                    cash[key] = dt
                except Exception as e:
                    pass

            new_income_statement = IncomeStatement(**income)
            new_balance_statement = BalanceSheetStatement(**balance)
            new_cash_statement = CashFlowStatement(**cash)

            new_income_statement.save()
            new_balance_statement.save()
            new_cash_statement.save()

class ListBalanceSheetStatements(ListAPIView):
    serializer_class = BalanceSheetStatementSerializer
    queryset = BalanceSheetStatement.objects.all()

    def get(self, request, *args, **kwargs):
        symbol_id = Indicator.objects.filter(symbol=kwargs['symbol']).first().id
        income_statements = BalanceSheetStatement.objects.filter(symbol=symbol_id).all()

        if income_statements.count() == 0:
            ListIncomeStatements.fetch_financial_statements(kwargs['symbol'], symbol_id)
            income_statements = BalanceSheetStatement.objects.filter(symbol=symbol_id).all()

        return Response(status=status.HTTP_200_OK,
                        data=BalanceSheetStatementSerializer(income_statements, many=True).data)

class ListCashFlowStatements(ListAPIView):
    serializer_class = CashFlowStatementSerializer
    queryset = CashFlowStatement.objects.all()

    def get(self, request, *args, **kwargs):
        symbol_id = Indicator.objects.filter(symbol=kwargs['symbol']).first().id
        income_statements = CashFlowStatement.objects.filter(symbol=symbol_id).all()

        if income_statements.count() == 0:
            ListIncomeStatements.fetch_financial_statements(kwargs['symbol'], symbol_id)
            income_statements = CashFlowStatement.objects.filter(symbol=symbol_id).all()

        return Response(status=status.HTTP_200_OK, data=CashFlowStatementSerializer(income_statements, many=True).data)


import time
from kafka import KafkaConsumer

SERVER = ['121.196.16.204:9091','121.196.16.204:9092','121.196.16.204:9093']
TOPIC = 'rpa-message'
print(("kafka server is {},topic is [{}]".format(SERVER, TOPIC)))
consumer = KafkaConsumer(
    TOPIC,
    bootstrap_servers=SERVER,
    group_id='rpa-worker',
    auto_offset_reset='earliest',
    enable_auto_commit=False,
    consumer_timeout_ms=3 * 1000,
    # max_poll_interval_ms= 50*60*1000,
    # max_poll_records = 100

)

while 1:
    try:
        message = next(consumer)
        consumer.commit()
        print(message)
    except StopIteration:
        time.sleep(.5)

kafka消费太多重复信息.py


import turtle
import pandas

screen = turtle.Screen()
screen.title("U.S States Game")
image = "blank_states_img.gif"
screen.addshape(image)
turtle.shape(image)

data = pandas.read_csv("50_states.csv")
state_list = data.state.to_list()
guessed_states = []

while len(guessed_states) < 50:
    answer_state = screen.textinput(title=f"{len(guessed_states)}/50 States Correct", prompt="What's another state?").title()
    if answer_state == "Exit":
        not_guessed = [state for state in state_list if state not in guessed_states]
        df = pandas.DataFrame(not_guessed)
        df.to_csv("states_to_learn.csv")
        break
    if answer_state in state_list:
        guessed_states.append(answer_state)
        st_name = turtle.Turtle()
        st_name.hideturtle()
        st_name.penup()
        st_row = data[data.state == answer_state]
        st_name.goto(int(st_row.x), int(st_row.y))
        st_name.write(answer_state)


# -*- coding: utf-8 -*-
# @Time   : 2021/3/7
# @Author : lorineluo
from email.header import Header
from email.mime.text import MIMEText
from email.utils import parseaddr, formataddr
import smtplib
import time
from email.header import Header
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
from email.utils import parseaddr, formataddr
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

def timeStr():
    t = time.strftime(str("%Y-%m-%d %H:%M:%S"), time.localtime())
    s = '[%s]' % t
    return s

def _format_addr(s):
    name, addr = parseaddr(s)
    return formataddr((Header(name, 'utf-8').encode(), addr))

def sendEmail(msg, sender, title):
    # send email
    from_addr = 'luoyu091@163.com'
    tok = 'ZIVRTJYTZTGODWUX'
    to_addr = ['381336925@qq.com', 'moonwalkings@vip.qq.com', '1015240649@qq.com']
    # to_addr = ['381336925@qq.com']
    smtp_server = 'smtp.163.com'
    stime = timeStr()

    msg['From'] = _format_addr('%s <%s>' % (sender, from_addr))
    msg['To'] = ",".join(to_addr)
    msg['Subject'] = Header('%s %s' % (title, stime), 'utf-8').encode()

    server = smtplib.SMTP_SSL(smtp_server, 465)
    # server.set_debuglevel(1)
    server.ehlo(smtp_server)
    server.login(from_addr, tok)
    server.sendmail(from_addr, to_addr, msg.as_string())
    server.quit()

if __name__ == '__main__':
    msg = MIMEMultipart('mixed')

    # 1. dataframe
    display_df = pd.DataFrame(
        np.array([[1.0, '20210815', 3], [4.8, '20210816', 6], [7.0, '20210817', 9]]),
        columns=['a', 'date', 'c'])
    print(display_df)
    # display_df['a'] = display_df['a'].apply(lambda x: format(x, ".2%"))
    display_df = display_df.round(3)
    ori_html = display_df.to_html()

    #set table style
    ori_html = ori_html.replace("<table", '<table style="border-collapse: collapse;"')

    # 可能有多个内容
    contents = [ori_html]

    for content in contents:
        context = MIMEText(content,_subtype='html', _charset='utf-8')
        msg.attach(context)

    # 2. 图
    x=list(range(display_df.index.size))
    name = 'test'
    # plt.legend(loc="upper left", bbox_to_anchor=(0, 0.85))
    plt.xticks(x, display_df.date, rotation=35)
    plt.title(name)
    plt.savefig("%s/%s.png" %("/tmp", name))

    items=[name]
    content = '

'
    for item in  items:
        content += '

' %item
        # 读图
        with open("%s/%s.png" %('/tmp', item), "rb") as f:
            img = MIMEImage(f.read())
            img.add_header('Content-ID', item)
            msg.attach(img)
    context = MIMEText(content,_subtype='html', _charset='utf-8')
    msg.attach(context)

    #发送
    sendEmail(msg, "email test", "email test")


import disnake

from disnake.ext import commands

class MemberBanClass(commands.Cog):
    def __init__(self, bot):
        self.bot = bot
        self.color = self.bot.color

    @commands.Cog.listener()
    async def on_member_ban(self, guild, user):
        data = await self.bot.db.get_data("guild_id", guild.id, "guilds")

        if not data:
            return

        try:
            if data['func_config']['cont_users']:
                numbers = ['<:0_:578615675182907402>', '<:1_:578615669487304704>', '<:2_:578615674109165568>',
                           '<:3_:578615683424976916>', '<:4_:578615679406833685>', '<:5_:578615684708171787>',
                           '<:6_:578617070309343281>', '<:7_:578615679041798144>', '<:8_:578617071521497088>',
                           '<:9_:578617070317469708>']
                canal = self.bot.get_channel(data['func_config']['cont_users_id'])
                if canal is None:
                    return
                text = str(len(guild.members))
                list_ = list()
                for letter in text:
                    list_.append(numbers[int(letter)])
                list_ = ''.join(list_)
                ashley = canal.guild.get_member(self.bot.user.id)
                perms = canal.permissions_for(ashley)
                if perms.send_messages and perms.read_messages:
                    if not perms.embed_links or not perms.attach_files:
                        await canal.send("<:negate:721581573396496464>â”‚`PRECISO DA PERMISSÃƒO DE:` "
                                         "**ADICIONAR LINKS E DE ADICIONAR IMAGENS, PARA PODER FUNCIONAR"
                                         " CORRETAMENTE!**")
                    else:
                        await canal.edit(topic="<a:caralho:525105064873033764> **Membros:**  " + list_)
        except disnake.Forbidden:
            pass
        except disnake.errors.NotFound:
            pass

        data = data["log_config"]

        if data['log'] and data['member_ban']:
            canal = self.bot.get_channel(data['log_channel_id'])

            if not canal:
                return

            embed = disnake.Embed(color=self.color,
                                  title=":star2: **Membro Banido**",
                                  description=f"**Membro:** {user.name}")
            embed.set_footer(text="Ashley Â® Todos os direitos reservados.")

            ashley = canal.guild.get_member(self.bot.user.id)
            perms = canal.permissions_for(ashley)
            if perms.send_messages and perms.read_messages:
                if not perms.embed_links or not perms.attach_files:
                    await canal.send("<:negate:721581573396496464>â”‚`PRECISO DA PERMISSÃƒO DE:` "
                                     "**ADICIONAR LINKS E DE ADICIONAR IMAGENS, PARA PODER FUNCIONAR"
                                     " CORRETAMENTE!**")
                else:
                    await canal.send(embed=embed)

def setup(bot):
    bot.add_cog(MemberBanClass(bot))
    print('\033[1;33m( ðŸ”¶ ) | O evento \033[1;34mMEMBER_BAN\033[1;33m foi carregado com sucesso!\33[m')


import requests
from datetime import datetime

config = [
    { 'name' : 'temp', 'public' : 'q5X5m25pp8FYYgZ0EQld' },
    { 'name' : 'pi', 'public' : 'MGw10nX37ZSbA2A463Xo' },
]

base_url = 'https://data.sparkfun.com/output/'
from_time = '2015-07-19T12:00'
from_time_dt = datetime.strptime(from_time, '%Y-%m-%dT%H:%M')
dt = datetime.now() - from_time_dt
exp_rows = float(dt.seconds / 60)  # one post per minute

for c in config:
    payload = { 'gte[timestamp]': from_time }
    r = requests.get(base_url + c['public'], params=payload)
    if r.status_code == 200:
        rows = len(r.text.splitlines())
        print("%5s: %d / %d = %02d%%" %
            (c['name'], rows, exp_rows, (rows/exp_rows)*100))


#!/usr/bin/env python
# -*- coding:utf-8 -*-
#Python2.x除法保留2位小数
# from __future__ import division
# from __future__ import print_function
# from __future__ import unicode_literals

from sqlalchemy import Column,create_engine,Integer,DateTime
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import and_
from sqlalchemy import inspect
import argparse,sys
import datetime
import time
import re

#Python2.x的中文支持
# reload(sys)
# sys.setdefaultencoding('utf-8')

from config.conf_database import get_arg # 数据库连接配置
from config.conf_database import test_db # 数据库连接测试
from core import DataManager
from core.DBfunction import DBs
from core.MongoFun import Mongo_DBs
from core.RedisFunction import Redis_DBs

#用户全局变量
#stables_count=511
# engine01 = create_engine('mysql+pymysql://%s:%s@%s:%d/%s' % (get_arg('user'),get_arg('passwd'),get_arg('url'),get_arg('port'),get_arg('dbs')['userdb1']), max_overflow=15, echo=False)
# engine02 = create_engine('mysql+pymysql://%s:%s@%s:%d/%s' % (get_arg('user'),get_arg('passwd'),get_arg('url'),get_arg('port'),get_arg('dbs')['userdb2']), max_overflow=15, echo=False)
# Satisfy_reg_uidset=[]
# Satisfy_login_set=[]

# base=declarative_base()
##获取数据库内所有表的信息#######
# base.metadata.reflect(engine01)
# tables = base.metadata.tables
# print(tables)
##获取数据库内所有表的信息 END####

# def usage():
#     '''
#     输出帮助信息
#     '''
#     print(
# """
# Usage:  sys.args[0]       [option]
#
# [option]：
#
# -h or --help：显示帮助信息
# -l or --login：指定查询那个日期的登录记录      例如: 2019-06-06
# -r or --reg：指定查询那个日期的注册记录      例如: 2019-06-06
# """
#     )
#
# def argv_check():
#     '''
#     判断是否输入了参数
#     '''
#     if len(sys.argv) == 1:
#         usage()
#         sys.exit()
#
# def parser_flag():
#     '''
#     获取用户输入参数的函数
#     :return:
#     '''
#     #帮助信息
#     parser=argparse.ArgumentParser(description="输入登录记录和注册记录的查询日期")
#     #相关选项
#     parser.add_argument("-l","--login",help="指定查询那个日期的登录记录      例如: 2019-06-06")
#     parser.add_argument("-r","--reg",help="指定查询那个日期的注册记录      例如: 2019-06-06")
#     #获取参数
#     # args=parser.parse_args()
#     return parser.parse_args()

class Collets(object):
    def __init__(self,argv_list):

        self.engine01 = create_engine('mysql+pymysql://%s:%s@%s:%d/%s' % (get_arg('user'),get_arg('passwd'),get_arg('url'),get_arg('port'),get_arg('dbs')['userdb1']), max_overflow=15, echo=False)
        self.engine02 = create_engine('mysql+pymysql://%s:%s@%s:%d/%s' % (get_arg('user'),get_arg('passwd'),get_arg('url'),get_arg('port'),get_arg('dbs')['userdb2']), max_overflow=15, echo=False)
        self.argvs=argv_list
        self.data_time=time.strftime("%Y-%m-%d", time.localtime())
        self.GAME_COUNT_NUM = 50 # 游戏记录次数
        self.mongo_list=[]
        self.mongo_dict={}
        self.mysql_list=[]
        self.redis_list=[]
        self.pattern = re.compile(r'^userInfo_[0-9]{3}')
        self.__data_check()
        self.__parse_argv()

    def __data_check(self):
        '''
        检测是否自定义了日期
        :return:
        '''
        if len(self.argvs) >= 3:
            self.validate(self.argvs[2])
            self.data_time=self.argvs[2]

    def __parse_argv(self):
        '''
        模块不同功能
        :return:
        '''
        if len(self.argvs) >1:
            if hasattr(self,self.argvs[1]):
                func = getattr(self,self.argvs[1])
                func()
            else:
                print('找不到对应的模块功能')
                self.help_msg()
        else:
            print('请输入功能参数')
            self.help_msg()

    def help_msg(self):
        '''帮助信息'''
        msg = '''
        dbtest                         测试数据库连接
        people                         查询注册总人数
        regpeople  <yyyy-mm-dd>        查询某日注册总的用户数，默认为当日
        pay        <yyyy-mm-dd>        查询某日支付用户数，默认为当日
        record     <yyyy-mm-dd>        查询某日游戏记录较多的用户数，默认为当日
        active     <yyyy-mm-dd>        查询某日活跃的用户数，默认为当日
        inputs     <yyyy-mm-dd>        查询某日投入前100的玩家数，默认为当日（即时查询）
        outputs    <yyyy-mm-dd>        查询某日产出前100的玩家数，默认为当日（即时查询）
        revenues   <yyyy-mm-dd>        查询某日游戏的营收（默认为昨日，超过昨天日期默认为昨日）
        win_rank   <yyyy-mm-dd>        查询某日赢前100的玩家
        lose_rank  <yyyy-mm-dd>        查询某日输前100的玩家
        '''
        print(msg)

    def dbtest(self):
        '''
        测试数据库连接
        :return:
        '''
        test_db()

    # def date_oper(self,srt_time):
    #     '''
    #     日期处理
    #     :param srt_time:
    #     :return: 返回当前日期后一天的日期
    #     '''
    #     try:
    #         now=datetime.datetime.strptime(srt_time,'%Y-%m-%d')
    #         now_later=now+datetime.timedelta(days=1)
    #         return  now_later.strftime('%Y-%m-%d')
    #     except ValueError:
    #         print("请输入正确的日期格式")
    #         sys.exit(600)

    def regpeople(self):
        '''
        默认查询当日注册总人数
        :return:
        '''
        self.Satisfy_db(self.engine01,self.query_db,re.compile(r'^userInfo_[0-9]{3}'),'qure_res')
        # self.Satisfy_db(self.engine02)
        self.reg_out_put()

    def people(self):
        '''
        查询总注册人数
        :return:
        '''
        self.Satisfy_db(self.engine01,self.query_db,re.compile(r'^userInfo_[0-9]{3}'),'qure_all')
        self.all_people_out()

    def pay(self):
        '''
        查询支付情况
        :return:
        '''
        self.Satisfy_db(self.engine02,self.query_db,re.compile(r'^payInfo_[0-9]{3}'),'qure_pay')
        self.pay_out_put()

    def record(self):
        '''
        查询游戏记录
        :return:
        '''
        mongo_fun = Mongo_DBs(self.data_time,self.GAME_COUNT_NUM)
        self.count_list(mongo_fun.game_record())
        self.record_out_put()

    def active(self):
        '''
        查询活跃用户数
        :return:
        '''
        self.pay()
        self.record()
        self.active_out_put()

    def inputs(self):
        '''
        查询玩家产出前100
        :return:
        '''
        redis_fun=Redis_DBs(self.data_time,'redis_input')
        self.redis_list = redis_fun.dofun()
        self.player_out_put('input')

    def outputs(self):
        '''
        查询玩家投入前100
        :return:
        '''
        redis_fun=Redis_DBs(self.data_time,'redis_output')
        self.redis_list = redis_fun.dofun()
        self.player_out_put()

    def revenues(self):
        '''玩家游戏营收情况'''
        mongo_fun=Mongo_DBs(self.data_time,self.GAME_COUNT_NUM)
        self.mongo_list = mongo_fun.revenue()
        DataManager.num_dict_initialize() # 初始化字典
        self.mongo_dict = DataManager.openr_games(self.mongo_list)
        # print(self.mongo_dict)
        # self.player_revenues_output()

    def win_rank(self):
        '''每日赢前100的玩家'''
        # mongo_fun = Mongo_DBs(self.data_time, self.GAME_COUNT_NUM)
        mongo_fun = Mongo_DBs(self.data_time, self.GAME_COUNT_NUM)
        self.mongo_list=mongo_fun.win_record()
        print(self.mongo_list)
        self.rank_out('win')

    def lose_rank(self):
        '''每日输前100的玩家'''
        # mongo_fun = Mongo_DBs(self.data_time, self.GAME_COUNT_NUM)
        mongo_fun = Mongo_DBs(self.data_time, self.GAME_COUNT_NUM)
        self.mongo_list=mongo_fun.lose_record()
        self.rank_out()

    def Satisfy_db(self,engine,fun,pattern,db_fun):
        '''
        库内列表遍历函数
        :param engine:
        :return:
        '''
        db_funs = db_fun
        SessionCls = sessionmaker(bind=engine)
        session = SessionCls()

        inspector = inspect(engine)

        print('%s引擎查询中，请稍候...' % engine)
        for table_name in inspector.get_table_names():
            # 使用re做表名的判断过滤，然后再查询
            if pattern.match(table_name):
                fun(table_name,session,db_funs)
        session.close()

    # def querys_db(self,table_name,session):
    #     '''
    #     查询功能方法，已被query_db方法替换
    #     :param table_name:
    #     :param session:
    #     :return:
    #     '''
    #     ##日期处理##
    #     reg_time_later=self.date_oper(self.data_time)
    #     # login_time_later=date_oper(login_time)
    #     base = declarative_base()
    #     # Satisfy_login_set=[]
    #     class userInfo(base):
    #         __tablename__ = table_name
    #         uid = Column(Integer, primary_key=True, autoincrement=True)
    #         loginTime = Column(DateTime)
    #         registerTime = Column(DateTime)
    #     reg_objs=session.query(userInfo).filter(and_(userInfo.registerTime>= self.data_time ,userInfo.registerTime < reg_time_later )) #注册人数
    #     # login_objs=session.query(userInfo).filter(and_(userInfo.loginTime>= login_time ,userInfo.loginTime < login_time_later))
    #     try:
    #         for index_obj in reg_objs:
    #             self.mysql_list.append(index_obj.uid)
    #         # for index in login_objs:
    #         #     Satisfy_login_set.append(index.uid)
    #     except AttributeError:
    #         print('查询的值不存在')

    def validate(self,date_text):
        '''
        检测日期格式是否正确
        :param date_text:
        :return:
        '''
        try:
            datetime.datetime.strptime(date_text, '%Y-%m-%d')
        except ValueError:
            print("日期格式不正确，格式应该为 YYYY-MM-DD 例如：2019-10-22")
            sys.exit(700)

    def reg_out_put(self):
        '''注册人数结果输出'''
        print('%s 注册人数为: %d' % (self.data_time, len(self.mysql_list)))

    def all_people_out(self):
        '''注册总人数输出'''
        all_num=0
        for index in self.mysql_list:
            all_num=all_num+index
        print('总计注册人数为: %d' % all_num)

    def pay_out_put(self):
        '''支付信息输出'''
        print('%s 支付人数为: %d' % (self.data_time, len(self.mysql_list)))
        print('支付用户uid列表: ',self.mysql_list)

    def record_out_put(self):
        '''游戏记录输出'''
        print('%s 游戏记录超过%d条的玩家数量为: %d' % (self.data_time,self.GAME_COUNT_NUM,len(self.mongo_list)))
        print('玩家uid列表：',self.mongo_list)

    def active_out_put(self):
        '''活跃玩家输出'''
        self.mysql_list.extend(self.mongo_list)
        active_set = set(self.mysql_list)
        print('%s 活跃的玩家数量为: %d' % (self.data_time,len(active_set)))
        print('活跃玩家uid列表：', list(active_set))

    def player_out_put(self,io='产出'):
        '''
        投入产出前100的输出
        '''
        informations = io
        if io=='input':
            informations = '投入'
        print('玩家 %s 前100排行如下：' % informations)
        print(self.redis_list)

    def player_revenues_output(self):

        DataManager.record_output(self.mongo_dict)

    def rank_out(self,flag='lose'):
        if flag == 'win':
            print('%s 赢的前100名玩家' % self.data_time)
            for i in self.mongo_list:
                print('%s %s' % (i['uid'],i['revenue']))
        else:
            print('%s 输的前100名玩家' % self.data_time)
            for i in self.mongo_list:
                print('%s %s' % (i['uid'],i['revenue']))

    def query_db(self,table_name,session,fun):
        '''
        调用DBfunction查询模块查询表内信息
        '''
        q_db=DBs(table_name,session,self.data_time,fun)
        res_list=q_db.dofun()
        if len(res_list) != 0:
            self.mysql_list.extend(res_list)

    def count_list(self,some_list):
        '''
        统计列表重复元素个数
        :return:
        '''
        myset = set(some_list)
        for item in myset:
            if some_list.count(item) >= 50:
                self.mongo_list.append(item)

    def data_return(self):
        '''
        模块的"API"
        外部程序import此模块时，返回输出记录给外部程序
        调用范例见：test.py 文件内的代码
        :return:
        '''
        return self.mysql_list,self.mongo_list,self.redis_list

    def dict_data_return(self):
        '''
        模块的"API"
        外部程序import此模块时，返回输出记录给外部程序
        调用范例见：test.py 文件内的代码
        :return:
        '''
        # print('此时mongo dict字典为')
        # for i in self.mongo_list:
        #     print(i)
        return self.mongo_dict

####################测试代码区###########################################
####################测试代码区END#########################################

if __name__ == '__main__':
    print('请在Coll模块中调用此模块的一切功能')
    sys.exit(101)
    # argv_check()
    # args = parser_flag()
    #
    # Satisfy_db(engine01, args.reg, args.login)
    # Satisfy_db(engine02, args.reg, args.login)
    # mysql_list = set(mysql_list)
    # # print(mysql_list)
    # print('%s 总计注册了%d人' % (args.reg,len(mysql_list)))
    #
    # Satisfy_login_set = set(Satisfy_login_set)
    # print('%s 总计登录了%d人' % (args.login,len(Satisfy_login_set)))
    #
    # #2个集合取交集，得到规定时间内即注册又登录的用户
    # Inter_set=mysql_list.intersection(Satisfy_login_set)
    # print("在%s登录，并在%s注册过的人有：%d人" % (args.login,args.reg,len(Inter_set)))
    #
    # print("在%s登录，并在%s注册的留存率：%0.2f%%" % (args.login,args.reg,(len(Inter_set)/len(mysql_list)*100)))

# li=[{'uid':2222,'uid date':'2019-10-19','gameId':3,'type':'fish','level':2,'input':99,'output':60,'revenue':-10},{'uid':22333,'uid date':'2019-10-19','gameId':2,'type':'fish','level':1,'input':10,'output':60,'revenue':50}]


import unittest
import unittest.mock
import datetime
import sqlite3
import rps
import captcha
import flask
import os
import shutil
import time
import PIL
import PIL.Image
import tempfile
import xml.etree.ElementTree as ET
import functools

class FlaskTemplateMocker:
    def __enter__(self):
        self.original_render_template = flask.render_template
        flask.render_template = unittest.mock.Mock(wraps=self.original_render_template)
        return flask.render_template
    def __exit__(self, exc_type, exc_val, exc_tb):
        flask.render_template = self.original_render_template

flaskTemplateMocker = FlaskTemplateMocker()

def lookForCallKey(call_args, target_key):
    for value in call_args:
        if type(value) != dict:
            continue
        return value[target_key ]
    return None

class TestRps(unittest.TestCase):
    """
    Test cases for testing the functionality of rps module
    """
    def check_template_generated_by_get_request(self, client, path, expectedTemplate):
        response = client.get(path)
        templateCalled, = flask.render_template.call_args[0]
        self.assertEqual(templateCalled, expectedTemplate)
    def play(self, client, nick, country, played, captchaText=None):
        response = client.get('/join')
        captcha_id = lookForCallKey(flask.render_template.call_args, 'captcha_id')
        for i in response.get_data().decode('utf-8').split('\n'):
            if 'csrf_token' in i:
                root = ET.fromstring(i)
                break
        csrf_token = root.attrib['value']

        return client.post('/action',
            data={
            'csrf_token': csrf_token,
            'nick': nick,
            'country': country,
            'played': played,
            'captcha': captcha.fetch_captcha_answer(captcha_id) if captchaText == None else captchaText,
            'captcha_id': str(captcha_id)
            }
        )
    def setUp(self):
        if os.path.exists(rps.app.config['DATABASE_NAME']):
            os.remove(rps.app.config['DATABASE_NAME'])
        rps.setup_db()
    def test_setup_db(self):
        #Delete the database file and check
        os.remove(rps.app.config['DATABASE_NAME'])
        self.assertFalse(os.path.exists(rps.app.config['DATABASE_NAME']))
        #Create the database file and check
        rps.setup_db()
        self.assertTrue(os.path.exists(rps.app.config['DATABASE_NAME']))
        #Check if the columes exists. If not, it'll raise an exception and this test case will fail
        conn = sqlite3.connect(rps.app.config['DATABASE_NAME'])
        conn.execute("SELECT pk, nick, country, played, cheat, timestamp, score used FROM game")
        conn.close()
    def test_page_routing_before_event(self):
        """
            Test if template routing is working correctly before the event had started
        """
        rps.app.config['START_TIME'] = (datetime.datetime.now()+datetime.timedelta(days=1))
        rps.app.config['END_TIME'] = (datetime.datetime.now()+datetime.timedelta(days=2))
        with rps.app.test_client() as client:
            with flaskTemplateMocker:
                self.check_template_generated_by_get_request(client, '/', 'index.html')
                self.check_template_generated_by_get_request(client, '/about', 'about.html')
                self.check_template_generated_by_get_request(client, '/join', 'join_not_started.html')
                self.check_template_generated_by_get_request(client, '/result', 'result_not_ended.html')
                #Ensure that POSTing to /action during the event won't return HTTP 200
                response = client.post('/action')
                self.assertNotEqual(response.status_code, 200)
                #Ensure that POSTing to /done before the event won't return HTTP 200
                response = client.get('/done')
                self.assertNotEqual(response.status_code, 200)
    def test_page_routing_during_event(self):
        """
            Test if template routing is working correctly during the event
        """
        rps.app.config['START_TIME'] = (datetime.datetime.now()+datetime.timedelta(days=-1))
        rps.app.config['END_TIME'] = (datetime.datetime.now()+datetime.timedelta(days=1))
        with rps.app.test_client() as client:
            with flaskTemplateMocker:
                self.check_template_generated_by_get_request(client, '/', 'index.html')
                self.check_template_generated_by_get_request(client, '/about', 'about.html')
                self.check_template_generated_by_get_request(client, '/join', 'join.html')
                self.check_template_generated_by_get_request(client, '/result', 'result_not_ended.html')
                #We're saving /action for another test case.
                #response = client.post('/action')
                #self.assertNotEqual(response.status_code, 200)
                #Ensure that POSTing to /done during the event will return HTTP 200
                response = client.get('/done')
                self.assertEqual(response.status_code, 200)
    def test_page_routing_after_event(self):
        """
            Test if template routing is working correctly after the event had ended
        """
        rps.app.config['START_TIME'] = (datetime.datetime.now()+datetime.timedelta(days=-2))
        rps.app.config['END_TIME'] = (datetime.datetime.now()+datetime.timedelta(days=-1))
        with rps.app.test_client() as client:
            with flaskTemplateMocker:
                self.check_template_generated_by_get_request(client, '/', 'index.html')
                self.check_template_generated_by_get_request(client, '/about', 'about.html')
                self.check_template_generated_by_get_request(client, '/join', 'join_ended.html')
                self.check_template_generated_by_get_request(client, '/result', 'result.html')
                #Ensure that POSTing to /action after the event won't return HTTP 200
                response = client.post('/action')
                self.assertNotEqual(response.status_code, 200)
                #Ensure that POSTing to /done after the event won't return HTTP 200
                response = client.get('/done')
                self.assertNotEqual(response.status_code, 200)
    def test_page_simulate_event_without_players(self):
        """
            Simulate an event without any player and check the result
        """
        EVENT_DURATION = 5
        rps.app.config['START_TIME'] = (datetime.datetime.now())
        rps.app.config['END_TIME'] = (datetime.datetime.now()+datetime.timedelta(seconds=EVENT_DURATION))
        startTime = time.time()
        with rps.app.test_client() as client:
            with flaskTemplateMocker as functionCalled:
                #We've got no players. So we just wait.
                #Wait for the completion of the event
                time.sleep(EVENT_DURATION-(time.time()-startTime))
                client.get('/result')
                players = lookForCallKey(functionCalled.call_args, 'players')
                self.assertEqual(players, [])
    def test_page_play_simple(self):
        """
            Ensure that self.play() is working correctly
        """
        rps.app.config['START_TIME'] = (datetime.datetime.now())
        rps.app.config['END_TIME'] = (datetime.datetime.now()+datetime.timedelta(days=1))
        with rps.app.test_client() as client:
            with flaskTemplateMocker as functionCalled:
                response = self.play(client, 'test', 'us', 'pspprprpsrrrpsprppspsrsspprsssprrrpsrprrsspprrprrs')
                self.assertTrue(response.headers.get('Location').endswith('done'))
    def test_page_play_duplicated_name(self):
        """
            Ensure that the website does not allow duplicate of player name
        """
        rps.app.config['START_TIME'] = (datetime.datetime.now())
        rps.app.config['END_TIME'] = (datetime.datetime.now()+datetime.timedelta(days=1))
        with rps.app.test_client() as client:
            with flaskTemplateMocker as functionCalled:
                self.play(client, 'test', 'us', 'pspprprpsrrrpsprppspsrsspprsssprrrpsrprrsspprrprrs')
                self.play(client, 'test', 'cn', 'ssssrrrppsrrspsrpprssssprprsrprpsprrrpprsrppssrrpp')
                self.assertEqual(functionCalled.call_args[0][0], 'join.html')
    def test_page_play_wrong_captcha(self):
        """
            Ensure that the website requires a correct captcha
        """
        rps.app.config['START_TIME'] = (datetime.datetime.now())
        rps.app.config['END_TIME'] = (datetime.datetime.now()+datetime.timedelta(days=1))
        with rps.app.test_client() as client:
            with flaskTemplateMocker as functionCalled:
                self.play(client, 'test', 'us', 'pspprprpsrrrpsprppspsrsspprsssprrrpsrprrsspprrprrs', '12345678')
                self.assertEqual(functionCalled.call_args[0][0], 'join.html')
    def test_page_play_invalid_country(self):
        """
            Ensure that the website requires a valid country code
        """
        rps.app.config['START_TIME'] = (datetime.datetime.now())
        rps.app.config['END_TIME'] = (datetime.datetime.now()+datetime.timedelta(days=1))
        with rps.app.test_client() as client:
            with flaskTemplateMocker as functionCalled:
                self.play(client, 'test', 'xx', 'pspprprpsrrrpsprppspsrsspprsssprrrpsrprrsspprrprrs')
                self.assertEqual(functionCalled.call_args[0][0], 'join.html')
    def test_page_play_invalid_hands(self):
        """
            Ensure that the website disallows playing of invalid hands
        """
        rps.app.config['START_TIME'] = (datetime.datetime.now())
        rps.app.config['END_TIME'] = (datetime.datetime.now()+datetime.timedelta(days=1))
        with rps.app.test_client() as client:
            with flaskTemplateMocker as functionCalled:
                #Too many consequtive hands
                self.play(client, 'test', 'us', 'pppppprpsrrrpsprppspsrsspprsssprrrpsrprrsspprrprrs')
                self.assertEqual(functionCalled.call_args[0][0], 'join.html')
                self.play(client, 'test', 'us', 'sssssrrpsrrrpsprppspsrsspprsssprrrpsrprrsspprsssss')
                self.assertEqual(functionCalled.call_args[0][0], 'join.html')
                self.play(client, 'test', 'us', 'pspprprpsrrrrrrsppspsrsspprsssprrrpsrprrsspprrprrs')
                self.assertEqual(functionCalled.call_args[0][0], 'join.html')
                #Too many hands played
                self.play(client, 'test', 'us', 'pspprprpsrrrpsprppspsrsspprsssprrrpsrprrsspprrprrsr')
                #Not enough hands played
                self.play(client, 'test', 'us', 'pspprprpsrrrpsprppspsrsspprsssprrrpsrprrsspprrprr')
                self.assertEqual(functionCalled.call_args[0][0], 'join.html')
    def test_page_simulate_event_with_players(self):
        return
        """
            Simulate an event with a few players and check the result
        """
        EVENT_DURATION = 5
        rps.app.config['START_TIME'] = (datetime.datetime.now())
        rps.app.config['END_TIME'] = (datetime.datetime.now()+datetime.timedelta(seconds=EVENT_DURATION))
        startTime = time.time()
        time.sleep(EVENT_DURATION-(time.time()-startTime))
        with rps.app.test_client() as client:
            with flaskTemplateMocker as functionCalled:
                #Simulate playing the game

                #Wait for the completion of the event
                time.sleep(EVENT_DURATION-(time.time()-startTime)+1)
                client.get('/result')
                players = lookForCallKey(functionCalled.call_args, 'players')
                self.assertEqual(players,
                [
                {'i': 1, 'country': 'us', 'nick': 'test', 'score': 7, 'cheat': 0, 'played': 'pspprprpsrrrpsprppspsrsspprsssprrrpsrprrsspprrprrs'},
                {'i': 2, 'country': 'uy', 'nick': 'bar', 'score': 0, 'cheat': 0, 'played': 'ssssrrrppsrrspsrpprssssprprsrprpsprrrpprsrppssrrpp'},
                {'i': 3, 'country': 'hk', 'nick': 'foo', 'score': -3, 'cheat': 0, 'played': 'rssrsrrrrsppsppsprsrpppppsspprrsrpsrspppsprsrprpss'},
                {'i': 4, 'country': 'se', 'nick': 'baz', 'score': -4, 'cheat': 0, 'played': 'prsrpsrrrsrpprspppprppspsprprssprspppppspssrpsrrsp'}
                ]
                )

                #TODO: also view the cert

if __name__ == '__main__':
    unittest.main()


import torch
import torch.nn as nn
import torch.nn.functional as F
from modeling.sync_batchnorm.batchnorm import SynchronizedBatchNorm2d

class Decoder(nn.Module):

    def __init__(self, n_class, BatchNorm):
        super(Decoder, self).__init__()
        eps = 1e-5
        momentum = 0.1
        self._conv = nn.Sequential(
                                    nn.ReLU(inplace=True),
                                    nn.Conv2d(304, 256, kernel_size=3, stride=1, padding=1, bias=False),
                                    BatchNorm(256, eps=eps, momentum=momentum),
                                    nn.ReLU(inplace=True),
                                    # 3x3 conv to refine the features
                                    nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1, bias=False),
                                    BatchNorm(256, eps=eps, momentum=momentum),
                                    nn.ReLU(inplace=True),
                                    nn.Conv2d(256, n_class, kernel_size=1, stride=1))

    def forward(self, x, low_level, size):
        x = F.interpolate(x, [low_level.shape[2], low_level.shape[3]], mode='bilinear') \
            if x.shape[2] != low_level.shape[2] else x
        x = torch.cat((x, low_level), 1)
        x = self._conv(x)
        x = F.interpolate(x, size, mode='bilinear')

        return x


from typing import Annotated

from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Depends, Cookie
from fastapi.middleware.cors import CORSMiddleware

from .services import get_chatbot_maker

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:3000"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

class ModelApiExtractor:
    def __init__(self, api_key: Annotated[str, Cookie()], model: Annotated[str, Cookie()]):
        self.api_key = api_key
        self.model = model

@app.get("/")
async def root():
    return {"message": "Hello World"}

@app.get("/models")
async def models() -> list[dict]:
    return [{"id": idx, "name": value} for idx, value in enumerate(get_chatbot_maker().keys())]

@app.websocket("/chat")
async def chat_endpoint(websocket: WebSocket, config: Annotated[ModelApiExtractor, Depends()]):
    await websocket.accept()
    chatbot = get_chatbot_maker()[config.model](config.api_key)
    await websocket.send_json({"sender": "bot", "text": "Hello, Alice here, how can I help you?"})
    while True:
        try:
            data = await websocket.receive_json()
            bot_response = chatbot.chat(human_input=data["text"])
            await websocket.send_json({"sender": "bot", "text": bot_response})
        except WebSocketDisconnect:
            break


import matplotlib
import numpy as np

matplotlib.rcParams['pdf.fonttype'] = 42
matplotlib.rcParams['ps.fonttype'] = 42
from matplotlib import pyplot as plt
from cnns.nnlib.robustness.utils import to_fft_magnitude
import torch
from cnns.nnlib.utils.object import Object
from cnns.nnlib.datasets.ucr.ucr_example import fifty_words
from cnns.nnlib.pytorch_layers.pytorch_utils import get_full_energy_only

# http://ksrowell.com/blog-visualizing-data/2012/02/02/optimal-colors-for-graphs/
MY_BLUE = (56, 106, 177)
MY_RED = (204, 37, 41)
MY_ORANGE = (218, 124, 48)
MY_GREEN = (62, 150, 81)
MY_BLACK = (83, 81, 84)
MY_GOLD = (148, 139, 61)

def get_color(COLOR_TUPLE_255):
    return [x / 255 for x in COLOR_TUPLE_255]

colors = [get_color(color) for color in
          [MY_GREEN, MY_BLUE, MY_BLACK, MY_ORANGE, MY_GOLD, MY_RED]]

figuresizex = 9.0
figuresizey = 5.0
fig = plt.figure(figsize=(figuresizex, figuresizey))

lw = 1
onesided = False
normalized = True
signal = fifty_words

print("Energy of the input signal: ", np.sum(np.square(signal)))

print("min max value signal: ", np.min(signal), np.max(signal))
is_log = True
markers = ["^", "o", "v", "s", "D", "p"]

signal = signal[0][0]
print("signal length: ", len(signal))
print("Energy of the input signal (torch): ",
      torch.sum(torch.pow(torch.from_numpy(signal), 2)).item())
plt.subplot(2, 2, 1)
plt.plot(range(len(signal)), signal, label="input signal", lw=1,
         color=colors[1])
plt.title("Time domain")
plt.ylabel("Amplitude")
plt.xlabel("Sample number")
plt.legend(frameon=False)

plt.subplot(2, 2, 2)

xfft = torch.rfft(torch.from_numpy(signal), onesided=onesided, signal_ndim=1,
                  normalized=normalized)
print("Energy in the frequency domain (pytorch): ", get_full_energy_only(xfft))
x_numpy = xfft[..., 0].numpy() + 1.0j * xfft[..., 1].numpy()
print("Energy in the frequency domain (numpy): ",
      np.sum(np.power(np.absolute(x_numpy), 2)))
xfft_mag = to_fft_magnitude(xfft, is_log)
plt.plot(range(len(signal)), xfft_mag, label="fft-ed signal", lw=lw,
         color=colors[2])
plt.title("Frequency domain")
plt.ylabel("dB")
plt.xlabel("Frequency (sample number)")
plt.legend(frameon=False)

compression_rate = 95
out_len = len(signal) * (100 - compression_rate) / 100
start = int(out_len // 2)
end = int(len(signal) - start)
print("compression rate, start, end: ", compression_rate, start, end)
xfft[start:end] = 0
signal2 = torch.irfft(xfft, onesided=onesided, signal_ndim=1,
                      normalized=normalized)
signal2 = signal2.numpy()

plt.subplot(2, 2, 3)
plt.plot(range(len(signal2)), signal, label="input signal", lw=lw,
         color=colors[1])
plt.plot(range(len(signal2)), signal2, label="compressed signal\n(" + str(
    compression_rate) + "% compression\nrate)", lw=lw,
         color=colors[5])
plt.legend(loc="upper left", frameon=False)
plt.ylabel("Amplitude")
plt.xlabel("Sample number")

plt.subplot(2, 2, 4)
xfft_mag = to_fft_magnitude(xfft, is_log)
plt.plot(range(len(signal)), xfft_mag,
         label="fft-ed signal\n(" + str(
             compression_rate) + "% compression rate)",
         lw=lw, color=colors[2])
plt.ylabel("dB")
plt.xlabel("Frequency (sample number)")
plt.legend(loc="upper center", frameon=False)

# type = "exact"
# type = "proxy"
compress_fft_layer = 50
result = Object()

# xfft = get_fft(image)
# image = np.clip(image, a_min=0.0, a_max=1.0)

# xfft = get_fft(image)
# xfft += np.abs(xfft.min())
# xfft = np.clip(xfft, a_min=0.0, a_max=118.0)
# image = np.moveaxis(image, 0, -1)

# example of titling colorbar1
# cbar1.set_label_text("label")

# readjust figure margins after adding colorbars,
# left and right are unequal because of how
# colorbar labels don't appear to factor in to the adjustment
# plt.subplots_adjust(left=0.075, right=0.9)

plt.subplots_adjust(hspace=0.3)

type = "original"
format = "pdf"  # "png" "pdf"
plt.savefig(fname=type + "-1D-2." + format, format=format)
plt.show(block=True)
plt.close()


#! -*- coding: utf-8 -*-
import  fasttext
vector_size=128
word_ngrams=3
words_file='data/comments_w2v_train.txt'
cbow_file='model/word2vec_cbow_'+str(vector_size)
w2v_model = fasttext.cbow(words_file, cbow_file, lr=0.1,dim=vector_size,min_count=2,word_ngrams=word_ngrams,minn=1,maxn=15,ws=3,silent=0,epoch=50,bucket=200000)
print("&"*50)

skip_file='model/word2vec_skip_'+str(vector_size)
w2v_model = fasttext.skipgram(words_file, skip_file, lr=0.1,dim=vector_size,min_count=2,word_ngrams=word_ngrams,minn=1,maxn=15,ws=3,silent=0,epoch=50,bucket=200000)
print("&"*50)

classify5_file="model/fasttext_sentiment_5c_"+str(vector_size)
classify5_model=fasttext.supervised('data/comments_fasttext_train.txt', classify5_file, label_prefix="__label__", dim=vector_size, min_count=2, ws=3,word_ngrams=word_ngrams, minn=1, maxn=15, epoch=20, silent=0, bucket=200000)
test5 = classify5_model.test('data/comments_fasttext_test.txt')
train5_pred=classify5_model.test('data/comments_fasttext_train.txt')
print('train data ：precision=%f,recall=%f'%(train5_pred.precision,train5_pred.recall))
print('test data ：precision=%f,recall=%f'%(test5.precision,test5.recall))

classify2_file="model/fasttext_sentiment_2c_"+str(vector_size)
classify2_model=fasttext.supervised('data/comments_fasttext_train_2c.txt', classify2_file, label_prefix="__label__", dim=vector_size, min_count=2, ws=3,word_ngrams=word_ngrams, minn=1, maxn=15, epoch=20, silent=0, bucket=200000)
test2 = classify2_model.test('data/comments_fasttext_test_2c.txt')
train2_pred=classify2_model.test('data/comments_fasttext_train_2c.txt')
print('train data ：precision=%f,recall=%f'%(train2_pred.precision,train2_pred.recall))
print('test data ：precision=%f,recall=%f'%(test2.precision,test2.recall))


import requests
from bs4 import BeautifulSoup
import pandas as pd
url = "https://www.numbeo.com/cost-of-living/rankings_by_country.jsp"
page = requests.get(url)
soup = BeautifulSoup(page.text, 'lxml')
table = soup.find('table', id = 't2')
head = []

for i in table.find_all('th'):
    head.append(i.text)
print(head)

data = pd.DataFrame(columns = head)

for j in table.find_all('tr')[1:]:
    row_data = j.find_all('td')
    row = [i.text for i in row_data]

    length = len(data)

    data.loc[length] = row

data.to_json('cost_of_living.json')

datatest = pd.read_json("cost_of_living.json")


import cv2 as cv
import numpy as np
import urllib.request

# change to your ESP32-CAM ip

url = 'http://192.168.10.187/cam-lo.jpg'       #hi or lo
winName = 'CAM'
cv.namedWindow("winName")

while 1:
 imgResponse = urllib.request.urlopen(url)
 imgNp=np.array(bytearray(imgResponse.read()),dtype=np.uint8)
 img=cv.imdecode(imgNp, -1)
 cv.imshow("winName",img)
 tecla = cv.waitKey(5) & 0xFF
 if tecla == 27:
   break

cv.destroyALLWINDOWS()


import tkinter as tk
import tkinter.ttk as ttk
import tkinter.constants as ctk
from tkinter import messagebox

class MyView(tk.Tk):
    def __init__(self, title: str):
        super().__init__()
        self.title(title)
        self.columnconfigure(0, weight=1)
        self.columnconfigure(1, weight=1)
        self.columnconfigure(2, weight=1)
        self.columnconfigure(3, weight=1)
        self.rowconfigure(1, weight=1)

        ################################################ menu
        # style
        style_frame = ttk.Style(self)
        style_frame.configure("test.TLabel", background="gray")
        style_save = ttk.Style(self)
        style_save.configure("save.TButton", background="gray", foreground="green")
        style_exit = ttk.Style(self)
        style_exit.configure("exit.TButton", background="gray", foreground="red")
        # widget
        self.save = ttk.Button(
            self, text="Sauvegarder", style="save.TButton", command=self.do_save
        )
        self.exit = ttk.Button(
            self, text="Quitter", command=self.destroy, style="exit.TButton"
        )
        # position
        self.save.grid(columnspan=2, row=0, sticky=ctk.NSEW)
        self.exit.grid(column=2, columnspan=2, row=0, sticky=ctk.NSEW)
        ################################################ text
        self.text = tk.Text(self)
        self.text.grid(columnspan=4, row=1, sticky=ctk.NSEW)
        scrollbar_ver = ttk.Scrollbar(self, orient=ctk.VERTICAL,command=self.text.yview)
        scrollbar_ver.grid(column=4, row=1, sticky=ctk.E)
        scrollbar_hor = ttk.Scrollbar(self, orient=ctk.HORIZONTAL,command=self.text.xview)
        scrollbar_hor.grid(columnspan=5, row=2, sticky=ctk.S)
        self.text.configure(yscrollcommand=scrollbar_ver.set,xscrollcommand=scrollbar_hor.set)
        ################################################ bottom bar
        self.position_text = ttk.Label(self, text="position")
        self.position_text.grid(column=0, row=3, sticky=ctk.W)
        self.zoom_text = ttk.Label(self, text="zoom")
        self.zoom_text.grid(column=1, row=3, sticky=ctk.E)
        self.encoding = ttk.Label(self, text="encoding")
        self.encoding.grid(column=2, row=3, sticky=ctk.E)
        self.format_text = ttk.Label(self, text="format")
        self.format_text.grid(column=3, row=3, sticky=ctk.E)

    def do_save(self):
        try:
            self.controller.save(self.text.get(1.0,ctk.END))
        except AttributeError:
            self.error_message("Erreur Controller !")

    def error_message(self, message: str) -> None:
        messagebox.showerror("Erreur Notepad", message)

    def start_my_view(self) -> None:
        self.mainloop()

    def set_controller(self, value):
        self.controller = value

    def success_message(self, message: str):
        messagebox.showinfo("confirmation notepad", message)


"""Datetime utilities."""

import numpy as np
import pandas as pd

from vectorbt.utils import checks

DatetimeTypes = (pd.DatetimeIndex, pd.TimedeltaIndex, pd.PeriodIndex)

def freq_delta(freq):
    """Return delta of frequency."""
    if isinstance(freq, str) and not freq[0].isdigit():
        # Otherwise "ValueError: unit abbreviation w/o a number"
        freq = '1' + freq
    return pd.to_timedelta(freq)

def to_time_units(obj, freq):
    """Multiply each element with `freq_delta` to get result in time units."""
    if not checks.is_array(obj):
        obj = np.asarray(obj)
    return obj * freq_delta(freq)


# 杨辉三角
#给定一个非负整数 numRows，生成“杨辉三角”的前 numRows 行。
#在“杨辉三角”中，每个数是它左上方和右上方的数的和。
# input:numRows = 5 output: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]
#     1
#    1 1
#   1 2 1
#  1 3 3 1
# 1 4 6 4 1
# dp[i][j] = dp[i-1][j-1] + dp[i-1][j]

def generate(numRows):
    ret = list()
    for i in range(0,numRows):
        row = list()
        for j in range(0,i + 1):
            if j == 0 or j == i:
                row.append(1)
            else:
                row.append(ret[i-1][j] + ret[i-1][j-1])
        ret.append(row)
    return ret

numRows = 5
print(generate(numRows))


# -*- coding: utf-8 -*-
"""
Created on Tue Aug 11 20:27:50 2020

@author: renli
"""

# recursive
def getUmbrellas(V, deno):
    from functools import lru_cache
    deno=tuple(deno)
    @lru_cache(maxsize=None)
    def f(requirement,size):
        if requirement==0:
            return 0
        elif requirement<0:
            return float('inf')
        if not size:
            return float('inf')
        res=min(
            (f(requirement-ele,size) for ele in size)
            )+1
        return res

    res=f(V,deno)
    return res if res!=float('inf') else -1

#dynamic programming
def getUmbrellas(V, deno):
    dp=[float('inf')]*(V+1)
    dp[0]=0
    for i,ele in enumerate(dp[1:]):
        i=i+1
        min_res=float('inf')
        for size in deno:
            if i-size>=0:
                min_res=min(min_res,dp[i-size])
        dp[i]=min_res+1
    return dp[-1] if dp[-1]!=float('inf') else -1

if __name__=="__main__":
    res=getUmbrellas(7,[3,5])


def get_dataloader_classes(dataloader):

    # returns an array with all the classes found in data loader:
    # future: optimize so doesnt go through whole dataset?

    classes = set()

    for _, batch_classes in dataloader:

        classes = classes.union(batch_classes.detach().cpu().numpy())

    return list(classes)


import pyautogui as auto
import pygame
import pygame_widgets as pw
from pygame_widgets.slider import Slider
import random
import numpy
from collections import namedtuple
import sys

DISPLAY_WIDTH = 700
DISPLAY_HEIGHT = 600

class game:

    def __init__(self):
        self.width = DISPLAY_WIDTH
        self.height = DISPLAY_HEIGHT
        self.window = pygame.display.set_mode((self.width, self.height))
        pygame.display.set_caption("Snek Game")
        pygame.init()

    def draw(self, color=(0, 0, 0)):
        self.window.fill(color)

class Block:

    def __init__(self, t, l, w, h):
        bound = namedtuple('Bound', ['left', 'top', 'width', 'height'])
        self.bound = bound(l, t, w, h)
        self.color = (random.randint(0, 255),
                      random.randint(0, 255),
                      random.randint(0, 255))

    def draw(self, surface):
        pygame.draw.rect(surface, self.color, self.bound)

    def updateColor(self, row, col, size, screenshot):
        red = numpy.mean(screenshot[row * size:row * size + size, col * size:col * size + size, 0])
        green = numpy.mean(screenshot[row * size:row * size + size, col * size:col * size + size, 1])
        blue = numpy.mean(screenshot[row * size:row * size + size, col * size:col * size + size, 2])
        if numpy.isnan(red) == False and numpy.isnan(green) == False and numpy.isnan(blue) == False:
            self.color = (int(red), int(green), int(blue))

class Grid:

    def __init__(self):
        self.pixels = []
        self.imageWidth = 800
        self.imageHeight = 500
        self.imageTop = 300
        self.imageLeft = 600
        self.screenshot = None

    def update(self, sizePercentage):
        top = DISPLAY_HEIGHT * .1
        left = DISPLAY_WIDTH * .1
        width = DISPLAY_WIDTH * .7
        height = DISPLAY_HEIGHT * .7

        self.screenshot = auto.screenshot("test.png",
                                     region=[self.imageLeft, self.imageTop, self.imageWidth, self.imageHeight])
        self.screenshot = numpy.array(self.screenshot)

        pixelSize = int(sizePercentage * self.imageWidth)
        imageHeight = int(self.imageHeight / pixelSize)
        imageWidth = int(self.imageWidth / pixelSize)

        displayWidth = int(sizePercentage * width)
        displayHeight = int(sizePercentage * height)

        self.pixels = [
            [Block(j * (displayHeight + 2) + top, i * (displayWidth + 2) + left, displayWidth, displayHeight) for i in
             range(imageWidth)]
            for j in range(imageHeight)]
        for row in range(len(self.pixels)):
            for col in range(len(self.pixels[row])):
                self.pixels[row][col].updateColor(row, col, pixelSize, self.screenshot)

    def draw(self):
        for row in range(len(self.pixels)):
            for col in range(len(self.pixels[row])):
                self.pixels[row][col].draw(main.window)

    def isFishing(self):
        avgBlue = numpy.mean(self.screenshot[:,:,2])
        return avgBlue > 50

    def fishAngry(self):
        redEnough = self.screenshot[(self.screenshot[:,:,0] >= 90) & (self.screenshot[:,:,0] < 150)]
        filtered = redEnough[ (redEnough[:,2] < 40) & (redEnough[:,1] < 40)]

        return len(filtered) != 0

main = game()
grid = Grid()

slider = Slider(main.window, int(DISPLAY_WIDTH * .05),
                int(DISPLAY_HEIGHT * .01),
                int(DISPLAY_WIDTH * .30),
                int(DISPLAY_HEIGHT * .025),
                initial=20,
                min=5,
                max=100,
                step=5,
                handleColour=(250, 50, 50))

# colorChange(blocks)
gameState = "SCANNING"
try:
    with open("data.txt") as fin:
        data = fin.readline().split(',')
        grid.imageTop = int(data[0])
        grid.imageLeft = int(data[1])
        grid.imageWidth = int(data[2])
        grid.imageHeight = int(data[3])
except:
    print("No Data")

while True:

    events = pygame.event.get()
    for event in events:
        if event.type == pygame.QUIT:
            pygame.quit()
            with open("data.txt",'w') as fout:
                fout.write("{},{},{},{}".format(
                    grid.imageTop,
                grid.imageLeft,
                grid.imageWidth,
                grid.imageHeight
                ))

            sys.exit()
        if event.type == pygame.KEYDOWN and event.key == pygame.K_c:
            gameState = "CALLIBRATE"

        if event.type == pygame.KEYDOWN and event.key == pygame.K_m:
            auto.mouseInfo()

        if gameState == "CALLIBRATE" and event.type == pygame.MOUSEBUTTONDOWN:
            gameState = "CALLIBRATE2"
            grid.imageTop = auto.position()[1]
            grid.imageLeft = auto.position()[0]
            startClick = (pygame.mouse.get_pos()[1], pygame.mouse.get_pos()[0])

        if gameState == "CALLIBRATE2" and event.type == pygame.MOUSEBUTTONUP:
            gameState = "SCANNING"

            grid.imageHeight = auto.position()[1] - grid.imageTop
            grid.imageWidth = auto.position()[0] - grid.imageLeft

    main.draw()

    # if sliderValue != slider.getValue():

    if gameState == "SCANNING":
        grid.update(slider.getValue() / (DISPLAY_WIDTH / 2))
        grid.draw()
    elif gameState == "CALLIBRATE":
        main.draw((255, 0, 0))
    elif gameState == "CALLIBRATE2":
        main.draw((255, 255, 0))
        pygame.draw.rect(main.window, (255, 0, 0), (grid.imageLeft,
                                                    grid.imageTop,
                                                    pygame.mouse.get_pos()[0] - grid.imageLeft,
                                                    pygame.mouse.get_pos()[1] - grid.imageTop))
    if grid.isFishing():
        if grid.fishAngry() == True:
            main.draw((255, 0, 0))
            auto.mouseUp(button='right')
        else:
            main.draw((0, 255, 250))
            auto.mouseDown(button='right')

    pw.update(events)
    pygame.display.update()


"""Parameter space exploration tool.

See the documentation at https://github.com/amorison/parspace
"""

from itertools import product

class ParSpace:
    """Parameter space explorer.

    Example:
        >>> @ParSpace(asp=[0.5, 1, 2],
        >>>           density=[1, 10])
        >>> def launch_simu(asp, density):
        >>>     print(f"aspect ratio {asp} and density {density}")
        >>> launch_simu()
        aspect ratio 0.5 and density 1
        aspect ratio 0.5 and density 10
        aspect ratio 1 and density 1
        aspect ratio 1 and density 10
        aspect ratio 2 and density 1
        aspect ratio 2 and density 10
    """

    def __init__(self, **space):
        self._space = space
        self._thunk = None

    def _sweeper(self):
        parnames = list(self._space.keys())
        for comb in product(*(self._space[name] for name in parnames)):
            yield dict(zip(parnames, comb))

    def __iter__(self):
        if self._thunk is None:
            yield from self._sweeper()
            return
        for pars in self._sweeper():
            yield pars, self._thunk(**pars)

    def __call__(self, func=None):
        if func is not None:
            self._thunk = func
            return self
        for _ in iter(self):
            pass


import json
import zlib
import copy
from pipeflow import Task

class TaskProtocal(Task):
    __slots__ = ['_info']
    def __init__(self, task):
        assert isinstance(task, (Task, dict)), "task should be a instance of Task or dict"
        if isinstance(task, Task):
            _data = task.get_raw_data()
            super(TaskProtocal, self).__init__(_data)
            self.set_from(task.get_from())
            self.set_to(task.get_to())
            self.set_confirm_handle(task.get_confirm_handle())
            self._info = json.loads(zlib.decompress(_data).decode('utf-8'))
        else:
            super(TaskProtocal, self).__init__(zlib.compress(json.dumps(task).encode('utf-8')))
            self._info = task
        assert 'i' in self._info and 'tid' in self._info, "Task Protocal illegal"

    def get_data(self):
        return copy.deepcopy(self._info['data'])

    def get_tid(self):
        return self._info['tid']

    def get_step(self):
        return self._info['i']

    def new_task(self, data, tid=None, next_step=False):
        assert isinstance(data, dict), "data isn't a dict"
        if 'extra' in self._info['data']:
            dct = data.setdefault("extra", {})
            dct.update(self._info['data']['extra'])
        dct = {
            'tid': tid if tid else self._info['tid'],
            'i': 0 if tid else self._info['i']+1 if next_step else self._info['i'],
            'data': data
        }
        tp = TaskProtocal(dct)
        tp.set_confirm_handle(self.get_confirm_handle())
        return tp


#Uses a function for each shape and in the square function uses a loop
import turtle

def draw_turtle():
	window = turtle.Screen()
	window.bgcolor("red")

	draw_square()
	draw_circle()
	draw_triangle()

	window.exitonclick()

def draw_square():

	brad = turtle.Turtle()
	brad.shape("turtle")
	brad.color("yellow")
	brad.speed(6)

	for i in range(5):
		brad.forward(100)
		brad.right(90)

def draw_circle():

	brad = turtle.Turtle()
	brad.shape("turtle")
	brad.color("blue")
	brad.speed(6)

	brad.circle(100)

def draw_triangle():

	triangle = turtle.Turtle()
	triangle.shape("turtle")
	triangle.color("black")
	triangle.speed(6)

	triangle.left(90)
	triangle.forward(200)
	triangle.right(135)
	triangle.forward(150)
	triangle.right(90)
	triangle.forward(135)

draw_turtle()


#Convert a list of Tuples into Dictionary

list1=[("Nakul",93), ("Shivansh",45), ("Samved",65),
           ("Yash",88), ("Vidit",70), ("Pradeep",52)]

dict1=dict()

for student,score in list1:
    dict1.setdefault(student,[]).append(score)

print(dict1)


#!/usr/bin/env python3
import sqlite3
import math
import pprint
import logging

import typing as t

import sys, getopt
import re
import os
import json
from enum import IntEnum, auto

def die(msg):
	print(msg, file=sys.stderr)
	sys.exit(1)

class sqltype(IntEnum):
	INTEGER = auto()
	REAL = auto()
	TEXT = auto()
	def __str__(self) -> str:
		return self.name

def merge_sqltypes(obja, objb):
	return max(obja, objb)

def make_sqltype(obj: t.Any) -> sqltype:
	try:
		int(obj)
		return sqltype.INTEGER
	except ValueError:
		pass
	except TypeError:
		pass
	try:
		float(obj)
		return sqltype.REAL
	except ValueError:
		pass
	except TypeError:
		pass
	logging.debug(f"type of {obj} is TEXT")
	return sqltype.TEXT

def split_keyvalueline(line: str) -> t.Mapping[str,str]:
	""" read a line of 'key=value' pairs separated by whitespace(s) into a dict """
	attrs=dict()
	while line.find('=') != -1:
		key = line[:line.find('=')]
		valuematch = re.match(r'^\S+', line[line.find('=')+1:])
		assert valuematch, 'invalid key/value line: %s' % line
		value = valuematch.group(0)
		line=line[len(key)+len(value)+1:]
		key = key.strip()
		value = value.strip()
		attrs[key] = value
	return attrs

def split_resultline(line: str) -> t.Mapping[str,str]:
	""" read a RESULT line and put the keyvalue pairs into a dict """
	return split_keyvalueline(line[len('RESULT '):].strip())

def create_json_table(tablename: str, tablefilename: str):
	import json
	with open(tablefilename,'r') as tablefile:
		json_data = json.loads(tablefile.read())
	keys = dict()
	for entry in json_data:
		for key in entry.keys():
			if not key in keys:
				keys[key] = make_sqltype(entry[key])
			else:
				keys[key] = merge_sqltypes(make_sqltype(entry[key]), keys[key])

	columns=[]
	for key in keys:
		columns.append('"%s" %s' % (key, str(keys[key])))
	sqlexecute('CREATE TABLE "%s" (%s);' % (tablename, ', '.join(columns)))

	for entry in json_data:
		sqlexecute('INSERT INTO "%s" (%s) VALUES (%s);' % (tablename
			, ', '.join(map(lambda key : '"' + str(key) + '"' , entry.keys()))
			, ', '.join(map(lambda value : '\'' + str(value) + '\'', entry.values()))))
	conn.commit()

def create_table(tablename: str, tablefilename: str):
	""" read the types of the used keys """
	keys = dict()
	with open(tablefilename,'r') as tablefile:
		for tableLine in tablefile.readlines():
			if tableLine.startswith('RESULT '):
				attrs = split_resultline(tableLine)
				for key in attrs:
					if not key in keys:
						keys[key] = make_sqltype(attrs[key])
					else:
						keys[key] = merge_sqltypes(make_sqltype(attrs[key]), keys[key])
	columns=[]
	for key in keys:
		columns.append('"%s" %s' % (key, str(keys[key])))
	sqlexecute('CREATE TABLE "%s" (%s);' % (tablename, ', '.join(columns)))

	# read the values
	with open(tablefilename, 'r') as tablefile:
		for tableLine in tablefile.readlines():
			if tableLine.startswith('RESULT '):
				attrs = split_resultline(tableLine)
				sqlexecute('INSERT INTO "%s" (%s) VALUES (%s);' % (tablename
					, ', '.join(map(lambda key : '"' + key + '"' , attrs.keys()))
					, ', '.join(map(lambda value : '\'' + value + '\'', attrs.values()))))
		conn.commit()

class ReadStatus(IntEnum):
	NONE = auto()
	MULTIPLOT = auto()
	SINGLEPLOT = auto()
	TABULAR = auto()
	MATRIX = auto()
	MACRO = auto()
	ERASE = auto() #! used for updating a document in-place by removing the old insertions (which is done until finding a newline)

keyword_to_status : t.Mapping[str, ReadStatus] = {
		"MULTIPLOT"  : ReadStatus.MULTIPLOT,
		"SINGLEPLOT" : ReadStatus.SINGLEPLOT,
		"TABULAR"    : ReadStatus.TABULAR,
		"MATRIX"     : ReadStatus.MATRIX,
		"DEFINE"     : ReadStatus.MACRO
		}

def apply_macros(sqlbuffer: str) -> str:
	match = re.search(r'\$(\w+)', sqlbuffer)
	while match:
		macroname = match.group(1)
		assert macroname in macros, 'macro not defined: "%s". used in the sql expression: %s' % (macroname, sqlbuffer)
		sqlbuffer = macros[macroname].apply(sqlbuffer)
		match = re.search(r'\\$(\w+)', sqlbuffer)
	return sqlbuffer

def multiplot(sqlbuffer : str, multiplot_columns : t.List[str]) -> t.Mapping[str, t.List[t.Tuple[str,str]]]:
	""" reads a MULTIPLOT statement and returns a dictionary mapping a MULTIPLOT instance to a list of coordinates """
	sqlbuffer = apply_macros(sqlbuffer)
	logging.info("macros-expanded SQL : " + sqlbuffer);

	""" if a column is is `a`.`b`, then we have to alias it to `a.b` """
	group_query = re.sub('MULTIPLOT', ','.join(map(lambda col: ".".join(map(lambda el: '"%s"' % el, col.split('.'))) + ' AS "%s"' % col, multiplot_columns)), sqlbuffer, 1)

	group_query = re.sub('MULTIPLOT', ','.join(map(lambda col: '"%s"' % col, multiplot_columns)), group_query)

	""" query for all possible values the variable MULTIPLOT can have """
	sqlexecute(group_query + ';')
	multiplot_value_tuples=set()
	# for row in cursor.fetchall():
	# 	multiplot_value_tuples.add(tuple(row[x] for x in multiplot_columns))

	multiplot_value_tuples = list(map(lambda row: tuple(row[x] for x in multiplot_columns), cursor.fetchall()))
	coordinates=dict()
	for multiplot_values in multiplot_value_tuples:
		#! this is a heuristic: we assume that if there is a where clause than this is for the outmost select command (and not for a subquery)
		if re.search(' where ', group_query, re.IGNORECASE):
			query = re.sub('(.*) where ', '\\1 WHERE %s AND ' %
					' AND '.join(map(lambda x: '"%s" = \'%s\'' % (x[0],x[1]), zip(multiplot_columns, multiplot_values)))
					, group_query, flags=re.IGNORECASE)
		else:
			query = re.sub('(.*) group by ', '\\1 WHERE %s GROUP BY ' %
					' AND '.join(map(lambda x: '"%s" = \'%s\'' % (x[0],x[1]), zip(multiplot_columns, multiplot_values)))
					, group_query, flags=re.IGNORECASE)
		sqlexecute(query + ';')
		rows = cursor.fetchall()
		#if(len(rows) > 0):
			# try:
			# 	list(map(lambda row: (float(row['x']), float(row['y'])), rows))
			# except ValueError:
			# 	die('Values of the MULTIPLOT tuple %s are not floats/not defined. SQL-Statement: %s ' % (str(multiplot_values),sqlbuffer) )
            #
		coordinates[multiplot_values] = list(map(lambda row: (row['x'], row['y']), rows))
	return coordinates

class Filetype(IntEnum):
	TEX = auto()
	PYTHON = auto()
	JS = auto()
	CSV = auto()
	GNUPLOT = auto()
	UNKNOWN = auto()

	def comment(self):
		if(self == Filetype.CSV):
			return '##'
		if(self == Filetype.PYTHON or self == Filetype.GNUPLOT):
			return '##'
		if(self == Filetype.JS):
			return '///'
		else:
			return '%%'

	@staticmethod
	def fromString(text: str) -> "Filetype":
		if(text == 'csv'):
			return Filetype.CSV
		if(text == 'tex'):
			return Filetype.TEX
		if(text == 'csv'):
			return Filetype.JS
		if(text == 'py'):
			return Filetype.PYTHON
		if(text == 'plt' or text == 'gnuplot'):
			return Filetype.GNUPLOT
		return Filetype.UNKNOWN

## MAIN
color_entries = dict()
try:
	from ast import literal_eval
	with open('pgf_color_entries.txt','r') as txtfile:
		for line in txtfile.readlines():
			if line.startswith('#'):
				continue
			cols = line.split("\t")
			assert len(cols) == 2, "Invalid Line : " + line
			if len(cols) == 2:
				try:
					color_entries[literal_eval(cols[0])] = int(cols[1])
					""" we use literal_eval to deserialize a tuple as keys are tuples """
				except ValueError:
					print('could not parse the line `%s` in pgf_color_entries.txt' % line, file=sys.stderr)
					sys.exit(1)

except IOError:
	print('file pgf_color_entries.txt does not exist -> will create it.', file=sys.stderr)

def sqlexecute(sqlcommand: str):
	try:
		logging.debug("SQL query: " + sqlbuffer);
		cursor.execute(sqlcommand)
	except sqlite3.Error as e:
		print("Error while executing the SQL statement: ", sqlcommand, file=sys.stderr)
		raise e

class Macro:
	name : str
	arguments : t.List[str]
	body : str

	def __init__(self, name: str, arguments: t.List[str], body: str):
		self.name = name
		self.arguments = arguments
		self.body = body

	def apply(self, s: str) -> str:
		""" applies the macro with a given list of parameters """
		regex = r'\$' + self.name + r'\s*\(([^)]+)\)'
		match = re.search(regex, s)
		while match:
			parameters = match.group(1).split(',')
			assert len(parameters) == len(self.arguments), "length of arguments and parameters for macro %s mismatch: " % (self.name, parameters)
			body = self.body
			for rule in zip(self.arguments, parameters):
				body = body.replace('$' + rule[0], rule[1])
			s = re.sub(regex, body, s, 1)
			match = re.search(regex, s)
		return s

""" writes the output of MULTIPLOT or SINGLEPLOT, where coordinates is a dict mapping an entryname to a list of coordinates. Adds to `previous_entries` the number of written entries """
def plot_coordinates(sqlbuffer: str,
		outfilename: str,
		coordinates: t.Mapping[str, t.List[t.Tuple[str,str]]],
		outfile: t.IO,
		outfiletype: Filetype,
		previous_entries: int) -> int:
	entrynames = list(coordinates.keys())
	entrynames.sort()
	sqlbuffer = sqlbuffer.replace('\n', ' ')

	if outfiletype == Filetype.PYTHON:
		pprint.pprint(coordinates, outfile)
	elif outfiletype == Filetype.GNUPLOT:
		if outfilename not in gnuplot_line_index:
			gnuplot_line_index[outfilename] = 0
		print('# ' + sqlbuffer, file=outfile)
		print('', file=outfile)
		for entry_id in range(len(entrynames)):
			entryname = entrynames[entry_id]
			print('#index %d with parameter %s' % (gnuplot_line_index[outfilename], entryname[0] if len(entryname) == 1 else str(entryname).replace(',',';')), file=outfile)
			for coordinate in coordinates[entryname]:
				print('%s\t%s' % (coordinate[0], coordinate[1]), file=outfile)
			""" gnuplot needs two newlines for marking the values of the next entry """
			print('', file=outfile)
			print('', file=outfile)
			gnuplot_line_index[outfilename] += 1

		print('# plot \\', file=outfile)
		for entry_id in range(len(entrynames)):
			entryname = entrynames[entry_id]
			index = gnuplot_line_index[outfilename] - len(entrynames) + entry_id
			title = entryname[0] if len(entryname) == 1 else str(entryname).replace(',',';')
			print('# \'%s\' index %d title "%s" with linespoints ls %d, \\' % (outfilename, index, title, index+1), file=outfile)
		print('# ', file=outfile)
		print('\n', file=outfile)

	elif outfiletype == Filetype.CSV:
		print('title,x,y', file=outfile)
		for entry_id in range(len(entrynames)):
			entryname = entrynames[entry_id]
			for coordinate in coordinates[entryname]:
				print('%s,%f,%f' % (entryname[0] if len(entryname) == 1 else str(entryname).replace(',',';'), coordinate[0], coordinate[1]), file=outfile)
	elif outfiletype == Filetype.JS:
		jsonoutput=dict()
		jsonoutput['query'] = sqlbuffer
		j=[]
		for entry_id in range(len(entrynames)):
			entryname = entrynames[entry_id]
			for coordinate in coordinates[entryname]:
				entry = dict()
				entry['name'] = entryname
				entry['x'] = coordinate[0]
				entry['y'] = coordinate[1]
				j.append(entry)
		jsonoutput['result'] = j
		json.dump(jsonoutput, outfile, indent=1)
	else: # default: latex
		if outfilename != 'stdout':
			print('% ' + sqlbuffer, file=outfile)

		for entry_id in range(len(entrynames)):
			entry = entrynames[entry_id]
			if not 'colorcache' in config_args or config_args['colorcache'] != 'none':
				if entry not in color_entries:
					color_entries[entry] = len(color_entries)+1
				shift = color_entries[entry]-(entry_id+previous_entries)
				print('\\pgfplotsset{cycle list shift=%d} %% %s' % (shift, str(color_entries[entry])), file=outfile)
			print('\\addplot coordinates{%s};' % ' '.join(map(lambda coord: '(%s, %s)' % (coord[0], coord[1]), coordinates[entry])), file=outfile)
			print('\\addlegendentry{%s};' % (str(entry) if len(entry) > 1 else entry[0]), file=outfile)
		previous_entries = previous_entries + len(entrynames) # number of previous entries -> needed for a subsequent plot call to determine the cycle list correctly
	return previous_entries

def print_tablentry(entry: t.Any) -> str:
	if entry == None:
		return 'NONE'
	typ = make_sqltype(entry)
	if typ == sqltype.INTEGER or typ == sqltype.REAL:
		return "\\num{%s}" % entry
	return str(entry)

if __name__ == "__main__":

	databasename=':memory:'
	loging_level_parameter='warning'
	filename=''
	filetype = Filetype.TEX

	try:
		opts, args = getopt.getopt(sys.argv[1:],"D:l:i:",["database=","log="])
	except getopt.GetoptError:
		print (sys.argv[0] + ' -D <databasename> -l <logginglevel> -i <infile>')
		sys.exit(2)
	for opt, arg in opts:
		if opt in ('-D', '--database'):
			databasename = arg
		elif opt in ('-l', '--log'):
			loging_level_parameter = arg
		elif opt in ('-i', '--infile'):
			filename = arg
		else:
			assert False, "unhandled option: %s" % arg
	if filename == '':
		assert False, "need at least the inputfile (-i) as parameter"

	logging_level = getattr(logging, loging_level_parameter.upper(), None)
	if not isinstance(logging_level, int):
		raise ValueError('Invalid log level: %s' % loging_level_parameter)
	logging.basicConfig(level=logging_level)

	readstatus = ReadStatus.NONE
	sqlbuffer = ''

	assert os.access(filename, os.R_OK), 'cannot read file %s' % filename
	filetype = Filetype.fromString(os.path.splitext(filename)[1][1:])
	if filetype == Filetype.UNKNOWN:
		die("unknown file type of file %s" % filename)

	conn = sqlite3.connect(databasename)
	if logging_level <= logging.DEBUG:
		sqlite3.enable_callback_tracebacks(True)
		conn.set_trace_callback(print)
	conn.row_factory = sqlite3.Row
	conn.create_function("pow", 2, lambda base,exp: math.pow(base, exp))
	conn.create_function("log", 2, lambda base,x: math.log(x, base))
	conn.create_function("basename", 1, lambda filepath: os.path.basename(filepath))
	cursor = conn.cursor()

	config_args : t.Mapping[str,str] = dict()
	outfile = sys.stdout
	outfilename = None
	outfiletype = Filetype.TEX
	previous_entries = -1

	""" mapping names to macros """
	macros : t.Mapping[str, Macro] = dict()

	""" storing the last index of the written gnuplot data for each file """
	gnuplot_line_index : t.Dict[str, int] = dict()

	with open(filename) as texfile:
		for texLine in texfile.readlines():
			if readstatus == ReadStatus.MACRO:
				if texLine.startswith(filetype.comment()):
					print(texLine, end='')
					sqlbuffer+=' ' + texLine[len(filetype.comment()):].rstrip()
					continue
				readstatus = ReadStatus.NONE
				match = re.match(r'\s*DEFINE\s+(\w+)\s*\(([^)]+)\)\s*(.*)', sqlbuffer)
				assert match, "no valid MACRO: " + sqlbuffer
				name = match.group(1)
				arguments = list(map(lambda x: x.strip(), match.group(2).split(',')))
				body = match.group(3)
				for argument in arguments:
					assert body.find('$' + argument) != -1, "argument %s not found in body: %s" % (argument, body)
				macros[name] = Macro(name, arguments, body)

			if readstatus in [ReadStatus.MULTIPLOT, ReadStatus.TABULAR, ReadStatus.SINGLEPLOT, ReadStatus.MATRIX]:
				if texLine.startswith(filetype.comment()):
					print(texLine, end='')
					if texLine.startswith('%s CONFIG' % filetype.comment()):
						config_args = split_keyvalueline(texLine[len('%s CONFIG' % filetype.comment()):])
					else:
						sqlbuffer+=' ' + texLine[len(filetype.comment()):].rstrip()
					continue
				else:
					if readstatus in [ReadStatus.MULTIPLOT, ReadStatus.SINGLEPLOT]:
						outfiletype = filetype
						""" if mode=a we use the previous_entries for the cycle list """
						if not 'mode' in config_args or config_args['mode'].find('a') == -1:
							previous_entries = 0
						if 'type' in config_args:
							outfiletype = Filetype.fromString(config_args['type'])
						if 'file' in config_args:
							if outfiletype == Filetype.GNUPLOT:
								assert ('mode' in config_args and config_args['mode'].find('a') != -1) or config_args['file'] not in gnuplot_line_index, 'overwriting a .dat file created within this execution without append mode is prohibited'

							os.makedirs(os.path.dirname(config_args['file']), exist_ok=True)
							outfile = open(config_args['file'], 'w' if not 'mode' in config_args else config_args['mode'])
							if outfiletype == Filetype.TEX:
								print('\\input{%s}' % config_args['file'])
							elif outfiletype == Filetype.PYTHON:
								print('# read comments in file %s for the plot command' % config_args['file'])

						else:
							outfile = sys.stdout
							assert outfiletype != Filetype.GNUPLOT, "need CONFIG file={outfile} parameter to know where to write the data"
						# try:
						# 	previous_entries
						# except NameError:
						if previous_entries == -1:
							die('mode is set to append, but there is no previous content!')

					if readstatus == ReadStatus.TABULAR:
						readstatus = ReadStatus.ERASE
						sqlbuffer = apply_macros(sqlbuffer[sqlbuffer.find('TABULAR')+len('TABULAR'):])
						sqlexecute(sqlbuffer + ';')

						if 'file' in config_args:
							outfile = open(config_args['file'], 'w' if not 'mode' in config_args else config_args['mode'])
							print('\\input{%s}' % config_args['file'])
						else:
							outfile = sys.stdout

						for row in cursor.fetchall():
							print(" & ".join(map(print_tablentry, row)) + ' \\\\', file=outfile)
					elif readstatus == ReadStatus.SINGLEPLOT:
						readstatus = ReadStatus.ERASE
						match = re.match(r'\s*SINGLEPLOT\(([^)]+)\)', sqlbuffer)
						assert match, "no singleplot argument given: " + sqlbuffer
						singleplot_name = match.group(1)
						sqlbuffer = sqlbuffer[match.span()[1]:] #remove 'MULTIPLOT(...) directive
						sqlexecute(sqlbuffer + ';')
						rows = cursor.fetchall()
						coordinates=dict()
						coordinates[(singleplot_name,)] = list(map(lambda row: (row['x'], row['y']), rows))
						previous_entries = plot_coordinates(sqlbuffer, config_args['file'] if 'file' in config_args else 'stdout', coordinates, outfile, outfiletype, previous_entries)
					elif readstatus == ReadStatus.MATRIX:
						readstatus = ReadStatus.ERASE
						sqlbuffer = apply_macros(sqlbuffer[sqlbuffer.find('MATRIX')+len('MATRIX'):])
						sqlexecute(sqlbuffer + ';')

						if 'file' in config_args:
							outfile = open(config_args['file'], 'w' if not 'mode' in config_args else config_args['mode'])
							print('\\input{%s}' % config_args['file'])
						else:
							outfile = sys.stdout

						column_names=set()
						row_names=set()
						matrix=dict()
						for row in cursor.fetchall():
							print(row)
							column_names.add(row['x'])
							row_names.add(row['y'])
							matrix[(row['x'], row['y'])] = row['val']
						print(" & ".join(map(str, column_names)) + ' \\\\', file=outfile)
						for row in row_names:
							print(row + " & " + " & ".join(map(print_tablentry, map(lambda x: matrix[(x, row)], column_names))) + ' \\\\', file=outfile)
					else:
						assert readstatus == ReadStatus.MULTIPLOT
						readstatus = ReadStatus.ERASE
						match = re.match(r'\s*MULTIPLOT\(([^)]+)\)', sqlbuffer)
						assert match, "no multiplot argument given: " + sqlbuffer
						multiplot_columns = match.group(1)
						sqlbuffer_rest = sqlbuffer[match.span()[1]:] #remove 'MULTIPLOT(...) directive
						coordinates = multiplot(sqlbuffer_rest, list(map(lambda col: col.strip(), multiplot_columns.split(','))))
						previous_entries = plot_coordinates(sqlbuffer, config_args['file'] if 'file' in config_args else 'stdout', coordinates, outfile, outfiletype, previous_entries)
					#cleanup
					if 'file' in config_args:
						outfile.close()
					config_args=dict()

			if readstatus == ReadStatus.ERASE:
				if len(texLine.strip()) == 0 or texLine.startswith(filetype.comment()):
					readstatus = ReadStatus.NONE
				else:
					continue

			#! check for a multiline command stored in keyword_to_status
			for key in keyword_to_status:
				if texLine.startswith('%s %s' % (filetype.comment(), key) ):
					config_args=dict()
					sqlbuffer = texLine[len(filetype.comment()):].rstrip()
					readstatus = keyword_to_status[key]
					break

			if texLine.startswith('%s UNDEF ' % filetype.comment()):
				sqlbuffer = texLine[len(filetype.comment()):].strip()
				match = re.match(r'UNDEF\s+(\w+)\s*', sqlbuffer)
				assert match, 'invalid UNDEF syntax : ' + sqlbuffer
				name = match.group(1).strip()
				assert name in macros, 'cannot UNDEF undefined macro: ' + name
				del macros[name]

			#! read a log file with '^RESULT .*' statements into a sql table
			if texLine.startswith('%s IMPORT-DATA ' % filetype.comment()):
				match = re.match('%s IMPORT-DATA ([^ ]+) (.+)' % filetype.comment(), texLine)
				assert match, 'invalid texLine ' + texLine
				create_table(match.group(1), match.group(2))

			#! read a list of JSON log statements into a sql table
			if texLine.startswith('%s IMPORT-JSON-DATA ' % filetype.comment()):
				match = re.match('%s IMPORT-JSON-DATA ([^ ]+) (.+)' % filetype.comment(), texLine)
				assert match, 'invalid texLine ' + texLine
				create_json_table(match.group(1), match.group(2))

			print(texLine, end='')

	conn.close()

	if filetype == Filetype.TEX:
		with open('pgf_color_entries.txt','w') as txtfile:
			print('# this file is automatically created by sqlplot.py to ensure the same legend symbol for each entry in all plots generated by sqlplot.py', file=txtfile)
			for key in color_entries:
				txtfile.write('%s\t%d\n' % (key, color_entries[key]))

# vim: ts=2


from enum import IntEnum
from itertools import takewhile
import datetime

class Part(IntEnum):
    X = 1
    A = 2
    B = 3
    C = 4
    D = 5

    def max_num(self):
        if self == Part.X:
            return 11
        else:
            return 4

    def to_x_num(self):
        if (self == Part.X):
            raise ValueError('Not supported for X.')
        return 2 * self - 1

    def to_x_pos(self):
        return Pos.build(Part.X, self.to_x_num())

    def all_positions_asc(self):
        if self == Part.A:
            return [Pos.A1, Pos.A2, Pos.A3, Pos.A4]
        if self == Part.B:
            return [Pos.B1, Pos.B2, Pos.B3, Pos.B4]
        if self == Part.C:
            return [Pos.C1, Pos.C2, Pos.C3, Pos.C4]
        if self == Part.D:
            return [Pos.D1, Pos.D2, Pos.D3, Pos.D4]

        return [Pos.X1, Pos.X2, Pos.X3, Pos.X4, Pos.X5, Pos.X6, Pos.X7, Pos.X8, Pos.X9, Pos.X10, Pos.X11]

    def to_path(self, start, end, include_start):
        start_excluded = start - 1 if include_start else start
        if start_excluded == end:
            return []
        nums = reversed(range(end, start_excluded, -1 if start_excluded < end else 1))
        return list(map(lambda n: Pos.build(self, n), nums))

    def multiplier(self):
        return [0, 1, 10, 100, 1000][self - 1]

    def __repr__(self):
        return self.name

class Pos(IntEnum):
    X1 = 1
    X2 = 2
    X3 = 3 # Does this position even matter?
    X4 = 4
    X5 = 5 # Does this position even matter?
    X6 = 6
    X7 = 7 # Does this position even matter?
    X8 = 8
    X9 = 9 # Does this position even matter?
    X10 = 10
    X11 = 11
    A1 = 21
    A2 = 22
    A3 = 23
    A4 = 24
    B1 = 31
    B2 = 32
    B3 = 33
    B4 = 34
    C1 = 41
    C2 = 42
    C3 = 43
    C4 = 44
    D1 = 51
    D2 = 52
    D3 = 53
    D4 = 54

    def __repr__(self):
        return self.name

    def num(self):
        enum_int = int(self)
        if enum_int >= 20:
            return enum_int % 10
        else:
            return enum_int

    def part(self):
        divide = int(int(self) / 10)
        if divide == 0:
            return Part(1)
        else:
            return Part(divide)

    def dist(self, pos2):
        part1 = self.part()
        part2 = pos2.part()
        num1 = self.num()
        num2 = pos2.num()

        if part1 == part2:
            return abs(num1 - num2)
        if part1 != Part.X and part2 != Part.X:
            corridor = 2 * abs(part1 - part2)
            dist_from_corr_1 = 5 - num1
            dist_from_corr_2 = 5 - num2
            return corridor + dist_from_corr_1 + dist_from_corr_2
        if part1 == Part.X:
            dist_from_corr = 5 - num2
            dist_to_room = abs(num1 - part2.to_x_num())
            return dist_from_corr + dist_to_room
        dist_from_corr = 5 - num1
        dist_to_room = abs(num2 - part1.to_x_num())
        return dist_from_corr + dist_to_room

    @classmethod
    def build(cls, part: Part, num):
        int_part = int(part)
        if int_part == 1:
            return Pos(num)
        else:
            return Pos(int_part * 10 + num)

class Pawn:
    def __init__(self, start_pos: Pos, dest_part: Part):
        self.start_pos = start_pos
        self.curr_pos = start_pos
        self.dest_part = dest_part
        self.total_dist = 0
        self.is_finished_cached = False

    def copy_pawn(self):
        new_pawn = Pawn(self.start_pos, self.dest_part)
        new_pawn.curr_pos = self.curr_pos
        new_pawn.total_dist = self.total_dist
        new_pawn.is_finished_cached = self.is_finished_cached
        return new_pawn

    def num(self):
        return self.curr_pos.num()

    def didnt_move(self):
        return self.moves == 0

    def corridor_entry_pos(self):
        start_part = self.start_pos.part()
        corr_pos = start_part.to_x_num()
        return Pos.build(Part.X, corr_pos)

    def move_to(self, pos: Pos):
        old_pos = self.curr_pos
        self.curr_pos = pos
        self.total_dist += old_pos.dist(pos)

    def curr_part(self):
        return self.curr_pos.part()

    def __repr__(self):
        return "Pawn at %s, dest = %s" % (self.curr_pos.name, self.dest_part)

class Board:
    def __init__(self, pawns):
        self.pawns: list[Pawn] = pawns
        self.path_dict = {}
        self.occupied_dict = {}
        self.pawn_dict = {}
        self.finish_pos_dict = {}
        self.moves = []
        self.occupied = [[False] * 11, [False] * 4, [False] * 4, [False] * 4, [False] * 4]
        for pawn in self.pawns:
            part = pawn.curr_part()
            num = pawn.num()
            self.occupied[part - 1][num - 1] = True

    def is_occupied(self, pos: Pos):
        return self.is_occupied_impl2(pos)

    def is_occupied_impl1(self, pos: Pos):
        occupied_value = self.occupied_dict.get(pos)
        if occupied_value != None:
            return occupied_value

        is_occupied = pos in map(lambda p: p.curr_pos, self.pawns)
        self.occupied_dict[pos] = is_occupied
        return is_occupied

    def is_occupied_impl2(self, pos: Pos):
        part = pos.part()
        num = pos.num()
        return self.occupied[part - 1][num - 1]

    def path_free(self, part: Part, start: int, end: int, start_included):
        real_start = start if start_included else start + 1
        dict_value = self.get_from_dict(part, real_start, end)

        if dict_value != None:
            return dict_value

        path = part.to_path(start, end, start_included)
        for pos in path:
            if self.is_occupied(pos):
                self.store_in_dict(part, real_start, end, False)
                return False

        self.store_in_dict(part, real_start, end, False)
        return True

    def store_in_dict(self, part: Part, real_start: int, end: int, result: bool):
        if real_start < end:
            self.path_dict[(part, real_start, end)] = result
        else:
            self.path_dict[(part, end, real_start)] = result

    def get_from_dict(self, part: Part, real_start: int, end: int):
        if real_start < end:
            return self.path_dict.get((part, real_start, end))
        else:
            return self.path_dict.get((part, end, real_start))

    def is_allowed(self, pos: Pos):
        return not pos in [Pos.X3, Pos.X5, Pos.X7, Pos.X9]

    def pawn_at(self, pos: Pos):
        if pos in self.pawn_dict:
            return self.pawn_dict[pos]

        pawn = next((p for p in self.pawns if p.curr_pos == pos), None)
        self.pawn_dict[pos] = pawn
        return pawn

    def is_finished(self, pawn: Pawn):
        if pawn.is_finished_cached:
            return True

        curr_pos = pawn.curr_pos
        curr_part = curr_pos.part()
        if curr_pos.part() == pawn.dest_part:
            nums_lower = range(1, pawn.num())

            nums_lower = range(1, curr_pos.num())
            for num in nums_lower:
                pawn_lower = self.pawn_at(Pos.build(curr_part, num))
                if pawn_lower == None or pawn_lower.dest_part != curr_part:
                    return False

            pawn.is_finished_cached = True
            return True

        return False

    def finish_pos(self, part: Part):
        if part in self.finish_pos_dict:
            return self.finish_pos_dict[part]

        all_positions_desc = list(reversed(part.all_positions_asc()))
        all_pawns = list(map(lambda p: self.pawn_at(p), all_positions_desc))

        all_open = list(takewhile(lambda p: p == None, all_pawns))
        all_open_len = len(all_open)

        if all_open_len > 0 and (all_open_len == 4 or self.is_finished(all_pawns[all_open_len])):
            finish = all_positions_desc[all_open_len - 1]
            self.finish_pos_dict[part] = finish
            return finish

        self.finish_pos_dict[part] = None
        return None

    def next_positions(self, pawn: Pawn):
        if self.is_finished(pawn):
            return []

        finish_pos = self.finish_pos(pawn.dest_part)
        if finish_pos != None and self.can_reach(pawn.curr_pos, finish_pos):
            return [finish_pos]
        else:
            if pawn.curr_part() == Part.X:
                return [] # Pawn is already at X and cannot finish

        x_entry_pos = pawn.curr_part().to_x_pos()
        if self.can_reach(pawn.curr_pos, x_entry_pos):
            accessible_xs = self.accessible_in_x_from_num(x_entry_pos.num())
            allowed_xs = list(filter(lambda p: self.is_allowed(p), accessible_xs))
            return allowed_xs
        return []

    def can_reach(self, start: Pos, end: Pos):
        start_part = start.part()
        end_part = end.part()
        if start_part == end_part:
            return self.path_free(start_part, start.num(), end.num(), False)

        if end_part == Part.X:
            return self.path_free(start_part, start.num(), 4, False) and \
                self.path_free(Part.X, start_part.to_x_num(), end.num(), False)

        if start_part == Part.X:
            return self.path_free(Part.X, start.num(), end_part.to_x_num(), False) and \
                self.path_free(end_part, 4, end.num(), True)

        return self.path_free(start_part, start.num(), 4, False) and \
            self.path_free(Part.X, start_part.to_x_num(), end_part.to_x_num(), False) and \
            self.path_free(end_part, 4, end.num(), True)

    def accessible_in_x(self, curr_pos: Pos):
        num = curr_pos.num()
        part = curr_pos.part()
        if part == Part.X:
            return self.accessible_in_x_from_num(num)
        route_to_x = part.to_path(num, 4, False)
        if all(lambda p: not self.is_occupied(p), route_to_x):
            entry_x_num = part.to_x_num()
            return self.accessible_in_x_from_num(entry_x_num)
        return []

    def accessible_in_x_from_num(self, x_num):
        lower = Part.X.to_path(x_num, 1, False)
        higher = Part.X.to_path(x_num, 11, False)
        lower_free = list(reversed(list(takewhile(lambda p: not self.is_occupied(p), lower))))
        higher_free = list(takewhile(lambda p: not self.is_occupied(p), higher))
        return lower_free + higher_free

    def move_new_board(self, start: Pos, end: Pos):
        new_pawns = list(map(lambda p: p.copy_pawn(), self.pawns))
        pawn = next(filter(lambda p: p.curr_pos == start, new_pawns), None)
        pawn.move_to(end)
        new_board = Board(new_pawns)
        existing_moves = self.moves.copy()
        existing_moves.append(f"({pawn}) moved {start.name} âž¡ {end.name}")
        new_moves = existing_moves
        new_board.moves = new_moves
        return new_board

    # Good that this does not use pawn_at, because that uses cached results
    # and can be outdated after a move
    def pawn_char(self, pos: Pos):
        result = next(filter(lambda p: p.curr_pos == pos, self.pawns), None)
        return " " if result == None else result.dest_part.name

    def print_board(self):
        print()
        print("#############")
        xs_chars = ''.join(list(map(lambda p: self.pawn_char(p), Part.X.all_positions_asc())))
        print("#" + xs_chars + "#")
        print("###" + self.pawn_char(Pos.A4) + "#" + self.pawn_char(Pos.B4) + "#" \
              + self.pawn_char(Pos.C4) + "#" + self.pawn_char(Pos.D4) + "###")
        print("  #" + self.pawn_char(Pos.A3) + "#" + self.pawn_char(Pos.B3) + "#" \
              + self.pawn_char(Pos.C3) + "#" + self.pawn_char(Pos.D3) + "#  ")
        print("  #" + self.pawn_char(Pos.A2) + "#" + self.pawn_char(Pos.B2) + "#" \
              + self.pawn_char(Pos.C2) + "#" + self.pawn_char(Pos.D2) + "#  ")
        print("  #" + self.pawn_char(Pos.A1) + "#" + self.pawn_char(Pos.B1) + "#" \
              + self.pawn_char(Pos.C1) + "#" + self.pawn_char(Pos.D1) + "#  ")
        print("  #########  ")
        print()

    def all_moves(self):
        moves = []
        for pawn in self.pawns:
            next_for_pawn = self.next_positions(pawn)
            moves_for_pawn = list(map(lambda p: Move(pawn.curr_pos, p), next_for_pawn))
            moves.extend(moves_for_pawn)

        return moves

    def end_reached(self):
        for part in [Part.A, Part.B, Part.C, Part.D]:
            for pos in part.all_positions_asc():
                pawn_on_pos = self.pawn_at(pos)
                if pawn_on_pos == None or pawn_on_pos.dest_part != part:
                    return False

        return True

    def calc_score(self):
        sum = 0
        for pawn in self.pawns:
            sum += pawn.total_dist * pawn.dest_part.multiplier()

        return sum

    def __repr__(self):
        return f"Board with {len(self.moves)} moves"

class Move:
    def __init__(self, start: Pos, end: Pos):
        self.start = start
        self.end = end

    def apply_move(self, board: Board):
        return board.move_new_board(self.start, self.end)

    def __repr__(self):
        return "Move %s âž¡ %s" % (self.start.name, self.end.name)

pawns_init_part_2 = [
    Pawn(Pos.A4, Part.B), Pawn(Pos.B4, Part.C), Pawn(Pos.C4, Part.A), Pawn(Pos.D4, Part.D),
    Pawn(Pos.A3, Part.D), Pawn(Pos.B3, Part.C), Pawn(Pos.C3, Part.B), Pawn(Pos.D3, Part.A),
    Pawn(Pos.A2, Part.D), Pawn(Pos.B2, Part.B), Pawn(Pos.C2, Part.A), Pawn(Pos.D2, Part.C),
    Pawn(Pos.A1, Part.B), Pawn(Pos.B1, Part.C), Pawn(Pos.C1, Part.D), Pawn(Pos.D1, Part.A)]

pawns_init_part_1 = [
    Pawn(Pos.A4, Part.B), Pawn(Pos.B4, Part.C), Pawn(Pos.C4, Part.A), Pawn(Pos.D4, Part.D),
    Pawn(Pos.A3, Part.B), Pawn(Pos.B3, Part.C), Pawn(Pos.C3, Part.D), Pawn(Pos.D3, Part.A),
    Pawn(Pos.A2, Part.A), Pawn(Pos.B2, Part.B), Pawn(Pos.C2, Part.C), Pawn(Pos.D2, Part.D),
    Pawn(Pos.A1, Part.A), Pawn(Pos.B1, Part.B), Pawn(Pos.C1, Part.C), Pawn(Pos.D1, Part.D)]

pawns_init_experiment = [
    Pawn(Pos.A4, Part.B), Pawn(Pos.B4, Part.A), Pawn(Pos.C4, Part.C), Pawn(Pos.D4, Part.D),
    Pawn(Pos.A3, Part.A), Pawn(Pos.B3, Part.B), Pawn(Pos.C3, Part.C), Pawn(Pos.D3, Part.D),
    Pawn(Pos.A2, Part.A), Pawn(Pos.B2, Part.B), Pawn(Pos.C2, Part.C), Pawn(Pos.D2, Part.D),
    Pawn(Pos.A1, Part.A), Pawn(Pos.B1, Part.B), Pawn(Pos.C1, Part.C), Pawn(Pos.D1, Part.D)]

lowest_score = 1000000
cycle = 0
move_to_test = 1
winning_moves = []

def check_moves(board_start: Board):
    global cycle
    global move_to_test
    global lowest_score
    global winning_moves

    print("Checking boards started")

    boards_to_check = [board_start]

    while len(boards_to_check) > 0:
        curr_board = boards_to_check.pop(0)
        moves = curr_board.all_moves()

        if len(moves) > 0:
            boards_to_insert = []
            for move in moves:
                new_board = move.apply_move(curr_board)
                boards_to_insert.append(new_board)
            for b in boards_to_insert:
                boards_to_check.insert(0, b)

            cycle += 1
            if cycle % 20000 == 0:
                time_format = "%H:%M:%S"
                print(f"> cycle {cycle}, time: {datetime.datetime.now().strftime(time_format)}, boards active: {len(boards_to_check)}")
        else:
            if curr_board.end_reached():
                score = curr_board.calc_score()
                if score < lowest_score:
                    lowest_score = score
                    winning_moves = curr_board.moves.copy()
                    print(f"Lowest score is now {lowest_score}")

check_moves(Board(pawns_init_part_2))

print("-- All options checked --")
print(f"Lowest score = {lowest_score}")

for move in winning_moves:
    print(">  " + move)

# 166 too low
# 42752 too low
# 42732 too low (ðŸ˜„)
# In total 2.280.000 cycles