import pandas as pd
pd.options.mode.chained_assignment = None  # default='warn'
import os
# from osemosys_global.configuration import ConfigFile, ConfigPaths
from configuration import ConfigFile, ConfigPaths
from utils import apply_dtypes
import logging
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)

# CONFIGURATION PARAMETERS

config_paths = ConfigPaths()
config = ConfigFile('config')

input_dir = config_paths.input_dir
input_data_dir = config_paths.input_data_dir
output_dir = config_paths.output_dir
output_data_dir = config_paths.output_data_dir

# ### Import data files and user input

## Data for variable costs of fuels taken from World Bank Commodity Market Outlooks:
##    https://www.worldbank.org/en/research/commodity-markets
## Download the 'Charts and Data' zip file and extract the forecasts file (CMO-April-2020-forecasts.xlsx).
## Adjust filename below for forecasts done at a different date.

# Read in World Bank Commodity Price Outlook - we only want rows 87 - 91
# using 85 as the headers (years) and skipping the energy header...

#### REPLACE FROM BELOW ONCE FIGURED OUT...df_prices = pd.read_excel(
df_prices = pd.read_excel(
    os.path.join(input_data_dir,
    "CMO-April-2020-forecasts.xlsx"), header=1, skiprows=83, nrows=6
)

# Read in Technologies
df_techs = pd.read_csv(os.path.join(output_data_dir,'TECHNOLOGY.csv'))
df_trn_techs = df_techs.copy()
years = config.get_years()

region_name = config.region_name
emissions = []

# ### Filter technologies to keep only fuel production technologies (MIN)

df_techs = df_techs[df_techs.VALUE.str.contains('MIN')]

df_techs['REGION'] = region_name
df_techs['MODE_OF_OPERATION'] = 1
df_techs_temp = df_techs.copy()
df_techs_temp['MODE_OF_OPERATION'] = 2
df_techs = pd.concat([df_techs,df_techs_temp])
df_techs.rename(columns={'VALUE':'TECHNOLOGY'}, inplace=True)

df_techs['YEAR'] = [range(years[0], years[-1] + 1)] * len(df_techs)

df_techs = df_techs.explode('YEAR')

df_techs.reset_index(drop=True, inplace=True)

# print(df_techs)

# ### Cleanup prices from CMO data

df_prices = df_prices.drop([0], axis=0)
df_prices = df_prices.drop(["Commodity"], axis=1)
columns = df_prices.columns.values
columns[0] = "YEAR"
df_prices = df_prices.loc[:, ~df_prices.columns.str.contains('^Unnamed', na=False)]

df_prices = df_prices.transpose()

# use commodity key as header
new_header = df_prices.iloc[0] #grab the first row for the header
df_prices = df_prices[1:] #take the data less the header row
new_header[1] = 'MINCOA'  # This was KFCOAL_AUS  KFCRUDE_PETRO  KFNGAS_EUR
new_header[2] = 'MINOIL'  # This was KFCRUDE_PETRO
new_header[3] = 'MINGAS'  # This was KFNGAS_EUR
df_prices.columns = new_header #set the header row as the df header

# drop units as we're doing $/PJ
df_prices = df_prices.drop("Unit", axis = 0)

# And convert to $/PJ
# Values taken from kylesconverter.com:
#  1 MT coal contains 29.31 PJ (1,000,000 tonnes coal) Original was $/mt ($/tonne I think).  We want $mill/PJ so divide by 29.31
#  1 MMBtu = 0.000001055056 PJ Original was MMBtu and we want $mill/pJ, so divide by 1.055056.
#  1 bbl = 0.00000612 PJ (Barrels of Oil) Original was $/bbl so divide by 0.00000612 and multiply by 1000000
# NOT ENTIRELY SURE I'M CALCULATING THE UNITS CORRECTLY (NOT SURE WHAT ORIGINAL UNITS WERE AS IT'S NOT STATED ANYWHERE)

# ORIGINAL UNITS:
#       KFCOAL_AUS KFCRUDE_PETRO KFNGAS_EUR KFNGAS_US KFNGAS_JP
#Unit       $/mt         $/bbl    $/mmbtu   $/mmbtu   $/mmbtu

df_prices['MINCOA'] = df_prices['MINCOA'] / 29.31
df_prices['MINOIL'] = df_prices['MINOIL'] / 0.00000612 / 1000000
df_prices['MINGAS'] = df_prices['MINGAS'] / 1.055056
df_prices['KFNGAS_US'] = df_prices['KFNGAS_US'] / 1.055056
df_prices['KFNGAS_JP'] = df_prices['KFNGAS_JP'] / 1.055056

# print(df_prices)

# Add in other fuels that are the same as those above:
df_prices['MINCOG'] = df_prices['MINGAS']  # Cogen is powered by gas
df_prices['MINOTH'] = df_prices['MINOIL']  # Other petroleum products are similar to oil
df_prices['MINPET'] = df_prices['MINOIL']  # Petroleum products are similar to oil

# And add in international prices that are 15% higher than the regular ones:
df_prices['INTCOA'] = df_prices['MINCOA'] * 0.15
df_prices['INTOIL'] = df_prices['MINOIL'] * 0.15
df_prices['INTGAS'] = df_prices['MINGAS'] * 0.15
df_prices['INTCOG'] = df_prices['MINCOG'] * 0.15
df_prices['INTOTH'] = df_prices['MINOTH'] * 0.15
df_prices['INTPET'] = df_prices['MINPET'] * 0.15

df_prices = df_prices.reindex(years)

df_prices = df_prices.apply(pd.to_numeric)

df_prices = df_prices.interpolate()

col = df_prices.columns
df_prices = pd.melt(df_prices.reset_index(), id_vars='index', value_vars=col)

df_prices = df_prices.rename(columns={'index': 'YEAR', 'YEAR': 'TEMPTECH'})

# print(df_prices)

# ### Map costs to technologies by region/country

## Need to create: REGION,TECHNOLOGY,MODE_OF_OPERATION,YEAR,VALUE

# Setup TEMPTECH column for merge
df_techs['TEMPTECH'] = df_techs['TECHNOLOGY'].str[0:6]

