import pygame
import os
import sys
from random import choice, randrange

pygame.init()
size = w, h = 1000, 420
pygame.display.set_caption('runner')
screen = pygame.display.set_mode(size)

all_sprites = pygame.sprite.Group()

runner_group = pygame.sprite.Group()
obstacles_group = pygame.sprite.Group()
background_group = pygame.sprite.Group()

play_but = pygame.Surface([200, 50])
play_fon = pygame.Surface([800, 600])
stop = pygame.Surface([400, 300])
monsters = ['wmonsterrun4.png', 'rmonsterrun4.png']
robots = ['wrobotrun3.png', 'grobotrun4.png']
s = [700]

WHITE = pygame.Color('white')
BLACK = pygame.Color('black')

FPS = 30
clock = pygame.time.Clock()

columns = 6
rows = 1

x, y = 100, 350

scores = 0
cnt_runner = 0
cnt_monsters = 0
cnt2 = 0
cnt_sc = [0]
cnt_rd = 0
speed = -15
cnt_d = -1
f = False
f2 = False
run = True

def load_image(name, color_key=None):
    fullname = os.path.join('data', name)
    if not os.path.isfile(fullname):
        print(f"Файл с изображением '{fullname}' не найден")
        sys.exit()
    image = pygame.image.load(fullname)
    if color_key is not None:
        image = image.convert()
        if color_key == -1:
            color_key = image.get_at((0, 0))
        image.set_colorkey(color_key)
    else:
        image = image.convert_alpha()
    return image

def terminate():
    pygame.quit()
    sys.exit()

def start_screen():
    global f2
    intro_text = ["CUTIESCAPE"]
    hl_text = ['PLAY HARD LEVEL']
    el_text = ['PLAY EASY LEVEL']
    fon = pygame.transform.scale(load_image('background2.png'), (w, h))
    screen.blit(fon, (0, 0))
    font = pygame.font.Font(None, 50)
    pb_font = pygame.font.Font(None, 30)
    text_coord = 50

    for line in intro_text:
        string_rendered = font.render(line, True, pygame.Color('black'))
        intro_rect = string_rendered.get_rect()
        text_coord += 100
        intro_rect.top = text_coord
        intro_rect.x = 100
        text_coord += intro_rect.height
        screen.blit(string_rendered, intro_rect)

    for line in hl_text:
        play_but.fill(pygame.Color('#2E8B57'))
        but_x2 = 100
        but_y2 = 300
        screen.blit(play_but, (but_x2, but_y2))
        string_rendered = pb_font.render(line, True, pygame.Color('black'))
        intro_rect = string_rendered.get_rect()
        text_coord += 135
        intro_rect.top = text_coord
        intro_rect.x = 110
        text_coord += intro_rect.height
        screen.blit(string_rendered, intro_rect)

    for line in el_text:
        play_but.fill(pygame.Color('#2E8B57'))
        but_x = 100
        but_y = 200
        screen.blit(play_but, (but_x, but_y))
        string_rendered = pb_font.render(line, True, pygame.Color('black'))
        intro_rect = string_rendered.get_rect()
        text_coord += -125
        intro_rect.top = text_coord
        intro_rect.x = 110
        text_coord += intro_rect.height
        screen.blit(string_rendered, intro_rect)

    while True:
        but_x = 100
        but_y = 200
        but_x2 = 100
        but_y2 = 300
        keys_pressed = pygame.key.get_pressed()
        if keys_pressed[pygame.K_RETURN]:
            return
        for event in pygame.event.get():

            if event.type == pygame.QUIT:
                terminate()

            elif event.type == pygame.MOUSEBUTTONDOWN:
                pos = event.pos

                if but_x < pos[0] < but_x + 200 and but_y < pos[1] < but_y + 50:
                    f2 = True
                    return

                elif but_x2 < pos[0] < but_x2 + 200 and but_y2 < pos[1] < but_y2 + 50:
                    f2 = False
                    return

        pygame.display.flip()
        clock.tick(FPS)

def text(message, x, y, font_type=None, font_size=30):
    global f2
    if f2:
        col = pygame.Color('black')
    else:
        col = pygame.Color('#2E8B57')
    font_type = pygame.font.Font(font_type, font_size)
    t = font_type.render(message, True, col)
    screen.blit(t, (x, y))

start_screen()

class Background(pygame.sprite.Sprite):

    def __init__(self):
        super().__init__(all_sprites, background_group)
        if f2:

            self.image = pygame.transform.scale(load_image('background1.png'), (w, h))
            self.rect = self.image.get_rect()
            self.rect.bottom = h
        else:
            self.image = pygame.transform.scale(load_image('background2.png'), (w, h))
            self.rect = self.image.get_rect()
            self.rect.bottom = h

def stopped(lt):
    font = pygame.font.Font(None, 50)
    text_coord = 100
    n = 100
    for line in lt:
        string_rendered = font.render(line, True, pygame.Color('white'))
        intro_rect = string_rendered.get_rect()
        intro_rect.top = text_coord
        n += 20
        intro_rect.x += n
        screen.blit(string_rendered, intro_rect)

def withdrawal_of_records():
    file = open('results.txt', 'w', encoding='utf8')
    file.write(f'record: {max(cnt_sc)}')
    file.close()