# International costs are identified by the INT in MINCOAINT, so make these INTCOA temporarily
df_techs.loc[df_techs.TECHNOLOGY.str[6:9]=='INT', 'TEMPTECH'] = 'INT'+df_techs['TECHNOLOGY'].str[3:6]

df_varcost = pd.merge(df_techs, df_prices, on=['YEAR', 'TEMPTECH'])

df_varcost = df_varcost.rename(columns={'value': 'VALUE'})

df_varcost = df_varcost.drop(['TEMPTECH'], axis=1)

# print(df_varcost)

## AND THEN DROP ANY ITEMS THAT HAVE A NAN AS THESE ARE DEFAULT (0) VALUES
## BUT THIS IS ALREADY DONE FOR US BY THE MERGE
#df_techs.dropna(subset = ["VALUE"], inplace=True)
#print(df_techs)

# Get transmission variable costs

df_trn_techs = df_trn_techs.loc[
    (df_trn_techs['VALUE'].str.startswith('TRN')) &
    (df_trn_techs['VALUE'].str.len() == 13)] # keeps TRNxxxxxxxxxx techs

df_trn_varcosts = df_trn_techs.copy()
df_trn_varcosts = df_trn_varcosts.rename(columns={'VALUE':'TECHNOLOGY'})
df_trn_varcosts['REGION'] = region_name
df_trn_varcosts['YEAR'] = [range(years[0], years[-1] + 1)] * len(df_trn_varcosts)
df_trn_varcosts['MODE_OF_OPERATION'] = [[1,2] for x in range(len(df_trn_varcosts))]
df_trn_varcosts = df_trn_varcosts.explode('MODE_OF_OPERATION')
df_trn_varcosts = df_trn_varcosts.explode('YEAR')

# Hardcode in transmission variable cost parameter following PLEXOS of $4/MWh
# $4/MWh * 1Wh/3600J * 1000000000 MJ/1PJ * 1M$/$1000000
trn_varcost = 4 / 3.6

df_trn_varcosts['VALUE'] = round(trn_varcost, 4)

# Merge with mining variable costs
df_varcost = pd.concat([df_varcost, df_trn_varcosts])

# ### Write out variablecost.csv

df_varcosts_final = df_varcost[['REGION',
                       'TECHNOLOGY',
                       'MODE_OF_OPERATION',
                       'YEAR',
                       'VALUE']]

df_varcosts_final = apply_dtypes(df_varcosts_final, "VariableCost")
df_varcosts_final.to_csv(os.path.join(output_data_dir,'VariableCost.csv'), mode='w', header=True, index = None)

logging.info('Variable Costs Completed')


def Cal_Postfix(num, postfix):
  str_to_num = []
  stack = []
  result = 0

  for _ in range(num):
    str_to_num.append(int(input()))

  for i in postfix:
    if ord(i) >= 65 and ord(i) <= 90:
      stack.append(str_to_num[ord(i)-65])
    elif i == '*':
      tmp1 = stack.pop()
      tmp2 = stack.pop()
      stack.append(tmp1 * tmp2)
    elif i == '/':
      tmp1 = stack.pop()
      tmp2 = stack.pop()
      stack.append(tmp2 / tmp1)
    elif i == '+':
      tmp1 = stack.pop()
      tmp2 = stack.pop()
      stack.append(tmp1 + tmp2)
    elif i == '-':
      tmp1 = stack.pop()
      tmp2 = stack.pop()
      stack.append(tmp2 - tmp1)

  return stack.pop()

append_num = int(input())
pf_str = input()

print("{:.2f}".format(Cal_Postfix(append_num, pf_str)))


import typing

from pydantic import BaseModel

from stateapi.pkg.orm import builder, query, source, spec, insert, update, base, delete
from stateapi.logger import Logger

FieldValue = base.FieldValue

class TableSpecField(BaseModel):
    """
    字段的类型
    """

    name: str
    mode: str  # FieldType[mode]
    default: str = ""
    unique: bool = False
    index: bool = False
    null: bool = False

class TableSpec(BaseModel):
    """
    创建表时声明的类型
    """

    table_name: str
    fields: list[TableSpecField]
    default: list[list[FieldValue]] = []
    create: bool = True
    clean: bool = False

async def table_create(db: str, app: str, tablespec: TableSpec):
    try:
        # spec.save_spec(db, "{}_{}".format(app, tablespec.table_name), tablespec.dict())
        spec.save_spec(
            source.DefaultManager.db(db), tablespec.table_name, tablespec.dict()
        )
    except Exception as e:
        Logger().error(e)
        return str(e)

    fields: list[builder.Field] = []
    for item in tablespec.fields:
        if item.default != "":
            fields.append(
                builder.Field(
                    item.name,
                    base.FieldType[item.mode],
                    base.FieldType[item.mode].trans_value(item.default),
                    item.unique,
                    item.index,
                    item.null,
                )
            )
        else:
            fields.append(
                builder.Field(
                    item.name,
                    base.FieldType[item.mode],
                    base.FieldType[item.mode].get_default(),
                    item.unique,
                    item.index,
                    item.null,
                )
            )
    try:
        model, isnew = builder.build_model(
            # db, "{}_{}".format(app, tablespec.table_name), fields, create=True
            source.DefaultManager.db(db),
            tablespec.table_name,
            fields,
            create=tablespec.create,
            clean=tablespec.clean,
        )
        if isnew and len(tablespec.default) > 0:
            for record in tablespec.default:
                await table_insert(
                    db,
                    app,
                    tablespec.table_name,
                    TableSpecInsert(returns="id", fields=record),
                )

        return "ok"
    except Exception as e:
        Logger().error(e)
        return str(e)

class TableSpecInsert(BaseModel):
    """
    插入数据时的类型，这里只能表示一行数据
    """

    returns: str = "*"
    fields: list[FieldValue] = []

async def table_insert(db: str, app: str, table: str, data: TableSpecInsert):
    values = base.field_value_trans(data.fields, source.DefaultManager.db(db), table)

    try:
        return insert.insert_one(
            # db, "{}_{}".format(app, table), returns=data.returns, **values
            source.DefaultManager.db(db),
            table,
            returns=data.returns,
            **values
        )
    except Exception as e:
        Logger().error(e)
        return str(e)

class TableQueryJoin(BaseModel):
    this: str  # columnname
    other: str  # columnname
    mode: str

class TableQueryExpr(BaseModel):
    op: str
    value: base.FieldValue

class TableQuery(BaseModel):
    expr: list[TableQueryExpr]
    joins: list[TableQueryJoin]
    selects: str = ""
    group: str = ""

async def table_query(
    db: str,
    app: str,
    table: str,
    querys: TableQuery,
    all: bool = False,
    page: int = 1,
    page_size: int = 50,
):
    exp: list[base.Query] = []
    for item in querys.expr:
        exp.append(
            base.Query(
                item.value.name,
                base.QueryType[item.op],
                item.value.mode,
                item.value.value,
            )
        )

    joins: list[base.Join] = []
    for jitem in querys.joins:
        joins.append(base.Join(jitem.this, jitem.other, base.JoinType[jitem.mode]))

    try:
        if all:
            return query.query_all(
                source.DefaultManager.db(db),
                table,
                exp,
                joins,
                selects=querys.selects,
                page=page,
                page_size=page_size,
            )
        else:
            return query.query_one(
                source.DefaultManager.db(db), table, exp, joins, selects=querys.selects
            )
    except Exception as e:
        Logger().error(e)
        return str(e)

async def table_query_group(db: str, app: str, table: str, data: TableQuery):
    exp: list[base.Query] = []
    for item in data.expr:
        exp.append(
            base.Query(
                item.value.name,
                base.QueryType[item.op],
                item.value.mode,
                item.value.value,
            )
        )

    joins: list[base.Join] = []
    for jitem in data.joins:
        joins.append(base.Join(jitem.this, jitem.other, base.JoinType[jitem.mode]))

    try:
        return query.query_group(
            source.DefaultManager.db(db),
            table,
            data.group,
            exp,
            joins,
            selects=data.selects,
        )
    except Exception as e:
        Logger().error(e)
        return str(e)

class TableUpdate(BaseModel):
    returns: str = "*"
    insert: bool = False
    expr: list[TableQueryExpr]
    fields: list[FieldValue]

async def table_update(db: str, app: str, table: str, data: TableUpdate):
    if len(data.fields) == 0:
        return "ok"

    exp: list[base.Query] = []
    for item in data.expr:
        exp.append(
            base.Query(
                item.value.name,
                base.QueryType[item.op],
                item.value.mode,
                item.value.value,
            )
        )

    values = base.field_value_update_trans(
        data.fields, source.DefaultManager.db(db), table
    )
    default = base.field_value_update_trans(
        data.fields, source.DefaultManager.db(db), table, skip=["expression"]
    )

    try:
        return update.update_one(
            source.DefaultManager.db(db), table, exp, values, default, data.returns
        )
    except Exception as e:
        Logger().error(e)
        return str(e)

class TableDelete(BaseModel):
    expr: list[TableQueryExpr]
    returns: str = "*"

async def table_delete(db: str, app: str, table: str, data: TableDelete):
    if len(data.expr) == 0:
        return 0

    exp: list[base.Query] = []
    for item in data.expr:
        exp.append(
            base.Query(
                item.value.name,
                base.QueryType[item.op],
                item.value.mode,
                item.value.value,
            )
        )

    try:
        return delete.delete_record(source.DefaultManager.db(db), table, exp)
    except Exception as e:
        Logger().error(e)
        return 0


# INSTALL DEPENDENCIES WITH THIS COMMAND
# pip install -r requirements.txt
# RUN THIS COMMAND TO RUN SERVER:
# python main.py and go to http://localhost:5000/
import json
import os
import urllib

import flask

from . import db, rec

app = flask.Flask(__name__)
app.config['JSON_AS_ASCII'] = False

@app.route('/stop')
def stop():
    return '
Stop hacking our site
Обратно на сайт'

@app.route('/get_goods/<int:n_page>')
def get_goods(n_page):
    if flask.request.is_xhr:
        names, prices, categories, image, ids = [[] for i in range(5)]
        goods = db.get_page_goods(n_page)
        for g in goods:
            names.append(g["name"])
            prices.append(g["price"])
            ids.append(g["pk"])
            image.append(g["image"])
            categories.append('')
        return flask.jsonify(
            list(zip(names, prices, categories, image, ids)),
        )
    else:
        return flask.redirect('/stop')

@app.route('/')
def index():
    names, prices, categories, image, ids = [
        [] for i in range(5)]  # Инициализация списков
    goods = db.get_page_goods(1)  # первая страница товаров
    for g in goods:
        names.append(g["name"])
        prices.append(g["price"])
        ids.append(g["pk"])
        image.append(g["image"])
        categories.append('')
    info = zip(names, prices, categories, image, ids)  # склейка в один список
    return flask.render_template(
        'index.html', info=info
    )

@app.route('/cart')
def cart():
    cart_ids, ns = [], []  # Инициализация списков
    cookie = flask.request.cookies.get('cart', '')
    if cookie:
        cookie = urllib.parse.unquote(cookie)
        cookie = json.loads(cookie)
    for (pk, n) in cookie:
        cart_ids.append(pk)
        ns.append(n)
    r_names, r_prices, r_categories, r_image, r_ids = [[] for i in range(5)]
    recommendations = rec.get_recs_from_db(cart_ids, ns)
    for g in recommendations:
        r_names.append(g["name"])
        r_prices.append(g["price"])
        r_ids.append(g["pk"])
        r_image.append(g["image"])
        r_categories.append('')
    rec_info = zip(r_names, r_prices, r_categories, r_image, r_ids)
    names, prices, categories, image, ids = [[] for i in range(5)]
    goods = db.get_goods_by_ids(cart_ids)
    for g in goods:
        names.append(g["name"])
        prices.append(g["price"])
        ids.append(g["pk"])
        image.append(g["image"])
        categories.append('')
    info = zip(names, prices, categories, image, ids)
    return flask.render_template(
        'cart.html', info=info, rec_info=rec_info
    )

@app.route('/search/<string:request>')
def search(request):
    names, prices, categories, image, ids = [[] for i in range(5)]
    items = db.find_items(request)
    isEmpty = False
    for g in items:
        names.append(g["name"])
        prices.append(g["price"])
        ids.append(g["pk"])
        image.append(g["image"])
        categories.append('')
    if len(items) == 0:
        isEmpty = True
    info = zip(names, prices, categories, image, ids)
    return flask.render_template(
        'search.html', info=info, request=request, isEmpty=isEmpty
    )