class White(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__(obstacles_group, all_sprites)
        self.frames = []
        self.columns = 4
        self.rows = 1
        self.sheet = pygame.transform.scale(
            pygame.transform.flip(load_image(choice(monsters)), True, False),
            (400, 120))
        self.cut_sheet(self.sheet, self.columns, self.rows)
        self.cur_frame = 0
        self.image = self.frames[self.cur_frame]
        self.mask = pygame.mask.from_surface(self.image)
        self.rect = self.rect.move(1000, y)
        self.cnt = cnt_monsters
        self.cnt_rd = cnt_rd
        self.speed = speed

    def cut_sheet(self, sheet, columns, rows):
        self.rect = pygame.Rect(0, -50, sheet.get_width() // columns,
                                sheet.get_height())
        for j in range(rows):
            for i in range(columns):
                frame_location = (self.rect.w * i, self.rect.h * j)
                self.frames.append(sheet.subsurface(pygame.Rect(
                    frame_location, self.rect.size)))

    def update(self, *args):
        if self.cnt % 4 == 0:
            self.cur_frame = (self.cur_frame + 1) % len(self.frames)
            self.image = self.frames[self.cur_frame]
            self.mask = pygame.mask.from_surface(self.image)
        if f2:
            self.speed = -15
        else:
            self.speed = -25
        self.rect = self.rect.move(speed, 0)
        if self.rect.x < -300:
            self.rect.x = randrange(1000, 1200)
            self.sheet = pygame.transform.scale(
                pygame.transform.flip(load_image(choice(monsters)), True, False),
                (120, 120))
        self.cnt += 1

class WhiteRobot(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__(obstacles_group, all_sprites)
        self.frames = []
        self.columns = 3
        self.rows = 1
        self.sheet = pygame.transform.scale(
            pygame.transform.flip(load_image('wrobotrun3.png'), True, False),
            (400, 120))
        self.columns = 3
        self.cut_sheet(self.sheet, self.columns, self.rows)
        self.cur_frame = 0
        self.image = self.frames[self.cur_frame]
        self.mask = pygame.mask.from_surface(self.image)
        self.rect = self.rect.move(1500, y)
        self.cnt = cnt_monsters
        self.speed = speed

    def cut_sheet(self, sheet, columns, rows):
        self.rect = pygame.Rect(0, -50, sheet.get_width() // columns,
                                sheet.get_height())
        for j in range(rows):
            for i in range(columns):
                frame_location = (self.rect.w * i, self.rect.h * j)
                self.frames.append(sheet.subsurface(pygame.Rect(
                    frame_location, self.rect.size)))

    def update(self, *args):
        if self.cnt % 4 == 0:
            self.cur_frame = (self.cur_frame + 1) % len(self.frames)
            self.image = self.frames[self.cur_frame]
            self.mask = pygame.mask.from_surface(self.image)
        if f2:
            self.speed = -15
        else:
            self.speed = -25
        self.rect = self.rect.move(speed, 0)
        if self.rect.x < -300:
            self.rect.x = randrange(2000, 2800)
        self.cnt += 1

class GreenRobot(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__(obstacles_group, all_sprites)
        self.frames = []
        self.columns = 3
        self.rows = 1

        self.sheet = pygame.transform.scale(
            pygame.transform.flip(load_image('grobotrun4.png'), True, False),
            (400, 120))
        self.columns = 4

        self.cut_sheet(self.sheet, self.columns, self.rows)
        self.cur_frame = 0
        self.image = self.frames[self.cur_frame]
        self.mask = pygame.mask.from_surface(self.image)
        self.rect = self.rect.move(1800, y)
        self.cnt = cnt_monsters
        self.speed = speed

    def cut_sheet(self, sheet, columns, rows):
        self.rect = pygame.Rect(0, -50, sheet.get_width() // columns,
                                sheet.get_height())
        for j in range(rows):
            for i in range(columns):
                frame_location = (self.rect.w * i, self.rect.h * j)
                self.frames.append(sheet.subsurface(pygame.Rect(
                    frame_location, self.rect.size)))

    def update(self, *args):
        if self.cnt % 4 == 0:
            self.cur_frame = (self.cur_frame + 1) % len(self.frames)
            self.image = self.frames[self.cur_frame]
            self.mask = pygame.mask.from_surface(self.image)
        if f2:
            self.speed = -15
        else:
            self.speed = -25
        self.rect = self.rect.move(speed, 0)
        if self.rect.x < -300:
            self.rect.x = randrange(3100, 3300)
        self.cnt += 1

m_white = White()
robot = WhiteRobot()
robot2 = GreenRobot()

class Runner(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__(runner_group, all_sprites)
        self.isJump = False
        self.jumpCount = 10
        sheet = pygame.transform.scale(load_image('omrun_6.png'), (500, 100))
        columns = 6
        self.frames = []
        self.cut_sheet(sheet, columns)
        self.cur_frame = 0
        self.image = self.frames[self.cur_frame]
        self.rect = self.rect.move(x, y)
        self.rect.midbottom = (250, h)
        self.cnt = cnt_runner
        self.col = False
        self.mask = pygame.mask.from_surface(self.image)
        self.cnt_rd = cnt_rd
        self.cnt_d = cnt_d

    def cut_sheet(self, sheet, columns):
        self.rect = pygame.Rect(0, 0, sheet.get_width() // columns,
                                sheet.get_height())
        for j in range(rows):
            for i in range(columns):
                frame_location = (self.rect.w * i, self.rect.h * j)
                self.frames.append(sheet.subsurface(pygame.Rect(
                    frame_location, self.rect.size)))

    def update(self, *args) -> None:
        global cnt2, f, run
        if self.cnt % 2 == 0 and self.isJump is False:
            self.cur_frame = (self.cur_frame + 1) % len(self.frames)
            self.image = self.frames[self.cur_frame]
            self.mask = pygame.mask.from_surface(self.image)
        keys_pressed = pygame.key.get_pressed()
        if keys_pressed[pygame.K_SPACE]:
            self.isJump = True
        if self.isJump is True:
            if self.jumpCount >= -10:
                if self.jumpCount < 0:
                    self.rect.y += (self.jumpCount ** 2) // 2
                else:
                    self.rect.y -= (self.jumpCount ** 2) // 2
                self.jumpCount -= 1
            else:
                self.isJump = False
                self.jumpCount = 10
        self.cnt += 1
        collided = pygame.sprite.spritecollideany(self, obstacles_group)
        if collided:
            for elem in obstacles_group:
                elem.speed = 0
            if pygame.sprite.collide_mask(self, collided):
                if f2:

                    collided.rect.x += 15
                else:
                    collided.rect.x += 30
                f = True

def final_screen():
    global scores, run, f, f2, cnt2
    intro_text = ["GAME OVER"]
    hl_text = ['PLAY AGAIN']
    el_text = ['OUTPUT RECORD']
    pb_font = pygame.font.Font(None, 30)
    if f2:
        fon = pygame.transform.scale(load_image('background1.png'), (w, h))
    else:
        fon = pygame.transform.scale(load_image('background2.png'), (w, h))
    screen.blit(fon, (0, 0))
    font = pygame.font.Font(None, 50)
    text_coord = 50

    for line in intro_text:
        if f2:
            col = pygame.Color('#2E8B57')
        else:
            col = pygame.Color('black')
        string_rendered = font.render(line, True, col)
        intro_rect = string_rendered.get_rect()
        text_coord += 0
        intro_rect.top = text_coord
        intro_rect.x = 130
        text_coord += intro_rect.height
        screen.blit(string_rendered, intro_rect)
        font = pygame.font.Font(None, 50)
        text_coord = 50
        cnt_sc.append(int(scores))
        text(
            f'PRESS ENTER TO PLAY AGAIN, record: {str(max(cnt_sc))}, TO DISPLAY THE RESULTS IN A TXT FILE, PRESS 1',
            50, 100)

        for line in hl_text:
            play_but.fill(pygame.Color('#2E8B57'))
            but_x2 = 100
            but_y2 = 300
            screen.blit(play_but, (but_x2, but_y2))
            string_rendered = pb_font.render(line, True, pygame.Color('black'))
            intro_rect = string_rendered.get_rect()
            text_coord += 265
            intro_rect.top = text_coord
            intro_rect.x = 110
            text_coord += intro_rect.height
            screen.blit(string_rendered, intro_rect)

        for line in el_text:
            play_but.fill(pygame.Color('#2E8B57'))
            but_x = 100
            but_y = 200
            screen.blit(play_but, (but_x, but_y))
            string_rendered = pb_font.render(line, True, pygame.Color('black'))
            intro_rect = string_rendered.get_rect()
            text_coord += -125
            intro_rect.top = text_coord
            intro_rect.x = 110
            text_coord += intro_rect.height
            screen.blit(string_rendered, intro_rect)

        for event in pygame.event.get():
            but_x = 100
            but_y = 200
            but_x2 = 100
            but_y2 = 300
            keys_pressed = pygame.key.get_pressed()
            if event.type == pygame.QUIT:
                run = False
                f = False

            if keys_pressed[pygame.K_ESCAPE]:
                run = False
                f = False

            if keys_pressed[pygame.K_RETURN]:
                m_white.rect.x += randrange(1100, 1300)
                robot.rect.x += randrange(1500, 1700)
                robot2.rect.x += randrange(1800, 1900)
                f = False

            if keys_pressed[pygame.K_1]:
                withdrawal_of_records()

            if event.type == pygame.MOUSEBUTTONDOWN:
                pos = event.pos
                if but_x2 < pos[0] < but_x2 + 200 and but_y2 < pos[1] < but_y2 + 50:
                    m_white.rect.x += randrange(1100, 1300)
                    robot.rect.x += randrange(1500, 1700)
                    robot2.rect.x += randrange(1800, 1900)
                    f = False
                if but_x < pos[0] < but_x + 200 and but_y < pos[1] < but_y + 50:
                    withdrawal_of_records()

        cnt2, scores = 0, 0
        pygame.display.flip()

background = Background()
runner = Runner()

while run:

    screen.fill(BLACK)
    cnt2 += 1
    clock.tick(FPS)

    for event in pygame.event.get():
        keys = pygame.key.get_pressed()

        if event.type == pygame.QUIT:
            run = False

        if event.type == pygame.KEYDOWN:
            runner.update(event.key)

        if keys[pygame.K_2]:
            paused = True

            while paused:
                for event in pygame.event.get():
                    if event.type == pygame.QUIT:
                        terminate()

                    keys = pygame.key.get_pressed()
                    if keys[pygame.K_RETURN]:
                        paused = False

                text('PRESS ENTER TO  CONTINUE THE GAME', 100, 100)
            pygame.display.flip()

    runner.update()
    m_white.update()
    robot.update()
    robot2.update()
    all_sprites.draw(screen)
    scores = cnt2 // 10
    text('scores: ' + str(scores), 800, 30)
    obstacles_group.draw(screen)

    while f:
        final_screen()

    pygame.display.flip()
pygame.quit()
quit()


'''
import sys
from collections import defaultdict
sys.setrecursionlimit(10000)
table = defaultdict(int)

def find(x):
    if table[x] == 0:
        table[x] = x + 1
        return x
    else:
        table[x] = find(table[x])
        return table[x]

def solution(k, room_number):
    result = []
    for i in room_number:
        result.append(find(i))
    return result
'''
def solution(k, room_number):
    result = []
    dic = dict()
    for i in room_number:
        cur = i
        visit = [cur]
        while cur in dic:
            cur = dic[cur]
            visit.append(cur)
        result.append(cur)
        for j in visit:
            dic[j] = cur + 1
    return result

카카오 문제모음/2019 카카오 개발자 겨울 인턴쉽/호텔 방 배정.py


from db import dbtypes as dbt
from typing import Any, Dict, List, Iterator, Sequence, Type, Union, Optional, get_type_hints

class TableMetadata:
    def __init__(self, table_class):

        type_hints:Dict[str, Any] = get_type_hints(table_class)
        self.table_name = type_hints['__table_name__'] if '__table_name__' in type_hints else table_class.__name__

        # generate columns and foregin keys
        self.columns:Dict[str, dbt.DataTypeBase] = {}
        _key_name:Optional[str] = None
        self.foreign_keys_table:Dict[str, TableBase] = {}
        for name, _type in type_hints.items():
            if name.startswith('__'): continue
            datatype = to_data_type(_type)
            self.columns[name] = datatype

            # If this column is primary key, save this key's name
            if datatype.info.primary:
                if _key_name is not None:
                    raise RuntimeError('Multiple primary key is not allowed.')
                _key_name = name

            # If this column is foreign key, append to list
            if datatype.info.link_table:
                self.foreign_keys_table[name] = datatype.info.link_table

        if _key_name is None:
            raise RuntimeError('Primary key not found.')

        self.key_column_name = _key_name

class TableBase:
    """ Base class of a Table in the database """

    @classmethod
    def metadata(cls):
        if not hasattr(cls, '__metadata__'):
            cls.__metadata__ = TableMetadata(cls)
        return cls.__metadata__

    @classmethod
    def show_create_table(cls) -> str:
        metadata = cls.metadata()
        table_name = metadata.table_name
        columns = metadata.columns
        fk_table = metadata.foreign_keys_table
        return (
            f'CREATE TABLE `{table_name}`(\n  ' + ', \n  '.join((
                *(f'`{name}` {dt.sql_expr}' for name, dt in columns.items()),
                *(
                    f'FOREIGN KEY `fk_{name}` (`{name}`) REFERENCES `{t.metadata().table_name}`(`{t.metadata().key_column_name}`)'
                    for name, t in fk_table.items()
                ),
            )) + '\n);'
        )

    @classmethod
    def select(cls, where, order, count, offset) -> Iterator:
        """ Select records from the database """

    @classmethod
    def select_one(cls, where) -> Iterator:
        """ Select just one record from the database
            If more than one records are found, throw a exception.
        """

    """ Instance methods """

    def load(self) -> None:
        """ Select (the latest version of) this record from the database """

    def save(self) -> None:
        """ Insert or update this record to the database """

    def insert(self) -> None:
        """ Insert this record as new record
            If the record already exists on the database, throw a exception.
        """

    def delete(self) -> None:
        """ Delete this record from the database """

class RawTable(TableBase):
    """ """

class Table(RawTable):
    """ """
    id: dbt.IDKey(auto_increment=True)

class UniqueTable(Table):
    """ """

    @classmethod
    def show_selsert(cls, arg_colnames:Optional[List[str]] = None) -> str:
        metadata = cls.metadata()
        table_name = metadata.table_name
        columns = metadata.columns
        key_name = metadata.key_column_name

        _v_colnames = {name for name in columns.keys() if name != key_name}

        if arg_colnames is not None:
            if len(arg_colnames) != len(set(arg_colnames)):
                raise RuntimeError('Duplicate argument column names.')
            if not all(colname in _v_colnames for colname in arg_colnames):
                raise RuntimeError('Unknown column(s) exist in argument column names.')
            v_colnames = arg_colnames
        else:
            v_colnames = list(_v_colnames)

        return (
             'DELIMITER //\n' +
            f'CREATE FUNCTION `selsert_{table_name}`(  \n' + ', '.join(
                f'v_{name} {columns[name].info.dbtype}' for name in v_colnames
            ) +
             ')\n' +
            f'RETURNS {columns[key_name].info.dbtype} DETERMINISTIC\n' +
             'BEGIN\n' +
               '@ret = (\n' +
                 f'SELECT `{key_name}` FROM `{table_name}`\n' +
                 f'WHERE ' + ' AND '.join(
                f'`{name}` = v_{name}' for name in v_colnames
            ) +
             '  );\n' +
             '  IF @ret IS NOT NULL THEN\n' +
             '    RETURN @ret;\n' +
             '  END IF;\n' +
            f'  INSERT INTO `{key_name}`(' + ', '.join(f'`{name}`' for name in v_colnames) + ') \n' +
             '    VALUES(' + ', '.join(f'v_{name}' for name in v_colnames) + ');\n' +
             '  RETURN LAST_INSERT_ID();\n' +
             'END//\n' +
             'DELIMITER ;\n'
        )
#
#         @classmethod
#         def show_tables_selsert_st(cls, args:Sequence[Union[str, Tuple[str, Any]]]) -> str:
#             metadata = cls.metadata()
#             table_name = metadata.table_name
#             arg_sts = []
#             for arg in args:
#                 if isinstance(arg, str):
#                     st.append(f'v_{arg}')
#                 elif isinstance(arg, tuple) and len(arg) == 2:
#                     st.append()
#
#             return f'selsert_{table_name}(\n  ' + ', \n  '.join(arg_sts) + ');\n'
#

def create_tables(*tables:List[Type]):
    for table in tables:
        # print(f'# {table.__name__}')
        # type_hints = get_type_hints(table)
        # for k, v in type_hints.items():
        #     print(f'    {k}: {v}')
        print(table.show_create_table())
        if issubclass(table, UniqueTable):
            print(table.show_selsert())
        print('')

def to_data_type(t:Any, **options):

    if isinstance(t, type):

        # if `t` is already DataType
        if issubclass(t, dbt.DataTypeBase):
            if options:
                return dbt.DataType(t, **options)
            return t

        if issubclass(t, TableBase):
            return dbt.ForeignKey(t)

    # assume typing.Optional type
    if getattr(t, '__origin__') == Union:
        if len(t.__args__) != 2:
            raise RuntimeError('This union type is not available.')
        if t.__args__[0] == type(None):
            return to_data_type(t.__args__[1], nullable=True)
        elif t.__args__[1] == type(None):
            return to_data_type(t.__args__[0], nullable=True)
        else:
            raise RuntimeError('This union type is not available.')

    raise RuntimeError('Failed to convert to data type.')


from django.contrib import admin
from django.urls import path, include
from django.conf.urls import url
from booker import views
from django.conf.urls.static import static
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseNotFound
from django.shortcuts import render

urlpatterns = [
    path('admin', admin.site.urls),
    path('', views.Home.as_view(), name='home'),
    path('upcomingcampaigns/', views.BookvenueList.as_view(),
         name='upcoming_campaigns'),
    path('createcampaign/', login_required(views.CreateCampaign.as_view()),
         name='create_campaign'),
    path('dashboard/', views.CampaignList.as_view(), name='dashboard'),
    path('venues/', views.Venue.as_view(), name='venues'),
    path('signup/', views.register_request, name="signup"),
    path('login/', views.login_request, name="login"),
    path('logout/', views.logout_request, name="logout"),
    path('profile/', views.Profile.as_view(), name="profile"),
    path('summernote/', include('django_summernote.urls')),
    path(
        'delete_campaign/<int:id>/',
        login_required(views.DeleteCampaign.as_view()),
        name='delete_campaign'
    ),
    path(
        'edit_campaign/<int:id>/',
        login_required(views.EditCampaign.as_view()),
        name='edit_campaign'
    ),
    path(
        'delete_venue/<int:id>/',
        login_required(views.DeleteVenue.as_view()),
        name='delete_venue'
    ),
    path(
        'edit_venue/<int:id>/',
        login_required(views.EditVenue.as_view()),
        name='edit_venue'
    ),
    path('<path:invalid_path>', views.handler404),  # Catch all invalid URLs
]

handler404 = 'booker.views.handler404'

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)


class Tree:
    """
    >>> t = Tree(3, [Tree(2, [Tree(5)]), Tree(4)])
    >>> t.label
    3
    >>> t.branches[0].label
    2
    >>> t.branches[1].is_leaf()
    True
    """
    def __init__(self, label, branches=[], score = 0, keywords = []):
        for b in branches:
            assert isinstance(b, Tree)

        self.label = label
        self.score = score
        self.keywords = keywords
        self.branches = list(branches)
        self.used = False
        self.datelist = []

    def is_leaf(self):
        return not self.branches

    def __contains__(self, e):
        """
        Determine whether an element exists in the tree.

        >>> t1 = Tree(1)
        >>> 1 in t1
        True
        >>> 8 in t1
        False
        >>> t2 = Tree(3, [Tree(2, [Tree(5)]), Tree(4)])
        >>> 6 in t2
        False
        >>> 5 in t2
        True
        """
        if self.label == e:
            return True
        for b in self.branches:
            if e in b:
                return True
        return False

    def __repr__(self):
        if self.branches:
            branch_str = ', ' + repr(self.branches)
        else:
            branch_str = ''
        return 'Tree({0}{1})'.format(self.label, branch_str)

    def __str__(self):
        def print_tree(t, indent=0):
            tree_str = '  ' * indent + str(t.label) + "\n"
            for b in t.branches:
                tree_str += print_tree(b, indent + 1)
            return tree_str
        return print_tree(self).rstrip()


from random import randint
import pdb

from config import NUM_PERSONS, MAX_LOCATION, NUM_ITERATION_PER_DAY, NUM_HOSPITALS, NUM_BEDS_PER_HOSPITAL, NUM_INITIAL_INFECTED, NUM_ITERATIONS_TO_RUN

from living_state import *
from person import Person
from hospital import Hospital
from covid19 import Covid19
from get_stats import get_people_stats
from contact import contact

def create_hospitals():
    all_hospitals = []
    for j in range(NUM_HOSPITALS):
        locations_x = []
        locations_y = []

        hospital_location_x = randint(10, MAX_LOCATION)
        hospital_location_y = randint(10, MAX_LOCATION)

        while (hospital_location_x in locations_x and hospital_location_y in locations_y):
            hospital_location_x = randint(10, MAX_LOCATION)
            hospital_location_y = randint(10, MAX_LOCATION)
        all_hospitals.append(Hospital(j, NUM_BEDS_PER_HOSPITAL, [hospital_location_x, hospital_location_y]))
    return all_hospitals

def create_people():
    all_people = []
    total_infected = 5
    infected_indices = []
    for j in range(total_infected):
        next_infected = randint(0, NUM_PERSONS)
        while(next_infected in infected_indices):
            next_infected = randint(0, NUM_PERSONS)
        infected_indices.append(next_infected)

    for j in range(NUM_PERSONS):
        if j in infected_indices:
            next_person = Person(j, MAX_LOCATION, INFECTED, active_probab = 0.6)
            next_person.infect(Covid19(), 0)
            all_people.append(next_person)
        else:
            next_person = Person(j, MAX_LOCATION, UNINFECTED, active_probab = 0.6)
            all_people.append(next_person)

    return all_people

def run_iters(num_iterations):
    all_hospitals = create_hospitals()
    all_people = create_people()
    all_hospital_full = False

    for i in range(num_iterations):
        for j in range(NUM_PERSONS):
            all_people[j].move()
            all_people[j].are_symptoms_visible(i)
            if all_people[j].shows_symptom:

                # Checking if there is any space left in hospital
                all_hospital_full = True
                for a_hospital in all_hospitals:
                    if not a_hospital.is_full:
                        all_hospital_full = False
                        break

                # If all hospitals are not full then
                if not all_hospital_full:
                    for a_hospital in all_hospitals:
                        if not a_hospital.is_full:
                            hospital_location = a_hospital.location
                            a_hospital.occupy_bed()
                            break
                    all_people[j].hospitalize(hospital_location)

                # otherwise quarantine the person
                else:
                    all_people[j].no_hospital_quarantine()

        for j in range(NUM_PERSONS):
            for k in range(NUM_PERSONS):
                if j != k:
                    contact(all_people[j], all_people[k], i)

        for j in range(NUM_PERSONS):
            if all_people[j].status == NO_HOSPITAL_QUARANTINED or all_people[j].is_hospitalized:
                all_people[j].dead_immune_delay(i)

        get_people_stats(all_people, i)

if __name__ == "__main__":
    run_iters(NUM_ITERATIONS_TO_RUN)


from django.conf import settings
from django.shortcuts import redirect, render

class login_required_middleware:
    """ This middleware takes care of anonymous users trying to visit links that requires an user to be logged-in.
        Also, non-admin users trying to access the admin panel
    """

    admin_base_path = '/admin/'

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        """ process_view() is called just before Django calls the view """

        assert hasattr(request, 'user'), "assertion error in login_required_middleware()"
        path = request.path_info
        if request.user.is_authenticated:
            if not request.user.is_admin():
                if path == self.admin_base_path:
                    return render(request, 'trespass.html', {})
            if path == '/':
                return redirect('/home/')
        else:
            if path not in settings.LOGIN_EXEMPT_URL:
                return redirect(settings.LOGIN_URL)


from django.urls import path

from HelloTemplate import views

urlpatterns = [
    path('hello', views.hello),
    path('get_students', views.get_students),
    path('home/', views.home),
    path('home_mine/', views.home_mine),
]


import algorithms.linear_reg.linearreg as lr
import algorithms.linear_reg.plotdata as pd
import numpy as np
import matplotlib.pyplot as plt

"""This is the main driver file to test the rest machine learning modules."""

#loads the data1_1.txt into data variable
#The data is a 97 x 2 matrix
data = np.genfromtxt("datas/data1_1.txt", delimiter=',')

#loading data to X and y - the first column corresponds to input and the second column corresponds to output
#X becomes a 97x2 matrix with first column as 1s and y becomes a 97x1 matrix
X=np.c_[np.ones(data.shape[0]),data[:,0]]
y=np.c_[data[:,1]]
print(data)

#plotting X and y
pd.plotData(X, y, 'x-label', 'y-label')
plt.close()

#initialise theta to zeros - theta is a 2 x 1 matrix
#ComputeCost computes the cost of the linear regression
theta =[[0],[0]]
J = lr.ComputeCost(X, y, theta)
print('The cost of the hypothesis created with theta as 0,0 : ')
print(J)

iteration = 1500
alpha = 0.01

#theta is the optimized theta after 1500 iterations and J_plot is the values of 1500 cost with theta after every iteration
#theta is the same 2 x 1 matrix and J_plot has 1500 values in a array
theta, J_plot= lr.gradientDescent(X, y, theta, iteration, alpha)

#plotting the cost of hypothesis in 1500 iterationset
pd.plotDataJ('x-label', 'y-label', J_plot)
#the optimised theta is
print('The optimised theta is : ')
print(theta)

#new cost must decrease
J = lr.ComputeCost(X,y,theta)
print('The new cost after the optimised theta is : ')
print(J)

#plotting the predicted function i.e. theta0*x0 + theta1*x1
#set the range for which hypothesis is to be plotted
range_x = np.arange(30)
#calculating the formula of hypothesis with the new theta
hx = theta[0]+theta[1]*range_x
pd.plotDataH(X, y, 'x-label', 'y-label', hx, range_x)

#using scikit-learn to plot the same and comapring both the values
pd.plotDataSK(X, y, range_x, hx)

#predicting profits - theta(T).x
print(' The predicted value for custom x is : ')
print(theta.T.dot([1, 3.5])*10000)

#plotting cost for each value of theta and plotting a 3D graph of the same
pd.plotDataCOST(X, y)

""" Contour plots are still to be completed"""


opcion=0
num1=int(input("ingresa un numero 1"))
num2=int(input("ingresa un numero 2"))
while True:
    print("""Opciones:
    1)Suma
    2)Resta
    3)Salir""")
    opcion=int(input("ingresa la operacion a realiar"))
    if opcion == 1:
        print("la suma es: ", num1+num2)
        print("¿Desea realizar otra operacion? s/n")
        rpta=input()
        if rpta=="s":
            continue
    elif opcion == 2:
        print("la resta es : ", num1-num2)
    elif opcion==3:
        print("adios")
        break


def rotation_piece(target, idx_lst):
    redirected_idx = sorted([(y - idx_lst[0][0], x - idx_lst[0][1]) for y, x in idx_lst])   # (0, 0)에 맞추기
    pieces.append(redirected_idx)
    tmp = [[0] * M for _ in range(M)]
    for i in range(M):  # 조각 리스트 90도 회전
        for j in range(M):
            tmp[j][M - i - 1] = target[i][j]
    return tmp

def count(y, x, delta):
    for dy, dx in delta:
        ny, nx = y + dy, x + dx
        if 0 <= nx < N and 0 <= ny < N:
            if puzzle[ny][nx] == '#':
                return
        else:
            return
    return True

N, M = 10, 4
piece = [list(input()) for _ in range(M)]
pieces = []
for _ in range(M):  # 4번 회전함으로썩 90도, 180도, 270도 회전 후 다시 0도까지 회전
    piece_idx = []
    for i in range(M):
        for j in range(M):
            if piece[i][j] == '$':
                piece_idx.append((i, j))
    piece = rotation_piece(piece, piece_idx)

pieces = list(set([tuple(set(piece)) for piece in pieces])) # 회전해도 같은 모양 없애주기

puzzle = [list(input()) for _ in range(N)]
ans = 0
for i in range(N):
    for j in range(N):
        if puzzle[i][j] == '_':
            for sub_piece in pieces:
                stack = [(i, j)]
                if count(i, j, sub_piece):
                    ans += 1
print(ans)

차윤이의 도형 끼우기.py


import os
import shutil
import math
import warnings
import numpy as np
import pandas as pd
from GlobalParameters import DefaultParam
from Preprocess import Utilities
from python_speech_features import sigproc
from FeatureExtraction import ITheoryDomain, WaveletDomain, FrequencyDomain, TimeDomain
warnings.filterwarnings("ignore")
# Overriding the paths
DefaultParam.DATA_PATH = os.path.join(os.path.dirname(os.getcwd()), 'Storage', 'RawDataGenuine')
DefaultParam.FEATURE_PATH = os.path.join(os.path.dirname(os.getcwd()), 'Storage', 'FeatureFilesGenuine')

USER_LIST = os.listdir(DefaultParam.DATA_PATH)
USER_LIST = sorted(USER_LIST)
INVALID_USER_LIST = []
VALID_USER_LIST = set(USER_LIST) - set(INVALID_USER_LIST)
# print('Total user in VALID_USER_LIST: ', len(VALID_USER_LIST))
# Sorting the list of users for the sake of keeping track how many finished
VALID_USER_LIST = sorted(VALID_USER_LIST)
print('VALID_USER_LIST',VALID_USER_LIST)
for USER in VALID_USER_LIST:  # For all user
    # print('Working on ', USER)
    # Creatin a folder for the current user in thr feature_files location
    USER_PATH_IN = os.path.join(DefaultParam.DATA_PATH, USER)
    USER_PATH_OUT = os.path.join(DefaultParam.FEATURE_PATH, USER)
    if os.path.exists(USER_PATH_OUT):
        raise FileExistsError("The output directory already exists.. delete manually")
    else:
        os.mkdir(USER_PATH_OUT)
        print(f'###############################Created a new directory!')

    DefaultParam.MODES = ['Training', 'Testing']
    for MODE in DefaultParam.MODES:  # For training and testing
        MODE_PATH_IN = os.path.join(DefaultParam.DATA_PATH, USER, MODE)
        MODE_PATH_OUT = os.path.join(DefaultParam.FEATURE_PATH, USER, MODE)
        FREQ_PATH = os.path.join(DefaultParam.FEATURE_PATH, USER, MODE, 'FrequencyFeatures')
        IT_PATH = os.path.join(DefaultParam.FEATURE_PATH, USER, MODE, 'ITheoryFeatures')
        TIME_PATH = os.path.join(DefaultParam.FEATURE_PATH, USER, MODE, 'TimeFeatures')
        WAVE_PATH = os.path.join(DefaultParam.FEATURE_PATH, USER, MODE, 'WaveletFeatures')
        # Create the feature director if it does not exists
        try:  # Create target Directory
            os.mkdir(MODE_PATH_OUT)
            os.mkdir(FREQ_PATH)
            os.mkdir(IT_PATH)
            os.mkdir(TIME_PATH)
            os.mkdir(WAVE_PATH)
            # print("Feature directory created at " + FREQ_PATH)
        except FileExistsError:
            print("Directories already exists")
        for SENSOR in DefaultParam.SENSOR_FILE_LIST:  # for all sensors
            CURR_SENSOR_PATH_IN = os.path.join(MODE_PATH_IN, SENSOR)
            CS_FREQ_PATH = os.path.join(FREQ_PATH, 'feat_' + SENSOR.replace(".txt",".csv"))
            CS_IT_PATH = os.path.join(IT_PATH, 'feat_' + SENSOR.replace(".txt",".csv"))
            CS_TIME_PATH = os.path.join(TIME_PATH, 'feat_' + SENSOR.replace(".txt",".csv"))
            CS_WAVE_PATH = os.path.join(WAVE_PATH, 'feat_' + SENSOR.replace(".txt",".csv"))
            # print('CURR_SENSOR_PATH',CURR_SENSOR_PATH_IN)

            # The old data had different sampling rates.. here computing the sampling rate dynamically
            if USER in DefaultParam.OLD_USER_LIST:
                RAW_DATA = pd.read_csv(CURR_SENSOR_PATH_IN, sep=',', header=None, names=DefaultParam.OLD_COLUMN_NAMES)
                samplerate = Utilities.get_sampling_rate(RAW_DATA)
            else:
                RAW_DATA = pd.read_csv(CURR_SENSOR_PATH_IN, sep=',', header=None, names=DefaultParam.NEW_COLUMN_NAMES)
                samplerate = DefaultParam.NEW_SAMPLING_RATE
            print('sampling rate for ' + CURR_SENSOR_PATH_IN + ': ' + str(samplerate))

            ######################################################################
            signalX = RAW_DATA['x']
            signalY = RAW_DATA['y']
            signalZ = RAW_DATA['z']

            # Sliding window based cutting of the signal
            framesX = sigproc.framesig(signalX, DefaultParam.WINLENGTH * samplerate, DefaultParam.WINSTEP * samplerate)
            framesY = sigproc.framesig(signalY, DefaultParam.WINLENGTH * samplerate, DefaultParam.WINSTEP * samplerate)
            framesZ = sigproc.framesig(signalZ, DefaultParam.WINLENGTH * samplerate, DefaultParam.WINSTEP * samplerate)

            if framesX.shape[1] > 64 and framesX.shape[1] < 128:
                FFTLENGTH = 128
            elif framesX.shape[1] > 128 and framesX.shape[1] < 256:
                FFTLENGTH = 256
            else:
                FFTLENGTH = 512

            # The  sigproc.framesig function fills zeroes in the last unavailable points
            # we dont want that
            framesX = framesX[:-1, :]
            framesY = framesY[:-1, :]
            framesZ = framesZ[:-1, :]

            fmatrix_freq = []
            fmatrix_itheory = []
            fmatrix_time = []
            fmatrix_wavelet = []

            for frameX, frameY, frameZ in zip(framesX, framesY, framesZ):
                ############SMOOTHING THE DATA BEFORE ANY FEATURE EXTRACTION
                ############EVEN BEFORE COMPUTATION OF THE M -- ELSE ERROR PROPOGATE
                # smoothing the signal with 5% of total obtained in every second
                percent_smooth = 0.05
                smoothing_span = math.ceil(samplerate * percent_smooth + 1)
                framesX = Utilities.moving_average(frameX, smoothing_span)
                framesY = Utilities.moving_average(frameY, smoothing_span)
                framesZ = Utilities.moving_average(frameZ, smoothing_span)

                frameM = np.sqrt(frameX*frameX + np.multiply(frameY, frameY) + np.multiply(frameZ, frameZ))

                fdnamesX, fdfvectorX = FrequencyDomain.getall_fd_features(frameX, DefaultParam.NUM_BINS_FOR_FFT,
                                                                          samplerate, DefaultParam.WINLENGTH,
                                                                          DefaultParam.WINSTEP, FFTLENGTH)
                fdnamesY, fdfvectorY = FrequencyDomain.getall_fd_features(frameY, DefaultParam.NUM_BINS_FOR_FFT,
                                                                          samplerate, DefaultParam.WINLENGTH,
                                                                          DefaultParam.WINSTEP, FFTLENGTH)
                fdnamesZ, fdfvectorZ = FrequencyDomain.getall_fd_features(frameZ, DefaultParam.NUM_BINS_FOR_FFT,
                                                                          samplerate, DefaultParam.WINLENGTH,
                                                                          DefaultParam.WINSTEP, FFTLENGTH)
                fdnamesM, fdfvectorM = FrequencyDomain.getall_fd_features(frameM, DefaultParam.NUM_BINS_FOR_FFT,
                                                                          samplerate, DefaultParam.WINLENGTH,
                                                                          DefaultParam.WINSTEP, FFTLENGTH)

                itdnamesX, itdfvectorX = ITheoryDomain.getall_itd_features(frameX)
                itdnamesY, itdfvectorY = ITheoryDomain.getall_itd_features(frameY)
                itdnamesZ, itdfvectorZ = ITheoryDomain.getall_itd_features(frameZ)
                itdnamesM, itdfvectorM = ITheoryDomain.getall_itd_features(frameM)

                tdnamesX, tdfvectorX = TimeDomain.getall_td_feature(frameX)
                tdnamesY, tdfvectorY = TimeDomain.getall_td_feature(frameY)
                tdnamesZ, tdfvectorZ = TimeDomain.getall_td_feature(frameZ)
                tdnamesM, tdfvectorM = TimeDomain.getall_td_feature(frameM)

                wdfnamesX, wdfvectorX = WaveletDomain.wavelet_features(frameX, DefaultParam.MOTHER_WAVELET,
                                                                       DefaultParam.WAVEDEC_LEVEL)
                wdfnamesY, wdfvectorY = WaveletDomain.wavelet_features(frameY, DefaultParam.MOTHER_WAVELET,
                                                                       DefaultParam.WAVEDEC_LEVEL)
                wdfnamesZ, wdfvectorZ = WaveletDomain.wavelet_features(frameZ, DefaultParam.MOTHER_WAVELET,
                                                                       DefaultParam.WAVEDEC_LEVEL)
                wdfnamesM, wdfvectorM = WaveletDomain.wavelet_features(frameM, DefaultParam.MOTHER_WAVELET,
                                                                       DefaultParam.WAVEDEC_LEVEL)

                finalfdfvs = fdfvectorX + fdfvectorY + fdfvectorZ + fdfvectorM
                finalitdfvs = itdfvectorX + itdfvectorY + itdfvectorZ + itdfvectorM
                finaltdfvs = tdfvectorX + tdfvectorY + tdfvectorZ + tdfvectorM
                finalwfdfvs = wdfvectorX + wdfvectorY + wdfvectorZ + wdfvectorM

                fmatrix_freq.append(finalfdfvs)
                fmatrix_itheory.append(finalitdfvs)
                fmatrix_time.append(finaltdfvs)
                fmatrix_wavelet.append(finalwfdfvs)

            fdnames = fdnamesX + fdnamesY + fdnamesZ + fdnamesM
            itdnames = itdnamesX + itdnamesY + itdnamesZ + itdnamesM
            tdnames = tdnamesX + tdnamesY + tdnamesZ + tdnamesM
            wdfnames = wdfnamesX + wdfnamesY + wdfnamesZ + wdfnamesM
            feature_names = fdnames + itdnames + tdnames + wdfnames

            fmatrix_freq = pd.DataFrame(fmatrix_freq, columns=fdnames)
            fmatrix_itheory = pd.DataFrame(fmatrix_itheory, columns=itdnames)
            fmatrix_time = pd.DataFrame(fmatrix_time, columns=tdnames)
            fmatrix_wavelet = pd.DataFrame(fmatrix_wavelet, columns=wdfnames)
            #
            # fmatrix_freq.to_csv(CS_FREQ_PATH)
            # fmatrix_itheory.to_csv(CS_IT_PATH)
            # fmatrix_time.to_csv(CS_TIME_PATH)
            # fmatrix_wavelet.to_csv(CS_WAVE_PATH)


#!/usr/bin/env python
# -*- coding: utf-8 -*-
#遺伝的アルゴリズム

import pygame, random
import sys #sysモジュール: コマンドライン引数受け取りのため
import math
import copy

import ga_puyo_ as puyo

args = sys.argv # コマンドライン引数受け取り
ai = True if len(args) >= 2 else False # コマンドライン引数（=seed値）でAIモード

IND = 6 # 個体数()
GENE = 300 # 遺伝子数()

class Game(object):
    SCREEN_SIZE = (640, 480)

    def __init__(self): #コンストラクタ(インスタンス生成時自動で呼び出される)
        pygame.init() #pygameモジュール初期化
        self.screen = pygame.display.set_mode(self.SCREEN_SIZE)

        self.gem = {"R":pygame.image.load("resource/r.png").convert_alpha(),
                    "G":pygame.image.load("resource/g.png").convert_alpha(),
                    "B":pygame.image.load("resource/b.png").convert_alpha(),
                    "Y":pygame.image.load("resource/y.png").convert_alpha()}

        #self.player1 = puyo.Puyopuyo(puyo.F)
        self.player1 = puyo.Puyopuyo("")
        self.player1.controller = {"left":pygame.K_LEFT,
                         "down":pygame.K_DOWN,
                         "right":pygame.K_RIGHT,
                         "roll":pygame.K_a,
                         "esc":pygame.K_ESCAPE,
                         "back":pygame.K_BACKSPACE}

        self.control_time = 1 if ai else 400
        self.update_time = 2 if ai else 1200
        self.generation = 0 # 世代
        self.ind = [[0 for i in range(GENE)] for j in range(IND)] # 遺伝子情報
        self.ind_num = 0 # 個体番号
        self.gene_num = 0 # 遺伝子番号
        self.i_score = [0] * IND # 得点
        self.i_chain = [0] * IND # 最大連鎖数
        for i in range(IND):
            for j in range(GENE):
                self.ind[i][j] = random.randrange(24)

        self.player1.OFFSET = (100, 100)
        self.screen.fill((100, 100, 100),
                         (self.player1.OFFSET[0], self.player1.OFFSET[1], self.player1.WIDTH*24, self.player1.HEIGHT*24))
        self.draw(self.player1)
        pygame.display.update()

        self.clock = pygame.time.Clock()

    def draw(self, p):
        x_offset, y_offset = p.OFFSET
        for y, row in enumerate(p.puyos):
            for x, color in enumerate(row):
                if color != " ":
                    self.screen.blit(self.gem[color], (x_offset + x*24, y_offset + y*24))
        if p.falling:
            for i in range(2):
                y, x = p.falling[i]["pos"]
                if y >= 0 and x >= 0:
                    self.screen.blit(self.gem[p.falling[i]["color"]], (x_offset + x*24, y_offset + y*24))

    def command(self): #1-24の数字を対応した操作で返す(左,右,回転)
        cmd = self.ind[self.ind_num][self.gene_num]
        if cmd % 6 < 3: # 左
            left = cmd % 6 + 1
            right = 0
        else: # 右
            left = 0
            right = cmd % 6 - 1
        roll = int(cmd / 6)
        self.gene_num += 1
        if self.gene_num == GENE:
            self.gene_num = 0

        return left,right,roll

    def play(self):
        counter = 0
        while True:
            counter += 1

            # exit game
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    sys.exit()

            # control puyo
            if self.player1.falling and not (counter % self.control_time):
                keys = pygame.key.get_pressed()
                col1, row1 = self.player1.falling[0]["pos"]
                col2, row2 = self.player1.falling[1]["pos"]
                a1 = col1 - col2
                a2 = row1 - row2

                if keys[self.player1.controller["esc"]]:
                    pygame.quit()

                if ai and self.player1.cmd_flag:
                    self.player1.cmd_flag = False
                    left,right,roll = self.command()
                else:
                    left = 0
                    right = 0
                    roll = 0
                    if keys[self.player1.controller["left"]]:
                        left = 1
                    if keys[self.player1.controller["right"]]:
                        right = 1
                    if keys[self.player1.controller["roll"]]:
                        roll = 1
                while roll > 0:
                    col1, row1 = self.player1.falling[0]["pos"]
                    col2, row2 = self.player1.falling[1]["pos"]
                    a1 = col1 - col2
                    a2 = row1 - row2
                    if (row1+a1 in (-1, self.player1.WIDTH)) or col1-a2 == self.player1.HEIGHT or self.player1.puyos[col1-a2][row1+a1] != " ":
                        pass
                    else:
                        self.player1.falling[1]["pos"] = (col1-a2, row1+a1)
                    roll -= 1
                while left > 0:
                    col1, row1 = self.player1.falling[0]["pos"]
                    col2, row2 = self.player1.falling[1]["pos"]
                    a1 = col1 - col2
                    a2 = row1 - row2
                    if (row1 > 0 and self.player1.puyos[col1][row1-1] == " ") and (row2 > 0 and self.player1.puyos[col2][row2-1] == " "):
                        self.player1.falling[0]["pos"] = (col1, row1-1)
                        self.player1.falling[1]["pos"] = (col2, row2-1)
                    left -= 1
                while right > 0:
                    col1, row1 = self.player1.falling[0]["pos"]
                    col2, row2 = self.player1.falling[1]["pos"]
                    a1 = col1 - col2
                    a2 = row1 - row2
                    if (row1 < self.player1.WIDTH-1 and self.player1.puyos[col1][row1+1] == " ") and (row2 < self.player1.WIDTH-1 and self.player1.puyos[col2][row2+1] == " "):
                        self.player1.falling[0]["pos"] = (col1, row1+1)
                        self.player1.falling[1]["pos"] = (col2, row2+1)
                    right -= 1
                if keys[self.player1.controller["down"]] or ai:
                    while (col1 < self.player1.HEIGHT-1 and self.player1.puyos[col1+1][row1] == " ") and (col2 < self.player1.HEIGHT-1 and self.player1.puyos[col2+1][row2] == " "):
                        self.player1.falling[0]["pos"] = (col1+1, row1)
                        self.player1.falling[1]["pos"] = (col2+1, row2)
                        col1, row1 = self.player1.falling[0]["pos"]
                        col2, row2 = self.player1.falling[1]["pos"]

            # update puyos' position
            update = True

            if not (counter % self.update_time):
                update = self.player1.update()

            if self.i_chain[self.ind_num] < self.player1.max_rensa:
                self.i_chain[self.ind_num] = self.player1.max_rensa
                self.i_score[self.ind_num] += self.player1.score
            if ai and ((not update) or self.gene_num == GENE-1):
                update = True
                self.i_score[self.ind_num] = self.gene_num
                print(self.generation, self.i_score[self.ind_num], self.i_chain[self.ind_num])
                if self.ind_num == IND-1:
                    random.seed(None)
                    # その世代の各情報を調べる
                    max_score = 0 # 最大連鎖の中での最大得点
                    max_chain = max(self.i_chain) # 最大連鎖
                    e = 0
                    for i in range(IND):
                        if self.i_chain[i] == max_chain and self.i_score[i] > max_score:
                            e = i
                            max_score = self.i_score[i]
                    elite = copy.deepcopy(self.ind[e])
                    print('best is', e)
                    # 次の世代に遺伝子を渡す
                    for i in range(IND):
                        if i < IND - 1: # (IND-1)個は二点交叉
                            r1 = random.randrange(0, GENE-1)
                            r2 = random.randrange(r1,GENE)
                            for j in range(GENE):
                                r = random.randrange(2)
                                if r == 0:
                                    if r1 < j and j < r2:
                                        self.ind[i][j] = self.ind[i+1][j]
                                    else:
                                        self.ind[i][j] = elite[j]
                                else:
                                    if r1 < j and j < r2:
                                        self.ind[i][j] = elite[j]
                                    else:
                                        self.ind[i][j] = self.ind[i+1][j]
                            r = random.randrange(2)
                            if r == 0: # 稀に変異を起こす
                                r = random.randrange(9) + 1
                                for j in range(r):
                                    self.ind[i][random.randrange(max_score)] = random.randrange(24)
                        else: # 最良個体を１つだけ引き継ぐ
                            self.ind[i] = copy.deepcopy(elite)
                        self.i_score[i] = 0
                        self.i_chain[i] = 0

                    self.generation += 1
                    self.ind_num = 0
                    if self.generation % 10 == 0: # データを保存
                        if self.generation == 10:
                            file = open('result2.txt', 'w')
                        else:
                            file = open('result2.txt', 'a')
                        savedata = 'generation:' + str(self.generation) + '\n_chain:' + str(max_chain) + '\n_score:' + str(max_score) + '\n'
                        file.write(savedata)
                        file.close()
                else:
                    self.ind_num += 1
                self.gene_num = 0

                if ai:
                    random.seed(int(args[1]))
                self.player1 = puyo.Puyopuyo("") # 初期化
                self.player1.controller = {"left":pygame.K_LEFT,
                                 "down":pygame.K_DOWN,
                                 "right":pygame.K_RIGHT,
                                 "roll":pygame.K_a,
                                 "esc":pygame.K_ESCAPE,
                                 "back":pygame.K_BACKSPACE}
                self.player1.OFFSET = (100, 100)

            # update screen
            self.screen.fill((100, 100, 100),
                             (self.player1.OFFSET[0],
                              self.player1.OFFSET[1],
                              self.player1.WIDTH*24,
                              self.player1.HEIGHT*24)
                             )

            keys_d = pygame.key.get_pressed()
            if not ai:
                fps = 10
                self.draw(self.player1)
                pygame.display.update()
            if ai and keys_d[self.player1.controller["back"]]:
                fps = 8
                self.draw(self.player1)
                pygame.display.update()
            else:
                fps = 10000
            self.clock.tick(fps)

            if counter == 2400:
                counter = 0

if __name__ == "__main__":
    Game().play()


import os.path
from datetime import datetime
from lib.Bocsar import Bocsar
from lib.ExcelParser import ExcelParser

class ImportResponse:
    def __init__(self):
        self.USED_TO_UPDATED_BEFORE = 10
        self.UPDATE_SUCCESSFULLY = 11
        self.LGA_HAS_NO_DATA = 20

    def get(self, lga):
        assumedDirectory = './storage/' + lga.replace(' ', '').lower() + 'lga.xlsx'
        if os.path.isfile(assumedDirectory):
            return self.USED_TO_UPDATED_BEFORE, 'LGA data used to be updated before', \
                   datetime.fromtimestamp(os.path.getmtime(assumedDirectory))
        else:
            bocsar = Bocsar()
            file = bocsar.downloadLgaExcel(lga.replace(' ', '').lower())
            if file:
                parser = ExcelParser(file)
                parser.write()
                return self.UPDATE_SUCCESSFULLY, 'LGA data update successfully', \
                       datetime.fromtimestamp(os.path.getmtime(file))
            else:
                return self.LGA_HAS_NO_DATA, 'LGA has no data', datetime.now()


from time import gmtime, strftime
from bottle import route, get, run, post, request

@post('/get')
def index():
    rulename = request.forms.get('rulename')
    f = open(rulename, 'rb')
    rule = f.read()
    f.close()
    return rule

@post('/put')
def index():
    recivedt = strftime('%Y-%m-%d %H:%M:%S', gmtime())
    rulename = request.forms.get('rulename')
    filename = request.forms.get('filename')
    hostname = request.forms.get('hostname')
    f = open("results.txt", "a")
    f.write("%s,%s,%s,%s\r\n" % (recivedt, hostname, rulename, filename))
    f.close()
    return ""

run(host='192.168.1.68', port=8080)


'''
SERVER of Jake's Distributed TD3 implementation. I guess call it Distr Twin Delayed DDPG
DTD3. This is done to transition to a recurrent version.

This server is essentially the replay buffer, maintained as a SumTree structure and prioritized, that
maintains and operates copies of the Q-nets and policy nets and all actors using Ray.

This implements:
- value function rescaling
- TD3 Q-val minimization of approximation errors
- prioritized experience replay
- n-step returns

TODO: optimize batch sample building to increase throughput. Optimal would be about 50x greater than current.
- this would likely need leaving about 50 cores open for that job & multiprocess it
- include a README for operation
'''

from concurrent import futures
import logging

import grpc

import dtd3_pb2
import dtd3_pb2_grpc

import time
import json
import numpy as np
import os
import math
import numpy as np
import multiprocessing
import warnings
warnings.filterwarnings("ignore", category=FutureWarning)
#import gym

from envs.ADCS_gym_cont import AttitudeControlEnv

# only doing this so we dont see that annoying pickle warning. Ray uses pickle. fix in future: send as arrays
# and then iterate thru the state_dicts and cast to FloatTensors like I do in UpdateNetworks().
warnings.filterwarnings("ignore", category=FutureWarning)
import torch
warnings.filterwarnings("ignore", category=FutureWarning)
import torch.nn as nn
warnings.filterwarnings("ignore", category=FutureWarning)
import torch.nn.functional as F
warnings.filterwarnings("ignore", category=FutureWarning)
import ray

if os.environ.get('https_proxy'):
    del os.environ['https_proxy']
if os.environ.get('http_proxy'):
    del os.environ['http_proxy']

# -----------
max_timesteps = 500        # max timesteps in one episode
env = AttitudeControlEnv(torque_scale=0.5, steps=max_timesteps)

device = 'cpu'

max_episodes = 1000000   # for when we do beta annealing eventually
num_cores = multiprocessing.cpu_count()

print(f'num cores: {num_cores}')

num_actors = 8

value_fxn_epsilon = 0.001
n_step_return = 5   # n-step return to use
rescale_value_fxn = False

num_episodes_per_act = 2   # number episodes each actor runs locally before rechecking for state dict

gamma = 0.99

num_episodes_for_monitor = 10

buffer_max_size = 2**21   # must be power of 2
buffer_alpha = 0.6
buffer_beta = 0.4

batch_size = 128

max_exploration_noise = 0.3
min_exploration_noise = 0.01

state_dim = 11
action_dim = 3
max_action = float(1)
exploration_noises = np.linspace(min_exploration_noise, max_exploration_noise, num_actors)

ray.init(num_cpus=num_actors, num_gpus=0)
# -----------

class Node:
    def __init__(self, left, right, is_leaf=False, idx=None, exp_tuple=None):
        self.left = left
        self.right = right
        self.is_leaf = is_leaf
        if not self.is_leaf:
            self.value = self.left.value + self.right.value
        self.parent = None
        self.idx = idx  # this value is only set for leaf nodes
        self.experience = exp_tuple
        if left is not None:
            left.parent = self
        if right is not None:
            right.parent = self

    @classmethod
    def create_leaf(cls, value, idx, exp_tuple):
        leaf = cls(None, None, is_leaf=True, idx=idx, exp_tuple=exp_tuple)
        leaf.value = value
        leaf.experience = exp_tuple
        return leaf

def create_tree(input_list):
    '''
    takes list of tuples in form [(experience_tuple, priority), ... ]
    '''
    # nodes = [Node.create_leaf(v, i) for i, v in enumerate(input_list)]
    nodes = []
    for i in range(len(input_list)):
        value = input_list[i][1]
        idx = i
        exp_tuple = input_list[i][0]
        curr_node = Node.create_leaf(value, idx, exp_tuple)
        nodes.append(curr_node)

    leaf_nodes = nodes

    # backfill node left and right vals
    while len(nodes) > 1:
        inodes = iter(nodes)
        nodes = [Node(*pair) for pair in zip(inodes, inodes)]

    return nodes[0], leaf_nodes

class PERBuffer:
    def __init__(self, max_size=buffer_max_size):
        '''
        Prioritized experience replay by Schaul et al (2015)
        implements a sumtree data structure to store priorities

        -note: no annealing of anything yet.

        tree total is value of the root_node.
        '''

        self.max_size = max_size

        self.alpha = buffer_alpha
        self.beta_initial = buffer_beta
        self.beta = self.beta_initial
        self.base_priority = 1e-6

        # generate empty buffer
        empty_list = []
        for i in range(int(max_size)):
            # sars'd. would need edited for r2d2
            empty_exp_tuple = (0., 0., 0., 0., 0.)
            empty_priority = 0.
            empty_tuple = tuple([empty_exp_tuple, empty_priority])
            empty_list.append(empty_tuple)

        root_node, leaf_nodes = create_tree(empty_list)

        self.root_node = root_node
        self.leaf_nodes = leaf_nodes

        # this keeps track of which node we update. goes 0-->max_size, repeat.
        self.leaf_node_counter = 0

        # this is used for N in the IS weights. tracks how many adds we've called.
        # maxes out at max_size.
        self.N = 0

        # checked at every update of the tree. for calc max IS weight
        self.min_priority = 9e+99

        # ---calc linear slopes for annealing based on episode---
        self.beta_slope = (1.0 - self.beta) / max_episodes

    def _update_node_priority(self, node, new_value):
        # new value is raw priority, without scale
        new_value = (new_value + self.base_priority) ** self.alpha
        change = new_value - node.value
        node.value = new_value
        self._propagate_changes(change, node.parent)

    def _propagate_changes(self, change, node):
        '''
        used internally to update the sumtree when new experience added
        '''
        node.value += change
        if node.parent is not None:
            self._propagate_changes(change, node.parent)

    def _retrieve(self, value, node):
        '''
        internal method to retrieve a value from a node. pass root_node to fully sample
        '''
        if node.is_leaf:
            return node
        if node.left.value >= value:
            return self._retrieve(value, node.left)
        else:
            return self._retrieve(value - node.left.value, node.right)

    def update_priorities(self, indices, new_values):
        '''
        called from train loop, update the priority vals with ones calcd from loop using leaf indices
        '''
        for i, idx in enumerate(indices):
            node = self.leaf_nodes[idx]
            new_value = new_values[i]

            new_value = (new_value + self.base_priority) ** self.alpha

            if new_value < self.min_priority:
                self.min_priority = new_value

            self._update_node_priority(node, new_value)

    def add(self, new_value, exp_tuple):
        '''
        really more of an "update". cycles thru buffer nodes circularly (FIFO)

        new value is raw priority, without scales. we do that here
        '''
        # first check to see where the index is
        if self.leaf_node_counter >= self.max_size:
            self.leaf_node_counter = 0

        # run this to set N to size of replay_buffer
        if self.N < self.max_size:
            self.N += 1

        node = self.leaf_nodes[self.leaf_node_counter]

        # adjustment, straight from paper. (TD_error + epsilon)^alpha
        new_value = (new_value + self.base_priority) ** self.alpha

        if new_value < self.min_priority:
            self.min_priority = new_value

        change = new_value - node.value
        node.value = new_value
        node.experience = exp_tuple

        self._propagate_changes(change, node.parent)

        self.leaf_node_counter += 1

    def sample(self):
        '''
        return one priority-sampled experience tuple and its current priority.
        '''
        # select a random uniform val for us to naviagte the tree with
        rand_val = np.random.uniform(0, self.root_node.value)
        sampled_node = self._retrieve(rand_val, self.root_node)

        sampled_exp = sampled_node.experience
        sampled_priority = sampled_node.value

        return sampled_exp, sampled_priority

    def sample_batch(self, batch_size, num_episode):
        '''
        return a batch of priority-sampled experience.
        '''
        # update beta first, linearly:
        self.beta = (self.beta_slope*num_episode) + self.beta_initial

        state, action, reward, next_state, done, is_weights, indices = [], [], [], [], [], [], []

        for i in range(batch_size):
            rand_val = np.random.uniform(0, self.root_node.value)
            sampled_node = self._retrieve(rand_val, self.root_node)

            sampled_exp = sampled_node.experience
            sampled_priority = sampled_node.value
            sampled_index = sampled_node.idx

            if sampled_priority <= 0.:
                sampled_priority = self.base_priority**self.alpha

            # --- IS weight calc ---
            # P(j) = p_j / sum(p_i)
            prob_of_j = sampled_priority / self.root_node.value
            is_weight = (self.N * prob_of_j) ** (-self.beta)

            s, a, r, s_, d = sampled_exp

            state.append(np.array(s, copy=False))
            action.append(np.array(a, copy=False))
            reward.append(np.array(r, copy=False))
            next_state.append(np.array(s_, copy=False))
            done.append(np.array(d, copy=False))
            is_weights.append(np.array(is_weight, copy=False))
            indices.append(np.array(sampled_index, copy=False))

        # perform normalization step like paper
        is_weights = np.array(is_weights)
        # max_is_weight = (self.N * self.min_priority / self.root_node.value) ** (-self.beta)
        # is_weights = is_weights / max_is_weight
        is_weights = is_weights / is_weights.max()

        return np.array(state).tolist(), np.array(action).tolist(), np.array(reward).tolist(), np.array(next_state).tolist(), np.array(
            done).tolist(), is_weights.tolist(), np.array(indices).tolist()

class ActorNet(nn.Module):
    def __init__(self, state_dim, action_dim, max_action):
        super(ActorNet, self).__init__()

        self.l1 = nn.Linear(state_dim, 400)
        self.l2 = nn.Linear(400, 300)
        self.l3 = nn.Linear(300, action_dim)

        self.max_action = max_action

    def forward(self, state):
        a = F.relu(self.l1(state))
        # a = F.relu(self.l12(a))
        a = F.relu(self.l2(a))
        a = torch.tanh(self.l3(a)) * self.max_action
        return a

class CriticNet(nn.Module):
    def __init__(self, state_dim, action_dim):
        super(CriticNet, self).__init__()

        self.l1 = nn.Linear(state_dim + action_dim, 400)
        self.l2 = nn.Linear(400, 300)
        self.l3 = nn.Linear(300, 1)

    def forward(self, state, action):
        state_action = torch.cat([state, action], 1)

        q = F.relu(self.l1(state_action))
        # q = F.relu(self.l12(q))
        q = F.relu(self.l2(q))
        q = self.l3(q)
        return q

def print_intro():
    print('\n Welcome to... \n')
    time.sleep(1)
    print('''
  _____  _     _        _ _           _           _      _______ _____    ____
 |  __ \(_)   | |      (_) |         | |         | |    |__   __|  __ \  |___ \
 | |  | |_ ___| |_ _ __ _| |__  _   _| |_ ___  __| |       | |  | |  | |   __) |
 | |  | | / __| __| '__| | '_ \| | | | __/ _ \/ _` |       | |  | |  | |  |__ <
 | |__| | \__ \ |_| |  | | |_) | |_| | ||  __/ (_| |       | |  | |__| |  ___) |
 |_____/|_|___/\__|_|  |_|_.__/ \__,_|\__\___|\__,_|       |_|  |_____/  |____/

    ''')
    time.sleep(2)
    print('\n built by Jake Elkins, the wizard himself. I hope this works. \n\n\n ------ [begin] -----')
    time.sleep(1)

@ray.remote(num_cpus=1, num_gpus=0)
class Actor(object):

    def __init__(self):

        self.local_device = 'cpu'
        self.env = env

        self.n = n_step_return
        self.num_episodes_per_act = num_episodes_per_act

        self.actor = ActorNet(state_dim, action_dim, max_action).to(self.local_device)
        self.actor_target = ActorNet(state_dim, action_dim, max_action).to(self.local_device)
        self.actor_target.load_state_dict(self.actor.state_dict())

        self.critic_1 = CriticNet(state_dim, action_dim).to(self.local_device)
        self.critic_1_target = CriticNet(state_dim, action_dim).to(self.local_device)
        self.critic_1_target.load_state_dict(self.critic_1.state_dict())

        self.critic_2 = CriticNet(state_dim, action_dim).to(self.local_device)
        self.critic_2_target = CriticNet(state_dim, action_dim).to(self.local_device)
        self.critic_2_target.load_state_dict(self.critic_2.state_dict())

        self.max_action = max_action

    def _value_fxn_rescale(self, x):
        if rescale_value_fxn:
            returnx = (torch.sign(x) * (torch.sqrt(torch.abs(x) + 1.) - 1.)) + value_fxn_epsilon * x
        else:
            returnx = x
        return returnx

    def _value_fxn_rescale_inverse(self, x):
        if rescale_value_fxn:
            numerator = torch.sqrt(1. + 4. * value_fxn_epsilon * (torch.abs(x) + 1. + value_fxn_epsilon)) - 1.
            hinv = torch.sign(x) * (((numerator / (2 * value_fxn_epsilon)) ** 2) - 1.)
            returnx = hinv
        else:
            returnx = x
        return returnx

    def _select_action(self, state):
        state = torch.FloatTensor(state.reshape(1, -1)).to(self.local_device)
        return self.actor(state).cpu().data.numpy().flatten()

    def _generate_initial_priority(self, exp_tuple):
        # pass the state-action thru the Q network
        # NOTE: none of the TD3 smoothing is going on here.
        state = exp_tuple[0]
        action = exp_tuple[1]
        reward = exp_tuple[2]
        next_state = exp_tuple[3]
        done = exp_tuple[4]

        state = torch.from_numpy(state).float().to(self.local_device)
        action = torch.from_numpy(action).float().to(self.local_device)
        reward = torch.from_numpy(np.array([reward])).float().to(self.local_device)
        next_state = torch.from_numpy(next_state).float().to(self.local_device)
        done = torch.from_numpy(np.array([done])).float().to(self.local_device)

        next_action = self.actor_target(next_state).unsqueeze(0)

        state = state.unsqueeze(0)
        action = action.unsqueeze(0)
        next_state = next_state.unsqueeze(0)

        target_Q1 = self.critic_1_target(next_state, next_action)
        target_Q2 = self.critic_2_target(next_state, next_action)
        target_Q = self._value_fxn_rescale_inverse(torch.min(target_Q1, target_Q2))
        target_Q = self._value_fxn_rescale(reward + ((1 - done) * (gamma ** self.n) * target_Q).detach())

        current_Q1 = self.critic_1(state, action)
        current_Q2 = self.critic_2(state, action)
        current_Q = torch.min(current_Q1, current_Q2)

        absolute_TD_error = torch.abs(target_Q - current_Q).detach().squeeze(0).cpu().numpy()[0]

        return absolute_TD_error

    def run_episodes(self, state_dict_list, exploration_noise):
        '''
        INPUT: torch-readable versions of the 6 state-dicts. should be:
        actor, actor-target, critic1, critic1-target, critic2, ciritc2-target
        called in replay buffer with a ray.wait()
        '''
        # check to see if we've started learner yet. If not, state_dicts will be None
        if None not in state_dict_list:
            self.actor.load_state_dict(state_dict_list[0])
            self.actor_target.load_state_dict(state_dict_list[1])
            self.critic_1.load_state_dict(state_dict_list[2])
            self.critic_1_target.load_state_dict(state_dict_list[3])
            self.critic_2.load_state_dict(state_dict_list[4])
            self.critic_2_target.load_state_dict(state_dict_list[5])

            self.actor.eval()
            self.actor_target.eval()
            self.critic_1.eval()
            self.critic_1_target.eval()
            self.critic_2.eval()
            self.critic_2_target.eval()

        env = self.env
        n = self.n

        local_buffer = []
        # run X episodes
        for _ in range(self.num_episodes_per_act):

            states = []
            actions = []
            rewards = []
            dones = []

            state = env.reset()
            done = False

            while not done:
                # select action and add exploration noise:
                action = self._select_action(state)
                action = action + np.random.normal(0, exploration_noise, size=3)
                action = action.clip(-1, 1)

                # take action in env:
                next_state, reward, done, _ = env.step(action)

                states.append(state)
                actions.append(action)
                rewards.append(reward)
                dones.append(float(done))

                state = next_state
            states.append(next_state)

            # accumulator for n-step returns
            acc = 0
            returns = []
            for i, r in enumerate(reversed(rewards)):
                acc = r + gamma * acc

                if i >= n:
                    acc = acc - (list(reversed(rewards))[i - n]) * (gamma ** n)

                returns.append(acc)

            returns = list(reversed(returns))

            # recording n-th step dones and nth step states
            nth_states = []
            nth_dones = []

            for i in range(len(dones)):
                if i < (len(dones) - n):
                    nth_done = dones[i + n]
                    nth_state = states[i + n]
                else:
                    nth_done = dones[-1]
                    nth_state = states[-1]

                nth_dones.append(nth_done)
                nth_states.append(nth_state)

            # drop last val of states now, dont need it
            states = states[:-1]

            for i in range(len(states)):
                init_priority = self._generate_initial_priority(
                    (states[i], actions[i], returns[i], nth_states[i], nth_dones[i]))
                local_buffer.append((states[i], actions[i], returns[i], nth_states[i], nth_dones[i], init_priority))

        return local_buffer

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

class BufferNetworkHandler(dtd3_pb2_grpc.LearnerServicer):
    # this class just maintains the easy methods we need for reading, writing, and changing networks
    def __init__(self):
        # note: I could probably fix these around better
        self.actor_dict = None
        self.actor_target_dict = None

        self.critic_1_dict = None
        self.critic_1_target_dict = None

        self.critic_2_dict = None
        self.critic_2_target_dict = None

        self.network_list = [self.actor_dict, self.actor_target_dict,
                             self.critic_1_dict, self.critic_1_target_dict,
                             self.critic_2_dict, self.critic_2_target_dict]

        self.replay_buffer = PERBuffer()

        self.actors = [Actor.remote() for _ in range(num_actors)]

        # this was used for debug
        self.msg = None
        self.indices = None
        self.reading_priorities = None
        self.reading_indices = None
        self.first_dict = None

        # -- for monitor --
        self.num_episodes_for_monitor = num_episodes_for_monitor
        self.actor_copy = ActorNet(state_dim, action_dim, max_action).to('cpu')

    def UpdateNetworks(self, request_iterator, context):
        '''
        this handles the sending of both networks and new priorities.
        messages will differ in where the Nones are
        update networks:
        [actor, actor_target, critic1, critic1_target, critic2, critic2_target, None, None]
        update priorities:
        [None, None, None, None, None, None, indices, priorities]
        '''

        '''for i, request in enumerate(request_iterator):
            curr_dict = json.loads(request.network_params)
            # switch network back into torch-readable tensors
            for entry in curr_dict:
                curr_dict[entry] = torch.FloatTensor(curr_dict[entry]).to(device)

            self.network_list[i] = curr_dict'''
        indices = None
        priorities = None

        for i, request in enumerate(request_iterator):
            curr_dict = json.loads(request.network_params)
            if (i <= 5) and (curr_dict is not None):
                # these are still state_dicts
                for entry in curr_dict:
                    curr_dict[entry] = torch.FloatTensor(curr_dict[entry]).to(device)

                self.network_list[i] = curr_dict
            elif (i > 5) and (curr_dict is not None):
                # we're reading priorities
                if i == 6:
                    self.reading_indices = True
                    indices = curr_dict
                elif i == 7:
                    self.reading_priorities = True
                    priorities = curr_dict

        if (indices is not None) and (priorities is not None):
            self.replay_buffer.update_priorities(indices, priorities)
            self.indices = indices

        if (None not in self.network_list) and (self.first_dict is None):
            self.first_dict = True

        return dtd3_pb2.BufferStatus(status=1)

    def act(self):
        '''
        this is where the Ray actors are sent and handled. note the infinite loop: this guy has to be terminated.
        :return:
        nil
        '''

        print(f'acting started. running {num_actors} across CPUs')
        loop_num = 0
        while True:
            loop_num += 1
            # print(f'reading indices: {self.reading_indices}')
            # print(f'reading priorities: {self.reading_priorities}')
            if (None in self.network_list) and (self.first_dict):
                print(f"[!] ERROR [!] network list contains a NoneType [!] ERROR [!]")

            not_done_actor_ids = []
            for i, actor in enumerate(self.actors):
                exploration_noise = exploration_noises[i]
                not_done_actor_ids.append(actor.run_episodes.remote(self.network_list, exploration_noise))

            while len(not_done_actor_ids):
                done_actor_ids, not_done_actor_ids = ray.wait(not_done_actor_ids)

                # if done_id == actors, add to replay buffer
                if done_actor_ids:
                    for actor_id in done_actor_ids:
                        local_buffer_out = ray.get(actor_id)
                        for tuple_ in local_buffer_out:
                            priority = tuple_[-1]
                            exp_tuple = tuple_[:-1]
                            self.replay_buffer.add(priority, exp_tuple)

            if loop_num%100 == 0:
                print(f'Current buffer size: {self.replay_buffer.N}')
                # print(f'indices read: {self.indices}')
                # print(f'curr main dict (should be None before the epoch): {self.network_list[0]}')

    def ReadData(self, request, context):

        # print(f'read_data request received. status: {request.status}')

        # TODO: tune beta annealing. Zero for now (constant at initial beta val)
        state, action_, reward, next_state, done, is_weights, indices = self.replay_buffer.sample_batch(batch_size, 0)

        send_list = [state, action_, reward, next_state, done, is_weights, indices]

        for data_section in send_list:
            #print(data_section)
            #data_section_json = json.dumps(data_section.tolist())
            data_section_json = json.dumps(data_section)
            yield dtd3_pb2.BufferResponse(train_data=bytes(data_section_json, 'utf-8'))

    def RunAgentStats(self, request, context):
        '''
        RPC that the monitor asks for. this asks for an agent stat update using current networks.
        '''
        #print(f'actor_copy keys: {self.actor_copy.state_dict().keys()}')

        # load up most recent policy net
        if self.network_list[0] is not None:
            #print(f'network_list keys: {self.network_list[0].keys()}')
            self.actor_copy.load_state_dict(self.network_list[0])

        rewsum_list = []
        meanminang_list = []

        for ep_num in range(self.num_episodes_for_monitor):

            done = False
            obs = env.reset()

            reward_list = []
            obs_list = []

            while not done:
                #act = policy.select_action(obs)
                obs = torch.FloatTensor(obs.reshape(1, -1)).to('cpu')
                act = self.actor_copy(obs).cpu().data.numpy().flatten()
                act = act.clip(-1, 1)
                obs, reward, done, _ = env.step(act)
                reward_list.append(reward)
                obs_list.append(obs)

            q4 = [i[0] for i in obs_list]
            q1 = [i[1] for i in obs_list]
            q2 = [i[2] for i in obs_list]
            q3 = [i[3] for i in obs_list]

            curr_minang = 2*np.arccos(np.max(q4))*(180/np.pi)
            curr_rew_sum = np.sum(reward_list)

            rewsum_list.append(curr_rew_sum)
            meanminang_list.append(curr_minang)

        mean_min_ang = np.mean(meanminang_list)
        mean_rew_sum = np.mean(rewsum_list)

        return dtd3_pb2.AgentStats(reward=mean_rew_sum, additional_data=mean_min_ang)

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

if __name__ == '__main__':
    logging.basicConfig()

    handler = BufferNetworkHandler()

    # --- server specifics ---
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    dtd3_pb2_grpc.add_LearnerServicer_to_server(handler, server)
    server.add_insecure_port('[::]:50051')
    server.start()

    print_intro()

    try:
        # start acting
        handler.act()
        server.wait_for_termination() # FOR DEBUG
    except KeyboardInterrupt as e:
        print(f'ERROR: terminated. {e}')
        print(f'please wait for safe shutdown...')
        if ray.is_initialized():
            ray.shutdown()
        server.stop(3)
# TODO: print buffer checkup and stats every now and then. also--ray handles ctrl-c really weirdly. how do we exit
#  before errors are caught?

# EOF