@app.route('/static/images/products/<string:name>')
def get_image(name):
    fullpath = 'web/static/images/products/' + name
    filepath = 'static/images/products/' + name
    if os.path.isfile(fullpath):
        return flask.send_file(filepath)
    else:
        default = 'static/images/products/default.png'
        return flask.send_file(default)


import cv2
import numpy as np

def moyenne_image(video, nbr):
    cap=cv2.VideoCapture(video)
    tab_image=[]
    for f in range(nbr):
        ret, frame=cap.read()
        if ret is False:
            break
        image=cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        tab_image.append(image)
    tab_image=np.array(tab_image)
    cap.release()
    return np.mean(tab_image, axis=0)

def calcul_mask(image, fond, seuil):
    image=cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    height, width=image.shape
    mask=np.zeros([height, width], np.uint8)
    image=image.astype(np.int32)
    for y in range(height):
        for x in range(width):
            if abs(fond[y][x]-image[y][x])>seuil:
                mask[y][x]=255
    kernel=np.ones((5, 5), np.uint8)
    mask=cv2.erode(mask, kernel, iterations=1)
    mask=cv2.dilate(mask, kernel, iterations=3)
    return mask


from datetime import datetime

from CommonSqliteAbstractDb import CommonSqliteAbstractDb

class ConversationsSqliteDb(CommonSqliteAbstractDb):
    def __init__(self, path):
        super().__init__(path)
        cursor = self.db.cursor()
        cursor.execute("""
            -- Only written by raccogliere.py
            CREATE TABLE IF NOT EXISTS collected_tweets (
                tweet_id TEXT,
                in_reply_to_status_id TEXT,
                PRIMARY KEY (tweet_id)
            )
        """)
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS root_tweets (
                tweet_id TEXT,
                root_tweet_id TEXT,
                PRIMARY KEY (tweet_id)
            )
        """)
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS scraped_tweets (
                tweet_id TEXT,
                last_check TEXT,
                PRIMARY KEY (tweet_id)
            )
        """)
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS conversations (
                root_tweet_id TEXT,
                tweet_id TEXT,
                conversation_id TEXT,
                tweet_timestamp TEXT,
                tweet_text TEXT,
                user_id TEXT,
                user_name TEXT,
                user_screenname TEXT,
                PRIMARY KEY (root_tweet_id, tweet_id)
            )
        """)
        self.db.commit()

    def census_tweet(self, tweet_id, in_reply_to_status_id):
        c = self.db.cursor()
        if not c.execute(
            'SELECT * FROM collected_tweets WHERE tweet_id = ?',
            (tweet_id,)
        ).fetchone():
            c.execute(
                'INSERT INTO collected_tweets (tweet_id, in_reply_to_status_id) VALUES (?, ?)',
                (tweet_id, in_reply_to_status_id)
            )
        self.db.commit()

    def get_root_tweet_id(self, tweet_id):
        c = self.db.cursor()
        return c.execute(
            'SELECT * FROM root_tweets WHERE tweet_id = ?',
            (tweet_id)
        ).fetchone()

    def get_tweet_id_with_no_root_tweet(self):
        c = self.db.cursor()
        return c.execute(
            """
            SELECT ct.tweet_id
            FROM collected_tweets ct
            LEFT JOIN root_tweets rt
            ON ct.tweet_id = rt.tweet_id
            WHERE rt.tweet_id IS NULL
            """
        ).fetchall()

    def set_root_tweet_id(self, tweet_id, root_tweet_id):
        c = self.db.cursor()
        if not c.execute('SELECT * FROM root_tweets WHERE tweet_id = ?', (tweet_id,)).fetchone():
            c.execute(
                'INSERT INTO root_tweets (tweet_id, root_tweet_id) VALUES (?, ?)',
                (tweet_id, root_tweet_id)
            )
        self.db.commit()

    def get_unscraped_root_tweets(self):
        c = self.db.cursor()
        return c.execute(
            """
            SELECT ct.tweet_id
            FROM collected_tweets ct
            LEFT JOIN scraped_tweets st
            ON ct.tweet_id = st.tweet_id
            WHERE st.tweet_id IS NULL
            """
        ).fetchall()

    def update_scraping_last_check(self, tweet_id, now):
        c = self.db.cursor()
        c.execute(
            'UPDATE scraped_tweets SET last_check = ? WHERE tweet_id = ?',
            (now, tweet_id)
        )

    def add_tweet_in_conversation(self, root_tweet_id, tweet_id, conversation_id, tweet_timestamp, tweet_text, user_id, user_name, user_screenname):
        c = self.db.cursor()
        if not c.execute('SELECT * FROM conversations WHERE root_tweet_id = ? AND tweet_id = ?',
                         (root_tweet_id, tweet_id)).fetchone():
            c.execute(
                """INSERT INTO conversations (
                    root_tweet_id,
                    tweet_id,
                    conversation_id,
                    tweet_timestamp,
                    tweet_text,
                    user_id,
                    user_name,
                    user_screenname
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
                """, (root_tweet_id, tweet_id, conversation_id, tweet_timestamp, tweet_text, user_id, user_name, user_screenname)
            )
            self.db.commit()


import pygame
from checkers.constants import RED, GREEN, BLUE, SQUARE_SIZE
from checkers.board import Board
from checkers.board import Board

# department responsible for checking the legality of a move and also for marking legal moves
# and also for switching between the players' turns

class Game:
    def __init__(self, win):
        self.selected = None
        self._init()
        self.win = win

    def update(self):
        self.board.draw(self.win)
        self.draw_valid_moves(self.valid_moves)
        pygame.display.update()

    def _init(self):
        self.selected = None
        self.board = Board()
        self.turn = RED
        self.valid_moves = {}

    def winner(self):
        return self.board.winner()

    def reset(self):
        self._init()

    def select(self, row, col):
        if self.selected:
            result = self._move(row, col)
            if not result:
                self.selected = None
                self.select(row, col)

        piece = self.board.get_piece(row, col)
        if piece != 0 and piece.color == self.turn:
            self.selected = piece
            self.valid_moves = self.board.get_valid_moves(piece)
            return True

        return False

    # A boolean function that returns true or false to
    # whether the current player is allowed to make the move he is about to make
    def _move(self, row, col):
        piece = self.board.get_piece(row, col)
        if self.selected and piece == 0 and (row, col) in self.valid_moves:
            self.board.move(self.selected, row, col)
            skipped = self.valid_moves[(row, col)]
            if skipped:
                self.board.remove(skipped)
            self.change_turn()
        else:
            return False

        return True

    # function that colors each legal square center for a move in blue in order to show the player
    # which move is a legal move
    def draw_valid_moves(self, moves):
        for move in moves:
            row, col = move
            pygame.draw.circle(self.win, BLUE,
                               (col * SQUARE_SIZE + SQUARE_SIZE // 2, row * SQUARE_SIZE + SQUARE_SIZE // 2), 15)

    # A function that replaces after each move who is allowed to play in the next move
    def change_turn(self):
        self.valid_moves = {}
        if self.turn == RED:
            self.turn = GREEN
        else:
            self.turn = RED


from project.client import Client
from project.meals.dessert import Dessert
from project.meals.main_dish import MainDish
from project.meals.meal import Meal
from project.meals.starter import Starter

class FoodOrdersApp:
    VALID_MEALS = {"Starter": Starter,
                   "MainDish": MainDish,
                   "Dessert": Dessert}

    def __init__(self):
        self.menu = []
        self.clients_list = []
        self.paid_bills = 0

    def find_meal_by_name(self, meal_name):
        return [m for m in self.menu if m.name == meal_name]

    def find_client_by_number(self, number):
        return [c for c in self.clients_list if c.phone_number == number]

    def register_client(self, client_phone_number):
        if self.find_client_by_number(client_phone_number):
            raise Exception("The client has already been registered!")

        new_client = Client(client_phone_number)
        self.clients_list.append(new_client)
        return f"Client {client_phone_number} registered successfully."

    def add_meals_to_menu(self, *meals: Meal):
        for el in meals:
            if isinstance(el, Starter) or isinstance(el, MainDish) or isinstance(el, Dessert):
                self.menu.append(el)

    def show_menu(self):
        if len(self.menu) < 5:
            raise Exception("The menu is not ready!")

        return '\n'.join([meal.details() for meal in self.menu])

    def add_meals_to_shopping_cart(self, client_phone_number, **meal_names_and_quantities):
        if len(self.menu) < 5:
            raise Exception("The menu is not ready!")

        client_obj = self.find_client_by_number(client_phone_number)

        if not client_obj:
            client_obj = Client(client_phone_number)
            self.clients_list.append(client_obj)

        client = client_obj[0]
        current_bill = 0
        current_ordered_meals = []

        for meal_name, qnt in meal_names_and_quantities.items():
            meal = self.find_meal_by_name(meal_name)
            if not meal:
                raise Exception(f"{meal_name} is not on the menu!")

            meal_obj = meal[0]
            if meal_obj.quantity < qnt:
                raise Exception(f"Not enough quantity of {meal_obj.__class__.__name__}: {meal_name}!")

        for meal_name, qnt in meal_names_and_quantities.items():
            meal = self.find_meal_by_name(meal_name)[0]
            current_ordered_meals.append(meal)
            current_bill += meal.price * qnt
            meal.quantity -= qnt

            if meal_name not in client.ordered_meals_qnt:
                client.ordered_meals_qnt[meal_name] = 0
            client.ordered_meals_qnt[meal_name] += qnt

        client.bill += current_bill
        client.shopping_cart.extend(current_ordered_meals)

        return f"Client {client_phone_number} successfully ordered " \
               f"{', '.join([m.name for m in client.shopping_cart])} for {client.bill:.2f}lv."

    def cancel_order(self, client_phone_number):
        client = self.find_client_by_number(client_phone_number)[0]
        if not client.shopping_cart:
            raise Exception("There are no ordered meals!")

        for meal_name, qnt in client.ordered_meals_qnt:
            for meal in self.menu:
                if meal.name == meal_name:
                    meal.quantity += qnt

        client.bill = 0
        client.shopping_cart = []
        client.ordered_meals_qnt = {}

        return f"Client {client_phone_number} successfully canceled his order."

    def finish_order(self, client_phone_number):
        client = self.find_client_by_number(client_phone_number)[0]
        if not client.shopping_cart:
            raise Exception("There are no ordered meals!")

        paid_money = client.bill
        client.bill = 0
        client.shopping_cart = []
        client.ordered_meals_qnt = {}
        self.paid_bills += 1
        return f"Receipt #{self.paid_bills} with total amount of {paid_money:.2f}" \
               f" was successfully paid for {client_phone_number}."

    def __str__(self):
        return f"Food Orders App has {len(self.menu)} meals " \
               f"on the menu and {len(self.clients_list)} clients."

Retake Exam - 22 August 2022/project/food_orders_app.py


'''
pytest -s -v
если добавить еще ключ duration=<время в секундах> -vv, будут указаны
медленные тесты
если добавить --alluredir=<package_name>, а потом запустить allire
serve <package_name>, то получим красоту
Тесты можно пропускать, обернув в декоратор
@pytest.mark.skip
Если нужно выполнить один тест с разными наборами параметров,
можно задать эти наборы параметров с помощью
@pytest.mark.parametrize(
    'first_value', 'second_value', 'result', [
        (1, 2, 3), (4, 5, 9)...
    ]
)
значения записать в качестве параметров оборачиваемой функции
и использовать по назначению
если маркировать тесты декоратором @pytest.prod.<имя из pytest.ini>,
то при вызове через pytest -k <имя из pytest.ini>, запустятся только
они '''

import sqlite3
from tkinter import LabelFrame
from main import Vocabulary
from exersizes import (
    new_words, eng_to_rus,  # status_buttons
)
from crs.enums.global_enums import ErrorMessages

class TestMain():

    @classmethod
    def setup_class(cls):
        cls.button_texts = [
            'Просмотреть новые слова', 'Смутно знакомые слова',
            'На русский', 'На английский'
        ]
        cls.new_texts = [
            'Следующее', 'Предыдущее', 'отметить как знакомое',
            'отметить как хорошо знакомое'
        ]
        cls.to_eng_texts = [
            'Проверить', 'отметить как знакомое',
            'отметить как хорошо знакомое'
        ]
        cls.new = new_words.Word(True, False)
        cls.known_words = new_words.Word(False, True)
        cls.to_rus = eng_to_rus.WellKnownWord(0, 1)
        cls.to_eng = eng_to_rus.WellKnownWord(1, 0)
        cls.voc = Vocabulary(
            cls.new, cls.known_words, cls.to_rus, cls.to_eng
        )

    def test_children(self):
        self.voc.start()
        ''' Проверяем, верно ли указаны названия кнопок на
        главной странице '''
        for child in self.voc.root.winfo_children():
            assert child['text'] in self.button_texts
        frame = LabelFrame(self.voc.second_screen)
        frame.pack()
        ''' Проверяем, верно ли указаны названия кнопок на
        странице новых слов '''
        self.new.show(frame, 0, True)
        # self.voc.root.winfo_children()[0].invoke()

        for child in frame.winfo_children():
            if child.widgetName == 'button':
                assert child['text'] in self.new_texts, (
                    ErrorMessages.WRONG_BUTTON_NAME.value
                )
        self.to_eng.translate(frame, 0, True)
        # self.voc.root.winfo_children()[1].invoke()
        for child in frame.winfo_children():
            if child.widgetName == 'button':
                assert child['text'] in self.to_eng_texts
        self.voc.root.quit()
        self.voc.second_screen.quit()

    def test_exersizes(self):
        ''' Проверяем, корректно ли выбираются слова для списка
        неизвестных слов '''
        word = self.new.get_word(0, 1)
        with sqlite3.connect('vocabulary.db') as conn:
            cursor = conn.cursor()
            result = cursor.execute(
                ''' SELECT english, russian, id, is_new, is_known
                FROM words_word
                WHERE id=:id ''', {'id': word[2]}
            ).fetchone()
            assert word[0] == result[0]
            assert word[1] == result[1]
            assert word[2] == result[2]
            assert result[3] == 1
            assert result[4] == 0


from CGRtools import smiles
from .abc import SynthonABC

class DummySynthon(SynthonABC):
    """
    Test synthon for Acetaminophen.
    """
    __slots__ = ()

    def __iter__(self):
        for prob, molecules in data[self._molecule][0]:
            yield prob, tuple(type(self)(mol) for mol in molecules)

    def __bool__(self):
        return self._molecule in building_blocks

    def __float__(self):
        return data[self._molecule][1]

building_blocks = {smiles('Oc1ccccc1')}
pre_data = {
    'CC(=O)Nc1ccc(O)cc1': (((.25, ('Oc1ccc(N)cc1',),),
                            (.15, ('C(Nc1ccc(OC)cc1)(C)=O',)),
                            (.2, ('ON=C(C)c1ccc(O)cc1',)),
                            (.25, ('Oc1ccc(O)cc1',)),
                            (.15, ('C(Nc1ccc(OC2OCCCC2)cc1)(C)=O',))), 1.),
    'Oc1ccc(N)cc1': (((.3, ('O=N(=O)c1ccc(O)cc1',)),
                      (.4, ('c1(N)ccc(OC)cc1',)),
                      (.3, ('c1(O)ccc(F)cc1',))), 1.),
    'O=N(=O)c1ccc(O)cc1': (((.35, ('Oc1ccccc1',)),
                            (.35, ('N(c1ccc(N)cc1)(=O)=O',)),
                            (.3, ('c1(N(=O)=O)cc(c(cc1)O)Br',))), 1.),
    'Oc1ccccc1': ((), 1.),
    'C(Nc1ccc(OC)cc1)(C)=O': ((), -1.),
    'Oc1ccc(O)cc1': ((), 0.),
    'C(Nc1ccc(OC2OCCCC2)cc1)(C)=O': ((), -1.),
    'c1(N)ccc(OC)cc1': ((), -1.),
    'c1(O)ccc(F)cc1': (((1., ('c1(OCOCCOC)ccc(F)cc1',)),), .1),
    'c1(OCOCCOC)ccc(F)cc1': ((), -1.),
    'c1(N(=O)=O)cc(c(cc1)O)Br': ((), -1.),
    'N(c1ccc(N)cc1)(=O)=O': (((1., ('C(c1c([N+](=O)[O-])ccc(c1)N)(=O)O',)),), -.1),
    'C(c1c([N+](=O)[O-])ccc(c1)N)(=O)O': ((), -1.),
    'ON=C(C)c1ccc(O)cc1': (((.5, ('O=C(C)c1ccc(O)cc1',)),
                            (.2, ('[Si](C(C)(C)C)(Oc1ccc(C(=NO)C)cc1)(C)C',)),
                            (.3, ('c1(c(ccc(C(=NO)C)c1)O)N',))), 1.),
    'c1(c(ccc(C(=NO)C)c1)O)N': (((1., ('c1(c(cc(C(=NO)C)cc1)N)OCOC',)),), -.2),
    'c1(c(cc(C(=NO)C)cc1)N)OCOC': ((), -1.),
    'O=C(C)c1ccc(O)cc1': (((.85, ('Oc1ccccc1',)),
                           (.15, ('[Si](C(C)(C)C)(Oc1ccc(C(=O)C)cc1)(C)C',))), 1.),
    '[Si](C(C)(C)C)(Oc1ccc(C(=O)C)cc1)(C)C': ((), -1.),
    '[Si](C(C)(C)C)(Oc1ccc(C(=NO)C)cc1)(C)C': ((), -1.),
}

def convert(dct):
    out = {}
    for k, (tuples, value) in dct.items():
        k = smiles(k)
        k.canonicalize()
        new_mols = []
        for prob, mols in tuples:
            synth = []
            for mol in mols:
                new_mol = smiles(mol)
                new_mol.canonicalize()
                synth.append(new_mol)
            new_mols.append((prob, tuple(synth)))
        out[k] = (tuple(new_mols), value)
    return out

data = convert(pre_data)

__all__ = ['DummySynthon']


import json
import pandas as pd
from tqdm import tqdm
import glob
import bz2
from utils import clean, remove_short

files = glob.glob('./Data/twitter-stream/*/*/*/*/*.json.bz2')
print('Numner of files to open:', len(files))
with open('Data/dataset_quote.txt', 'w') as fw:
    for i, file in tqdm(enumerate(files[:])):
        with bz2.open(file, "rb") as f:
            try:
                for line in f.readlines():
                    tw = json.loads(line)
                    # The tweet should be in English, it should be a quote and the quoted text should be in English
                    if 'lang' in tw and \
                        tw['lang'] == 'en' and \
                        'quoted_status' in tw and \
                        tw['quoted_status']['lang'] == 'en':

                        if 'retweeted_status' in tw:
                            tw = tw['retweeted_status'] # If the tweet is a retweet, take the retweeeted tweet

                        # Collect (full) text and mentions of the quote
                        if 'extended_tweet' in tw:
                            text = tw['extended_tweet']['full_text']
                            mentions = [x['screen_name'] for x in tw['extended_tweet']['entities']['user_mentions']]
                        else:
                            text = tw['text']
                            mentions = [x['screen_name'] for x in tw['entities']['user_mentions']]

                        # Collect (full) text and mentions of quoted tweet
                        if 'extended_tweet' in tw['quoted_status']:
                            qtext = tw['quoted_status']['extended_tweet']['full_text']
                            qmentions = [x['screen_name'] for x in tw['quoted_status']['extended_tweet']['entities']['user_mentions']]
                        else:
                            qtext = tw['quoted_status']['text']
                            qmentions = [x['screen_name'] for x in tw['quoted_status']['entities']['user_mentions']]

                        # Replace newline and tab
                        text = text.replace('\n', ' ').replace(' \t', ' ').replace('\r', ' ').lower()
                        qtext = qtext.replace('\n', ' ').replace(' \t', ' ').replace('\r', ' ').lower()

                        # Standardize mentions
                        for mention in mentions:
                            text = text.replace(mention.lower(), '')
                        for qmention in qmentions:
                            qtext = qtext.replace(qmention.lower(), '')

                        d = tw['id_str'] + '\t' + \
                            tw['quoted_status_id_str'] + '\t' + \
                            text + '\t' + \
                            qtext + '\n'
                        fw.write(d)
            except:
                continue

df = pd.read_csv('Data/dataset_quote.txt', sep='\t', engine='python', quoting=3, header=None)
df = df.rename(columns={0:'id1', 1:'id2', 2:'text1', 3:'text2'})

# Clean and remove short tweets, drop duplicates
df['text1_clean'] = df['text1'].apply(clean)
df['text2_clean'] = df['text2'].apply(clean)
df = remove_short(df)
df = df.drop_duplicates(subset='text2_clean', keep='first')
df = df.drop_duplicates(subset='text1_clean', keep='first')
df = df.drop(['text1', 'text2'], axis=1)
df = df.rename(columns={'text1_clean':'text1', 'text2_clean':'text2'})

df[['id1', 'id2', 'text1', 'text2']].to_csv('Data/dataset_quote.csv', sep='\t', index=None)


import sys, tty, termios, os
import time
from board import SCL, SDA
import busio
from adafruit_motor import servo
from adafruit_pca9685 import PCA9685

i2c = busio.I2C(SCL, SDA)
pca = PCA9685(i2c)

pca.frequency = 60

servo1 = servo.Servo(pca.channels[1])
#servo4 = servo.Servo(pca.channels[4])
servo2 = servo.Servo(pca.channels[2])
degree1 = 90
#degree4 = 0
degree2 = 90

def getch():
    fd = sys.stdin.fileno()
    old_settings = termios.tcgetattr(fd)
    try:
        tty.setraw(sys.stdin.fileno())
        ch = sys.stdin.read(1)
    finally:
        termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
    return ch

while True:
   char = getch()
   #print(char)
   if(char == 'r'):
       print('increment angle joint0 '+str(degree1))
       degree1 = degree1 + 1
       degree2 = degree2 - 1
       servo1.angle = degree1
       servo2.angle = degree2
   if(char == 'f'):
       print('Decrement angle joint0 {}'.format(degree2))
       degree1 = degree1 - 1
       degree2 = degree2 + 1
       servo1.angle = degree1
       servo2.angle = degree2
   if(char == 't'):
      print('increment angle joint2 {} '.format(degree2))
      #degree2 = degree2 + 1
      servo2.angle = degree2
   if(char == 'g'):
      print('Decrement angle joint2 {}'.format(degree2))
      #degree2 = degree2 - 1
      servo2.angle = degree2
   if(char == 'y'):
      print('increment angle joint4 {}'.format(degree4))
      degree4 = degree4 + 1
      servo4.angle = degree4
   if(char == 'h'):
      print('Decrement angle joint4 {}'.format(degree4))
      degree4 = degree4 - 1
      servo4.angle = degree4
   if(char == "x"):
       break
   char = ""


from numpy import array
from keras.layers import Input
from keras.layers import LSTM
from keras.layers import GRU
from keras.layers import Dense
from keras.layers import RepeatVector
from keras.layers import TimeDistributed
from keras.layers.merge import Concatenate
from keras.layers.merge import Multiply
from keras.models import Model
from keras.models import load_model
from src.prediction import utils
from src.aisdata.scope import Scope
from src.aisdata.ship import Ship
from src.aisdata.route import Route
from src.aisdata.state import State
import numpy as np
import argparse
from keras.utils import plot_model

class Prediction:
    n_neighbours = 2

    def __init__(self, n_features=2, input_window_size=3, training_data_size=100, forecast_size=3, n_unit=100,
                 net_type="LSTM", epochs=1000, model_save_path="", model_load_path=""):
        """Constructor of Prediction

        Parameters:
            n_features: number of features
            input_window_size: size of the input window
            training_data_size: number of training data sequences
            forecast_size: number of forecast time steps / output window
            n_unit: number of LSTM/GRU units to use per neighbour
            net_type: type of the net (LSTM or GRU)
            epochs: number of training epochs
            model_save_path: path to save model
            model_load_path: path to load model
        """
        self.nFeatures = n_features
        self.inputWindowSize = input_window_size
        self.forecastSize = forecast_size
        self.nUnit = n_unit
        self.net_type = net_type
        self.training_data_size = training_data_size
        self.epochs = epochs
        self.model_save_path = model_save_path
        self.model_load_path = model_load_path

    def generate_model(self, X):
        """ Generate the model.

        return: model
        """
        # LSTM encoders
        inp = [Input(shape=(X[0].shape[1], X[0].shape[2])), Input(shape=(X[1].shape[1], X[1].shape[2])), Input(shape=(X[1].shape[1], X[1].shape[2]))]
        if (self.net_type == "LSTM"):
            enc = [LSTM(self.nUnit)(inp[0]), LSTM(self.nUnit)(inp[1]), LSTM(self.nUnit)(inp[2])]
        else:
            enc = [GRU(self.nUnit)(inp[0]), GRU(self.nUnit)(inp[1]), GRU(self.nUnit)(inp[2])]

        # Attention layer for observed ship
        at_probs_o = Dense(self.nUnit, activation='softmax')(enc[0])
        at_mul_o = Multiply()([enc[0], at_probs_o])

        # Attention layer for neighbours
        con_n = Concatenate()([enc[1], enc[2]])
        at_probs_n = Dense((len(X)-1)*self.nUnit, activation='softmax')(con_n)
        at_mul_n = Multiply()([con_n, at_probs_n])

        # Attention layer for all
        con_a = Concatenate()([at_mul_o, at_mul_n])
        at_probs_a = Dense(len(X)*self.nUnit, activation='softmax')(con_a)
        at_mul_a = Multiply()([con_a, at_probs_a])

        # LSTM decoder
        rep = RepeatVector(self.inputWindowSize)(at_mul_a)

        if (self.net_type == "LSTM"):
            dec = LSTM(self.nUnit, return_sequences=True)(rep)
        else:
            dec = GRU(self.nUnit, return_sequences=True)(rep)

        tdis = TimeDistributed(Dense(self.nFeatures))(dec)
        model = Model(inputs=inp, outputs=tdis)
        return model

    def train(self, X, y):
        """ Train the prediciton model

        return: trained model
        """
        #reshape from [samples, timesteps] into [samples, timesteps, features]
        for i in range(X.shape[1]):
            print("seq: " + str(i))
            print(X[0][i])
            print(X[1][i])
            print(X[2][i])
            print(y[i])

        X = list(map(lambda x: x.reshape((x.shape[0], x.shape[1], self.nFeatures)), X))
        y = y.reshape((y.shape[0], y.shape[1], self.nFeatures))

        model = self.generate_model(X)

        model.compile(optimizer='adam', loss='mse')
        # fit model
        model.fit(X, y, epochs=self.epochs, verbose=1)
        return model

    def predict(self, model, x_input):
        """ Predicts the next forecast_size time steps.

        return: prediction as a numpy array
        """
        # Prediction start array
        print("input:")

        x_input = x_input.reshape((3, 1, self.inputWindowSize, self.nFeatures))
        print(x_input)
        # predict
        yhat = model.predict([x_input[0], x_input[1], x_input[2]], verbose=0)
        print("output: ")
        print(yhat)

        # print result
        return yhat

    def predict_route(self, model, route, other_ships):

        X, y = utils.extract_training_examples_for_route(route, other_ships, n_ships=3, n_states=10)

        #r = route.states
        #a = []
        #for s in r:
        #    a.append([s.latitude, s.longitude])

        #a = array(a[0:self.inputWindowSize])
        print(X.shape)
        x = array([X[0][X.shape[1]-1], X[1][X.shape[1]-1], X[2][X.shape[1]-1]])
        res = self.predict(model, x)
        res = res[0]
        p_states = []
        for r in res:
            state = route.states[len(p_states) + self.inputWindowSize]
            p_states.append(State(len(p_states) + self.inputWindowSize,r[0], r[1], state.status,
                                  state.rate_of_turn, state.speed_over_ground, state.course_over_ground,
                                  state.true_heading, state.t_day, state.t_week, state.draught))

        route.predicted_states = p_states
        return route

def arg_parser():
    """ returns an argument parse, which parses the arugments, which are needed.
    """
    parser = argparse.ArgumentParser(add_help=False)
    parser.add_argument("--n_features", action='store', type=int, help="number of features", default=2)
    parser.add_argument("--input_window_size", action='store', type=int, help="size of the input window", default=3)
    parser.add_argument("--training_data_size", action='store', type=int, help="number of training sequences", default=72)
    parser.add_argument("--forecast_size", action='store', type=int, help="number of forecast time steps", default=3)
    parser.add_argument("--n_unit", action='store', type=int, help="number of LSTM / GRU units", default=100)
    parser.add_argument("--net_type", action='store', type=str, help="type of the net (LSTM | GRU)", default="LSTM")
    parser.add_argument("--epochs", action='store', type=int, help="number of training epochs", default=1000)
    parser.add_argument("--model_save_path", action='store', type=str, help="model save path", default="")
    parser.add_argument("--model_load_path", action='store', type=str, help="model load path", default="")
    return parser

if __name__ == "__main__":
    import argparse
    from src.persistent.writer import Writer
    from src.persistent.reader import Reader
    import src.persistent.argument as argument

    parser = argparse.ArgumentParser(parents=[argument.io_paths_parser(), arg_parser()])
    args = parser.parse_args()
    pr = Prediction(args.n_features, args.input_window_size, args.training_data_size, args.forecast_size, args.n_unit,
                    args.net_type, args.epochs, args.model_save_path, args.model_load_path)
    reader = Reader(args.input)
    scope = reader.read()

    ship = list(scope.ships)[0]
    other_ships = list(scope.ships)
    other_ships.remove(ship)
    route = list(ship.routes)[0]
    if(pr.model_load_path==""):
        X, y = utils.extract_training_examples_for_route(route, other_ships, n_ships=3, n_states=10)
        pr.training_data_size = X.shape[0]

        #y_values = list(map(lambda r: [r.latitude, r.longitude], route.states))
        #y = []
        #for i in range(X.shape[1]):
        #    y.append(y_values[i+pr.inputWindowSize:i+2*pr.inputWindowSize])

        #y = array(y)
        model = pr.train(X, y)
        if(pr.model_save_path != ""):
            model.save("trained_model.h5")
    else:
        model = load_model(pr.model_load_path)

    route.predicted_states = pr.predict_route(model, route, other_ships).predicted_states
    writer = Writer(args.output)
    writer.write(scope)