from entities import Hero, Town, Gameboard, cur
from dataclasses import dataclass, fields
import os, time, random, itertools

# Code written by Alex Stråe from Sweden. Creatures, heroes and town attributes and
# names are, where copied correctly, copied from the original game 'Heroes of Might and Magic 3'.

class Dialogues:
    def line(width):
        return ("-" + '{:-^'  + str(width) + 's}').format("-") + "-\n"

    def box(text: str, width, box, lines)->str:
        result=""
        separator = "" if not lines else "-"
        if box:
            result = Dialogues.line(width)
        for row in text.split("\n"):
            result += ("|" + '{:'+separator+'^' + str(width) + 's}').format(row) + "|"
            if box:
                result += "\n"
        if box:
            result += Dialogues.line(width)
        return result

@dataclass
class Resources:
    wood:int = 0
    mercury:int = 0
    stone:int = 0
    sulfur: int = 0
    crystal:int = 0
    gems:int = 0
    gold:int = 0

    def __add__(self, other):
        return Resources(*(getattr(self, dim.name) + getattr(other, dim.name) for dim in fields(self)))

class Player:
    def __init__(self, input_name, input_no, input_color):
        self.name = input_name
        self.number = input_no
        self.color = input_color
        self.hasLost = False
        self.hasWon = False
        self.heroes = []
        self.heroes_left = 0
        self.towns = []
        self.kingdom = ""
        self.hero_ticker = 1
        self.has_hired = False
        self.num_towns = 0
        self.resources = Resources(10, 4, 10, 4, 4, 4, 4000)
        self.daily = Resources(0, 0, 0, 0, 0, 0, 500)
        self.weekday = 1
        self.week = 1

    def __str__(self):
        return f'{self.name}'

    def clear_window(self):
        os.system('cls' if os.name == 'nt' else 'clear')

    def dialogue_display(self, input1="", input2="", input3="", input4="", width=140, box=True, lines=False):
        print(Dialogues.box(input1+input2+"\n"+input3+input4, width, box, lines))
        input("\n")

    def box_display(self, input, width=140, box=True, lines=False):
        print(Dialogues.box(input, width, box, lines))

    def dialogue_return(self, input1="", input2="", input3="", input4="", width=140, box=True, lines=False):
        print(Dialogues.box(input1+input2+"\n"+input3+input4, width, box, lines))
        choice = input("\n")
        return choice

    def view_info(self):
        print("")
        self.box_display("Player: " + self.name, 40, False, False)
        self.box_display("Towns", 40, False, True)
        for town in self.towns:
            self.box_display(town.name +", Kingdom: " + town.kingdom, 40, False, True)
            if town.army:
                for unit in town.army:
                    self.box_display(unit.name+ ", " + str(unit.amount) + " units",40, False, False)
            else:
                self.box_display("No army.", 40, False, False)
        self.box_display("Heroes", 40, False, True)
        for hero in self.heroes:
            self.box_display(hero.name + ", " + hero.kind + " level: " + str(hero.level), 40, False, True)
            self.box_display("Daily movement points: " + str(hero.new_speed),40, False, False)
            self.box_display("Attack: " + str(hero.attack) + "   Defense: " + str(hero.defense), 40, False, False)
            self.box_display("Knowledge: " + str(hero.knowledge) + " Spell Power: " + str(hero.spell_power), 40, False, False)
            self.box_display("Army:", 40, False, False)
            for unit in hero.army:
                self.box_display(unit.name + ", " + str(unit.amount) + " units", 40, False, False)
        self.box_display("", 40, False, True)
        input("\n")

    def new_turn(self):
        self.resources += self.daily
        if self.towns != []:
            for i in range(len(self.towns)):
                self.towns[i].has_built = False
        if self.heroes != []:
            for hero in self.heroes:
                hero.speed_left = hero.new_speed
        self.weekday += 1
        if self.weekday == 8:
            self.has_hired = False
            self.weekday = 1
            self.week += 1
            if self.towns != []:
                for town in self.towns:
                    town.new_week()
        for hero in self.heroes:
            if hero.spell_points < hero.knowledge*10:
                hero.spell_points += 5

    def choose_kingdom(self, available_kingdoms):
        chosen_kingdom = self.dialogue_return(str(available_kingdoms), "",
                            "These kingdoms are available. Choose your kingdom, ", self.name + "!").capitalize()
        while chosen_kingdom not in available_kingdoms:
            chosen_kingdom = input("Try again " + self.name + ".\n").capitalize()
        self.kingdom = chosen_kingdom
        available_kingdoms.remove(chosen_kingdom)

    def create_heroes(self, new_loc=None, map=None):
        new_hero = None
        for name, type, attack, defense, knowledge, spell_power in cur.execute("SELECT name, type, attack, " \
             "defense, knowledge, spell_power FROM heroes WHERE kingdom = '" + self.kingdom.lower() +
                "' AND id = " + str(self.hero_ticker)):
            new_hero = Hero(name, type, attack, defense, knowledge, spell_power, self)
        if new_loc != None:
            new_hero.location = new_loc
            map.square[new_loc[0]][new_loc[1]].has_hero = True
            map.square[new_loc[0]][new_loc[1]].hero = new_hero
        self.heroes.append(new_hero)
        self.hero_ticker += 1
        self.heroes_left += 1
        new_hero.location = new_loc
        new_hero.create_starting_army()

    def create_towns(self):
        new_town = None
        if self.kingdom == "Castle": new_town = Town("Valetta", self.kingdom, self)
        elif self.kingdom == "Dungeon": new_town = Town("Deepwarren", self.kingdom, self)
        elif self.kingdom == "Inferno": new_town = Town("Styx", self.kingdom, self)
        elif self.kingdom == "Necropolis": new_town = Town("Blighttown", self.kingdom, self)
        elif self.kingdom == "Rampart": new_town = Town("Goldenglade", self.kingdom, self)
        elif self.kingdom == "Tower": new_town = Town("Celeste", self.kingdom, self)
        self.towns.append(new_town)

    def set_locations(self, number_of_players, input_rows, input_cols, map):
        start_row = 0
        end_row = 0
        start_col = 0
        end_col = 0
        if self.number == 1:
            start_row = 4
            end_row = int(input_rows / 2 - 4)
            start_col = 4
            end_col = int(input_cols / 2 - 4)
        elif self.number == 2:
            start_row = int(input_rows / 2 + 4)
            end_row = input_rows - 4
            start_col = 4
            end_col = int(input_cols / 2 - 4)
        elif self.number == 3:
            start_row = 4
            end_row = int(input_rows / 2 - 4)
            start_col = int(input_cols / 2 + 4)
            end_col = input_cols - 4
        elif self.number == 4:
            start_row = int(input_rows / 2 + 4)
            end_row = input_rows - 4
            start_col = int(input_cols / 2 + 4)
            end_col = input_cols - 4
        if number_of_players < 3:
            end_col = input_cols - 4

        dice_row = random.randrange(start_row, end_row)
        dice_col = random.randrange(start_col, end_col)
        while map.square[dice_row][dice_col].kind == "mountain" or map.square[dice_row][dice_col].kind == "water":
            dice_row = random.randrange(start_row, end_row)
            dice_col = random.randrange(start_col, end_col)

        self.towns[0].location[0], self.towns[0].location[1] = dice_row, dice_col
        self.heroes[0].location = self.towns[0].location
        map.square[dice_row][dice_col].has_object = True
        map.square[dice_row][dice_col].object_name = "Town"
        map.square[dice_row][dice_col].operated_by = self
        map.square[dice_row][dice_col].town = self.towns[0]
        map.square[dice_row][dice_col].has_hero = True
        map.square[dice_row][dice_col].hero = self.heroes[0]

    def update_discovery(self, map):
        rows = len(map.square)
        cols = len(map.square[0])
        for i in range(len(self.heroes)):
            pn = int(self.heroes[i].location[0])
            pl = int(self.heroes[i].location[1])
            for c in range(-2, 3):
                for d in range(-2, 3):
                    if pn == 0 and c < 0: c = 0
                    elif pn == 1 and c < 0: c = -1
                    elif pn == (rows - 1) and c > 0: c = 0
                    elif pn == (rows - 2) and c > 1: c = 1
                    if pl == 0 and d < 0: d = 0
                    elif pl == 1 and d < 0: d = -1
                    elif pl == (cols - 1) and d > 0: d = 0
                    elif pl == (cols - 2) and d > 1: d = 1
                    map.square[pn + c][pl + d].seen[self.number - 1] = 1

    def interpretor(self, choice, map, list_of_players):
        if choice.lower() == "view":
            self.view_info()

        elif choice.lower() == "move":
            if len(self.heroes) == 1:
                hero_choice = self.heroes[0].name
                self.move_obj(hero_choice, map)
            elif self.heroes == []:
                self.dialogue_display("You have no heroes left! Recruit new ones in a tavern, in a town.")
            else:
                hero_choice = input("Move which hero?\n")
                self.move_obj(hero_choice, map)

        elif choice.lower() == "spells":
            if len(self.heroes) == 1:
                hero = self.heroes[0]
            else:
                hero = input("Spells for which hero?\n")
                if self.has_hero_name(hero):
                    hero = self.get_hero(hero)
                else:
                    self.dialogue_display("No hero with that name found.")
                    return
            if hero.spellbook != []:
                hero.view_spells()
                spell = ""
                while spell == "":
                    spell = self.dialogue_return("Name the spell you want to throw or ""C"" to cancel.").title()
                if spell != "C":
                    spell_cost = None
                    for spell_in_book in hero.spellbook:
                        if spell == spell_in_book.get("name"):
                            spell_cost = spell_in_book.get("cost")
                    if spell_cost == None:
                        self.dialogue_display("Could not find that spell.")
                    elif spell != "Summon Boat":
                        self.dialogue_display(hero.name + " cannot throw that spell outside of combat.")
                    else:
                        hero.has_boat = True
                        hero.spell_points -= spell_cost
                        self.dialogue_display(hero.name + " has a boat until they step on ground!")
            else:
                self.dialogue_display(hero.name + " does not have a spellbook.")

        elif choice.lower() == "town":
            if self.towns != []:
                if len(self.towns) > 1:
                    town_choice = input("Enter which town? Number:\n")
                    while town_choice not in ("1", "2", "3"):
                        town_choice = input("Type town to enter. 1 = First town. 2 = Second town. 3 = Third town.\n")
                    if town_choice == "1":
                        self.enter_town(self.towns[0], map)
                    elif town_choice == "2":
                        self.enter_town(self.towns[1], map)
                    elif town_choice == "3":
                        self.enter_town(self.towns[2], map)
                else:
                    self.enter_town(self.towns[0], map)
            else:
                self.dialogue_display("You have lost all your towns!")
        elif choice.lower() == "end turn":
            return
        else:
            print("Use commands listed in the action bar above the map to play the game.\n")

        for i in range(len(list_of_players)):
            if list_of_players[i].heroes_left == 0 and list_of_players[i].towns == []:
                list_of_players[i].hasLost = True
                self.dialogue_display(list_of_players[i].name, " has been defeated!")
                list_of_players.pop(i)
            if len(list_of_players) == 1:
                return
        self.clear_window()
        map.view_board(self)
        choice = self.dialogue_return("What do you want to do?", "", "")
        self.interpretor(choice, map, list_of_players)

    def has_hero_name(self, input):
        for i in range(len(self.heroes)):
            if self.heroes[i].name[0:4] == input[0:4].title() and self.heroes[i].alive:
                return True
        print("Found no hero with that name.")
        time.sleep(1)
        return False

    def get_hero(self, input):
        for i in range(len(self.heroes)):
            if self.heroes[i].name[0:4] == input[0:4].title():
                return self.heroes[i]
        return ""

    def new_pos_calculator(self, choice, old_pos):
        new_pos = [0,0]
        if choice == 'q': new_pos[0], new_pos[1] = old_pos[0] - 1, old_pos[1] - 1
        elif choice == 'w': new_pos[0], new_pos[1] = old_pos[0] - 1, old_pos[1]
        elif choice == 'e': new_pos[0], new_pos[1] = old_pos[0] - 1, old_pos[1] + 1
        elif choice == 'a': new_pos[0], new_pos[1] = old_pos[0], old_pos[1] - 1
        elif choice == 's': new_pos[0], new_pos[1] = old_pos[0] + 1, old_pos[1]
        elif choice == 'd': new_pos[0], new_pos[1] = old_pos[0], old_pos[1] + 1
        elif choice == 'z': new_pos[0], new_pos[1] = old_pos[0] + 1, old_pos[1] - 1
        elif choice == 'x': new_pos[0], new_pos[1] = old_pos[0] + 1, old_pos[1] + 1
        return new_pos

    def by_speed(self, unit):
        return unit.speed_left

    def move_obj(self, input_hero, input_board):
        if self.has_hero_name(input_hero):
            hero = self.get_hero(input_hero)
            while True:
                self.clear_window()
                input_board.view_board(self, True)
                choice = ""
                while choice == "" or choice[0] not in ("q", "w", "e", "a", "s", "d", "z", "x", "o", "-"):
                    choice = input(hero.speed_bar()).lower()
                old_pos = hero.location
                new_pos = [0, 0]
                if choice[0] == '-':
                    hero.speed_left += 1000
                    hero.new_speed += 1000
                    break
                elif choice[0] == "o":
                    print("Exiting.")
                    time.sleep(0.5)
                    return
                new_pos = self.new_pos_calculator(choice[0], old_pos)
                if new_pos[0] < 0: new_pos[0] = 0
                elif new_pos[0] == len(input_board.square): new_pos[0] = len(input_board.square) - 1
                if new_pos[1] < 0: new_pos[1] = 0
                elif new_pos[1] == len(input_board.square[0]): new_pos[1] = len(input_board.square[0]) - 1
                old_loc = input_board.square[old_pos[0]][old_pos[1]]
                new_loc = input_board.square[new_pos[0]][new_pos[1]]
                if new_loc.kind == "water" and hero.has_boat is False:
                    continue
                else:
                    if old_loc.kind == "water" and new_loc.kind != "water":
                        hero.has_boat = False
                    if new_loc.speed_drain <= hero.speed_left:
                        hero.speed_left -= new_loc.speed_drain
                        if new_loc.has_hero and new_loc.hero.operating_player != self:
                            self.start_war(hero, new_loc.hero, new_loc, old_loc)
                        elif new_loc.has_object and new_loc.object_name == "Town" and \
                                new_loc.town.operating_player != self:
                            if new_loc.town.army != []:
                                self.start_war(hero, new_loc.town, new_loc, old_loc)
                                new_loc.town.alive = True
                            else:
                                self.towns.append(new_loc.town)
                                new_loc.operated_by = self
                                for town in new_loc.town.operating_player.towns:
                                    if town.name == new_loc.town.name:
                                        new_loc.town.operating_player.towns.remove(town)
                                self.towns[-1].operating_player = self
                                if self.towns[-1].buildings.hall_lvl == 4:
                                    self.towns[-1].buildings.hall_lvl = 3
                                self.dialogue_display("You have conquered a town!")

                        elif new_loc.has_hero == False:
                            old_loc.has_hero = False
                            old_loc.hero = None
                            new_loc.has_hero = True
                            new_loc.hero = hero
                            hero.location = new_pos
                            if new_loc.has_object and new_loc.object_name == "Town" and new_loc.town.operating_player == self:
                                self.enter_town(new_loc.town, input_board)
                                return
                            elif new_loc.has_object:
                                hero.confront_object(new_loc)
                        self.update_discovery(input_board)

                        if hero.speed_left == 0:
                            self.dialogue_display("You have run out of movement points. Exiting movement.")
                            return
                        elif hero.alive == False:
                            self.dialogue_display("Your forces suffer a bitter defeat, and " + hero.name + " leaves your cause.")
                            return
                    else:
                        self.dialogue_display("You have run out of movement points. Exiting movement.")
                        return

    def start_war(self, attacker, defender, battle_loc, old_loc):
        # Setting up battlefield:
        battlefield = Gameboard(10, 13, False)
        for u in attacker.army:
            u.location[0] = u.start_location[0] + 1
            u.location[1] = 0
            battlefield.square[u.location[0]][0].has_hero = True
            battlefield.square[u.location[0]][0].hero = u
            u.health = u.orig_health
        for u in defender.army:
            u.location[0] = u.start_location[0] + 1
            u.location[1] = 12
            battlefield.square[u.location[0]][12].has_hero = True
            battlefield.square[u.location[0]][12].hero = u
            u.health = u.orig_health
        # Battle starts:
        # First: Reset standard attributes and apply active spell effects if any:
        while attacker.alive and defender.alive:
            for u in attacker.army:
                u.battle_attributes_handler()
            attacker.army.sort(key=self.by_speed, reverse=True)
            for u in defender.army:
                u.battle_attributes_handler()
            defender.army.sort(key=self.by_speed, reverse=True)
            attacker.can_throw_spell = True
            defender.can_throw_spell = True
            # Each has their turn, then restart
            for (a_unit, d_unit) in itertools.zip_longest(attacker.army, defender.army):
                if a_unit and defender.alive:
                    if a_unit.amount > 0 and a_unit.turn_left is True:
                        self.war_move_obj(a_unit, defender, battlefield)
                    if a_unit.battle_actions:
                        a_unit.battle_attributes_handler(True)
                attacker.alive = attacker.check_alive()
                if d_unit and attacker.alive:
                    if d_unit.amount > 0 and d_unit.turn_left is True:
                        defender.operating_player.war_move_obj(d_unit, attacker, battlefield)
                    if d_unit.battle_actions:
                        d_unit.battle_attributes_handler(True)
                attacker.alive = attacker.check_alive()
                defender.alive = defender.check_alive()
        # Now at least one is dead. Let's wrap up and return
        if not attacker.alive:
            for unit in defender.army:
                if unit.amount < 1:
                    defender.army.remove(unit)
            old_loc.has_hero = False
            old_loc.hero = None
            self.heroes_left -= 1
            self.heroes.remove(attacker)

        if not defender.alive:
            for unit in attacker.army:
                if unit.amount < 1:
                    attacker.army.remove(unit)
            battle_loc.has_hero = False
            battle_loc.hero = None
            if type(battle_loc.object_name) == Hero:
                battle_loc.object_name = ""
            elif type(defender) == Hero:
                defender.operating_player.heroes_left -= 1
                defender.operating_player.heroes.remove(defender)
            elif type(defender) == Town and attacker.alive:
                self.towns.append(defender)
                self.towns[-1].operating_player = self
                if self.towns[-1].buildings.hall_lvl == 4:
                    self.towns[-1].buildings.hall_lvl = 3
                battle_loc.operated_by = self
                defender.operating_player.towns.remove(defender)
                self.dialogue_display("You have conquered a town!")

    def war_move_obj(self, attacker, defending_hero, battlefield):
        a = attacker
        total_damage_attacker = int(a.amount * a.damage * (a.attack * a.operating_hero.attack * 2 / 100 + 1))
        original_damage_attacker = total_damage_attacker
        original_health_attacker = a.health
        d = None
        defender_loc = None
        total_damage_defender = None
        original_damage_defender = None
        original_health_defender = None

        # For AI control / Computer Player:
        if a.operating_hero.operating_player.number == 9:
            self.clear_window()
            battlefield.view_battlefield(self, a)
            # ACQUIRING TARGET:
            diff_damage_health = 100000
            for unit in defending_hero.army:
                if unit.amount > 0:
                    if abs((unit.health * unit.amount) - total_damage_attacker) < diff_damage_health:
                        if d:
                            if unit.isranged:
                                diff_damage_health = abs((unit.health * unit.amount) - total_damage_attacker)
                                d = unit
                        else:
                            diff_damage_health = abs((unit.health * unit.amount) - total_damage_attacker)
                            d = unit
            # Moving closer to target, if melee unit:
            if a.isranged == False:
                while a.speed_left > 0:
                    current = battlefield.square[a.location[0]][a.location[1]]
                    prospect = None
                    direction_row = a.location[0] - d.location[0]
                    direction_col = a.location[1] - d.location[1]
                    diff_row = abs(a.location[0] - d.location[0])
                    diff_col = abs(a.location[1] - d.location[1])
                    ss = 0
                    counter = 0
                    move_around = 0
                    total_counter = 0
                    while prospect == None or (prospect.has_hero and prospect.hero != d and move_around < 2) or (
                            prospect.has_hero and move_around >= 2 and prospect.hero.operating_hero == a.operating_hero):
                        total_counter += 1
                        if total_counter > 30:
                            self.clear_window()
                            battlefield.view_battlefield(self, attacker)
                            print("AI failed to find matching movement prospect after too many tries.")
                            print(a.name + " targeted " + d.name)
                            if prospect == None:
                                print("Prospect was None!")
                            else:
                                print("Prospect was " + str(prospect.coord))
                            print("Returning in 10 seconds...")
                            time.sleep(10)
                            return
                        if prospect != None and prospect.has_hero and prospect.hero != d:
                            move_around += 1
                            if move_around == 3:
                                counter = 0
                            counter += 1
                            if counter == 1: ss = -1
                            elif counter == 2: ss = 1
                        if diff_col == 0:
                            if direction_row > 0: prospect = battlefield.square[a.location[0] - 1][a.location[1] + ss]
                            elif direction_row < 0: prospect = battlefield.square[a.location[0] + 1][a.location[1] + ss]
                        elif diff_row == 0:
                            if direction_col > 0: prospect = battlefield.square[a.location[0] + ss][a.location[1] - 1]
                            elif direction_col < 0: prospect = battlefield.square[a.location[0] + ss][a.location[1] + 1]
                        else:
                            if diff_col > diff_row:
                                if direction_col > 0: prospect = battlefield.square[a.location[0] + ss][a.location[1] - 1]
                                elif direction_col < 0: prospect = battlefield.square[a.location[0] + ss][a.location[1] + 1]
                            elif diff_row >= diff_col:
                                if diff_row == 1 and diff_col == 1: prospect = battlefield.square[d.location[0]][d.location[1]]
                                elif direction_row > 0: prospect = battlefield.square[a.location[0] - 1][a.location[1] + ss]
                                elif direction_row < 0: prospect = battlefield.square[a.location[0] + 1][a.location[1] + ss]

                    if prospect.has_hero == False:
                        current.has_hero = False
                        current.hero = None
                        a.location[0], a.location[1] = prospect.coord[0], prospect.coord[1]
                        prospect.has_hero = True
                        prospect.hero = attacker
                        a.speed_left -= 1
                        if a.speed_left == 0:
                            return
                    elif prospect.has_hero and prospect.hero.operating_hero != a.operating_hero:
                        d = prospect.hero
                        break
                    elif prospect.has_hero and prospect.hero.operating_hero == a.operating_hero:
                        print("AI failed to calculate move around own unit.")
                        time.sleep(3)
                        return
        # For human players:
        else:
            while True:
                self.clear_window()
                battlefield.view_battlefield(self, attacker)
                choice = input("Enter commands.\n").lower()
                while choice == "" or choice[0] not in ("q", "w", "e", "a", "s", "d", "z", "x", "o", "r"):
                    choice = input("     Move with QWEASDZX or use commands in the action bar.\n").lower()

                if choice == "r":
                    if attacker.isranged:
                        while True:
                            choice = input("Type unit to range attack:\n").title()
                            for unit in defending_hero.army:
                                if choice[:6] == unit.name[:6] and unit.amount > 0:
                                    d = unit
                                    break
                            if d:
                                break
                            else:
                                print("         Found no unit with that name.")
                                time.sleep(1)
                    else:
                        print("         This unit does not have a ranged attack!")
                        time.sleep(1)

                elif choice == "spells":
                    spell_damage = None
                    original_spell_damage = None
                    spell_effect = None
                    spell_cost = None
                    spell_color = None
                    if attacker.operating_hero.can_throw_spell:
                        while True:
                            if not attacker.operating_hero.spellbook:
                                self.dialogue_display(attacker.operating_hero.name + " does not have a spellbook!")
                                break
                            attacker.operating_hero.view_spells()
                            spell = ""
                            while spell == "":
                                spell = self.dialogue_return(
                                    "Name the spell you want to throw or ""C"" to cancel.").title()
                            if spell == "C":
                                break
                            target = ""
                            while target == "":
                                target = self.dialogue_return("Name your target or ""C"" to cancel.").title()
                            if target == "C":
                                break
                            for spell_in_book in attacker.operating_hero.spellbook:
                                if spell == spell_in_book.get("name"):
                                    spell_damage = spell_in_book.get("damage")
                                    spell_effect = spell_in_book.get("effect")
                                    spell_cost = spell_in_book.get("cost")
                                    if "color" in spell_in_book:
                                        spell_color = spell_in_book.get("color")
                            if spell_cost == None:
                                self.dialogue_display("No such spell found.")
                            elif spell_cost > attacker.operating_hero.spell_points:
                                self.dialogue_display("You don't have the spell points.")
                            elif spell_color != "ADV":
                                if spell_effect:
                                    if spell_color == "red":
                                        for unit in defending_hero.army:
                                            if target[:7] == unit.name[:7]:
                                                d = unit
                                    elif spell_color == "green":
                                        for unit in a.operating_hero.army:
                                            if target[:7] == unit.name[:7]:
                                                d = unit
                                else:
                                    for unit in defending_hero.army:
                                        if target[:7] == unit.name[:7]:
                                            d = unit
                                if d == None:
                                    print("         Found no unit with that name.")
                                else:
                                    a.operating_hero.spell_points -= spell_cost
                                    a.operating_hero.can_throw_spell = False
                                    if spell_damage:
                                        original_spell_damage = spell_damage * a.operating_hero.spell_power
                                        original_health_defender = d.health
                                        new_loc = battlefield.square[d.location[0]][d.location[1]]
                                        d.health -= spell_damage * a.operating_hero.spell_power
                                        d.health = int(d.health)
                                        spell_damage -= original_health_defender
                                        while d.health <= 0:
                                            d.amount -= 1
                                            d.health = d.orig_health
                                            if spell_damage > 0:
                                                d.health -= spell_damage
                                                spell_damage -= d.orig_health
                                        if d.amount < 1:
                                            new_loc.has_hero = False
                                            new_loc.hero = None
                                        self.dialogue_display(a.operating_hero.name + " throws  " + spell + " at " +
                                                              d.name, "", "for " + str(original_spell_damage) + " damage!")
                                        d = None
                                        break
                                    else:
                                        if spell_effect in d.battle_actions:
                                            for spell in d.battle_actions:
                                                if spell[0] is spell_effect:
                                                    spell[1] = a.operating_hero.spell_power
                                        else:
                                            attacker.operating_hero.effect_thrower(spell_effect, d)
                                            if spell_color:
                                                d.affected_color = spell_color
                                            d.spells_affected_by.append(spell.title())
                                            d.battle_actions.append([spell_effect, a.operating_hero.spell_power, spell])
                                            self.dialogue_display(a.operating_hero.name + " throws  " + spell + " at " +
                                                                  d.name + "!")
                                        d = None
                                        break
                    else:
                        print("         You have already thrown a spell this cycle.")
                        time.sleep(2)
                # With ranged units and spells out of the way, time for movement:
                else:
                    for i in range(len(choice)):
                        old_pos = a.location
                        new_pos = [0, 0]
                        if choice[i] in ("q", "w", "e", "a", "s", "d", "z", "x"):
                            new_pos = self.new_pos_calculator(choice[i], old_pos)
                        elif choice[i] == "o": return
                        else:
                            print("     Invalid input.")
                            time.sleep(1)
                            break
                        if new_pos[0] < 0: new_pos[0] = 0
                        elif new_pos[0] == len(battlefield.square): new_pos[0] = len(battlefield.square) - 1
                        if new_pos[1] < 0: new_pos[1] = 0
                        elif new_pos[1] == len(battlefield.square[0]): new_pos[1] = len(battlefield.square[0]) - 1
                        old_loc = battlefield.square[old_pos[0]][old_pos[1]]
                        new_loc = battlefield.square[new_pos[0]][new_pos[1]]
                        if new_loc.speed_drain <= a.speed_left:
                            if new_loc.has_hero == False:
                                a.speed_left -= new_loc.speed_drain
                                new_loc.has_hero = True
                                new_loc.hero = a
                                a.location = new_pos
                                old_loc.has_hero = False
                                old_loc.hero = None
                                if a.speed_left == 0:
                                    print("No more speed left. Ending turn now.")
                                    time.sleep(0.5)
                                    return
                            elif new_loc.has_hero and new_loc.hero.operating_hero == a.operating_hero:
                                print("You already have a Unit standing there.")
                                time.sleep(1)
                            elif new_loc.has_hero and new_loc.hero.operating_hero != a.operating_hero:
                                d = new_loc.hero
                                break
                    if d:
                        break
                if d:
                    break
        # Executing damage from all units, human or AI:
        attacker_loc = battlefield.square[a.location[0]][a.location[1]]
        defender_loc = battlefield.square[d.location[0]][d.location[1]]
        if a.isranged == False:
            a.speed_left -= defender_loc.speed_drain
        original_health_defender = d.health
        if type(d.operating_hero) == Hero:
            d.health -= total_damage_attacker / ((d.defense + d.operating_hero.defense) * 2 / 100 + 1)
        else:
            d.health -= total_damage_attacker / (d.operating_hero.defense * 2 / 100 + 1)
        d.health = int(d.health)
        total_damage_attacker -= original_health_defender
        while d.health <= 0:
            d.amount -= 1
            d.health = d.orig_health
            if total_damage_attacker > 0:
                d.health -= total_damage_attacker
                total_damage_attacker -= d.orig_health
        if d.amount < 1:
            defender_loc.has_hero = False
            defender_loc.hero = None
        # If target is still alive they may retaliate:
        if a.isranged == False and defender_loc.has_hero and d.has_retaliated == False:
            if type(d.operating_hero) == Hero:
                total_damage_defender = d.amount * d.damage * ((d.attack + d.operating_hero.attack) * 2 / 100 + 1)
            else:
                total_damage_defender = d.amount * d.damage * (d.attack * 2 / 100 + 1)
            total_damage_defender = int(total_damage_defender)
            original_damage_defender = total_damage_defender
            if type(attacker.operating_hero) == Hero:
                a.health -= total_damage_defender / ((a.defense + a.operating_hero.defense) * 2 / 100 + 1)
            else:
                a.health -= total_damage_defender / (a.operating_hero.defense * 2 / 100 + 1)
            a.health = int(a.health)
            total_damage_defender -= original_health_attacker
            while a.health <= 0:
                a.amount -= 1
                a.health = a.orig_health
                if total_damage_defender > 0:
                    a.health -= total_damage_defender
                    total_damage_defender -= a.orig_health
            if a.amount < 1:
                attacker_loc.has_hero = False
                attacker_loc.hero = None
            d.has_retaliated = True
        self.clear_window()
        battlefield.view_battlefield(self, a)
        # Display results:
        if a.isranged:
            self.dialogue_display(a.name + " shoots " + d.name, " with " + str(original_damage_attacker) + " damage!")

        elif d.has_retaliated == True and original_damage_defender is not None:
            self.dialogue_display(a.name + " attacks " + d.name, " with " + str(original_damage_attacker) +
                                  " damage!", d.name + " retaliates with ", str(original_damage_defender) + " damage!")
        else:
            self.dialogue_display(a.name + " attacks " + d.name, " with " + str(original_damage_attacker) + "!")

    def enter_town(self, town, map):
        if town.render == None:
            town.render = Gameboard(10, 12, False)
        while True:
            self.clear_window()
            town.renderer()
            town.render.view_town(town, self)
            visiting_hero = map.square[town.location[0]][town.location[1]].hero
            if visiting_hero and visiting_hero.spellbook != [] and town.buildings.mageGuildLvl > 0:
                    for spell in town.spellbook:
                        if spell not in visiting_hero.spellbook:
                            visiting_hero.spellbook.append(spell)
            choice = self.dialogue_return("What do you want to do?").lower()
            while choice not in ("build", "recruit", "mage guild", "tavern", "view", "exit"):
                choice = self.dialogue_return("See the upper action bar for available commands.").lower()

            if choice == "mage guild":
                if town.buildings.mageGuildLvl > 0:
                    if visiting_hero and visiting_hero.spellbook == []:
                        choice9 = "not yet"
                        while choice9 != "":
                            choice9 = self.dialogue_return(visiting_hero.name +
                                " does not own a spellbook. ", "Do you wish to purchase one for 500 gold?",
                                                           "Enter to purchase, ""C"" to cancel")
                            if choice9 == "" and self.resources.gold > 499:
                                self.resources.gold -= 500
                                self.dialogue_display("You purchased a spellbook!")
                                visiting_hero.can_throw_spell = True
                                for spell in town.spellbook:
                                    if spell not in visiting_hero.spellbook:
                                        visiting_hero.spellbook.append(spell)
                            else:
                                self.dialogue_display("You lack the necessary funds!")
                    town.view_spells()
                else:
                    self.dialogue_display("This town does not have a Mage Guild.")

            elif choice == "build":
                if town.has_built:
                    self.dialogue_display("You can only build once per turn.")
                else:
                    self.townbuilder(town)

            elif choice == "tavern":
                if map.square[town.location[0]][town.location[1]].has_hero:
                    self.dialogue_display("You cannot hire a new hero while your town is occupied by another hero.")
                elif self.has_hired:
                    self.dialogue_display("You have already hired a hero this week.")
                else:
                    choice = self.dialogue_return("Hiring a new hero costs 2500 gold.", "",
                                                  "Press Enter to hire. Press C to cancel.").lower()
                    if self.hero_ticker == 3:
                        self.dialogue_display("Unfortunately there are only three heroes per player.")
                    elif choice != "c" and self.resources.gold >= 2500:
                        self.create_heroes(town.location, map)
                        self.resources.gold -= 2500
                        self.has_hired = True
                        self.dialogue_display("Hero hired! Press Enter to return to map.")
                        return
                    elif choice != "c" and self.resources.gold < 2500:
                        self.dialogue_display("You lack the necessary funds.")

            elif choice == "recruit":
                if visiting_hero == None:
                    choice = "not yet"
                    while choice not in ("", "c"):
                        choice = self.dialogue_return(
                            "You have no hero in town. Purchase army for fortification defense?", "",
                            "\"Enter\" to purchase units. \"C\" to cancel.").lower()
                    if choice == "":
                        visiting_hero = town
                    else:
                        break
                while True:
                    see_price = ""
                    while see_price not in town.unit_names and see_price != "C":
                        see_price = self.dialogue_return("Type a unit to see its price.", "", "Type \"C\" to cancel.").title()
                    if see_price == "C":
                        break
                    else:
                        for i in range(7):
                            if see_price == list(town.unit_names)[i]:
                                available_stack = town.available_units[i]
                                amount = ""
                                while amount == "":
                                    amount = self.dialogue_return(see_price + ".", " Price: " + \
                                        str(town.unit_names.get(see_price)) + " gold.", str(available_stack) \
                                        + " available.", " Type the amount to recruit or C to cancel.")
                                if amount == "C" or amount == "c":
                                    break
                                else:
                                    try:
                                        amount = int(amount)
                                    except ValueError:
                                        print("Numbers only, or C to exit.")
                                        break
                                found = False
                                if amount * town.unit_names.get(
                                        see_price) <= self.resources.gold and amount <= available_stack:
                                    if len(visiting_hero.army) == 7:
                                        for unit in visiting_hero.army:
                                            if unit.name == see_price:
                                                found = True
                                                self.dialogue_display("Your army has run out of space.", "",
                                                                    "The unit will recruit to first existing stack.")
                                                break
                                        if not found:
                                            self.dialogue_display("Your army is full! Press Enter to exit.")
                                            break
                                    if found:
                                        visiting_hero.create_unit(town.kingdom, see_price, amount, True)
                                    else:
                                        visiting_hero.create_unit(town.kingdom, see_price, amount)
                                    town.available_units[i] -= amount
                                    self.resources.gold -= amount * town.unit_names.get(see_price)
                                    self.dialogue_return(str(amount) + " " + see_price + " recruited!")
                                else:
                                    self.dialogue_display("You either do not have the gold", "",
                                                          "or lack available units.")
                                break
            elif choice == "view":
                self.view_info()
            elif choice == "exit":
                break

    def townbuilder(self, town):
        see_price = ""
        prices = None
        req = None
        prices_string = ""
        type = None
        while see_price not in town.buildings_available:
            see_price = self.dialogue_return(str(town.buildings_available), "",
                                             "Type a building to see its price.").title()
        for entry in town.buildings_prices:
            if see_price == entry.get("name"):
                prices = entry.get("price")
                req = entry.get("req")
                type = entry.get("type")
                break
        for resource, price in prices.items():
            if price > 0:
                prices_string = prices_string + str(price) + " "
                prices_string = prices_string + resource + ", "
        choice = self.dialogue_return(see_price, " Requirements: " + req + ". Price: "
                                      + prices_string[:-2], "Press Enter to construct this building. ",
                                      "Type ""C"" to cancel.").lower()
        if choice == "c":
            return
        list_req = req.split(", ")
        funds = True
        for resource in prices.keys():
            if resource in vars(self.resources):
                if vars(self.resources).get(resource) < int(prices.get(resource)):
                    funds = False
                    self.dialogue_display("You lack the necessary funds.")
                    return
        req_fulfilled = True
        for requirement in list_req:
            if "=" in requirement:
                building_and_level = requirement.split("=")
                if building_and_level[0] in vars(town.buildings):
                    if vars(town.buildings).get(building_and_level[0]) < int(building_and_level[1]):
                        req_fulfilled = False
                        self.dialogue_display("You lack the necessary requirements.")
                        return
            elif requirement in vars(town.buildings):
                if vars(town.buildings).get(requirement) == False:
                    req_fulfilled = False
                    self.dialogue_display("You lack the necessary requirements.")
                    return
        if funds and req_fulfilled:
            if see_price == "Capitol":
                town.buildings.hall_lvl = 4
                self.daily.gold += 2000
                town.buildings_available[0] = ""
            elif see_price == "City Hall":
                town.buildings.hall_lvl = 3
                self.daily.gold += 1000
                town.buildings_available[0] = "Capitol"
            elif see_price == "Town Hall":
                town.buildings.hall_lvl = 2
                self.daily.gold += 500
                town.buildings_available[0] = "City Hall"
            elif see_price == "Citadel":
                town.buildings.fort_lvl = 2
                town.buildings_available[1] = "Castle"
            elif see_price == "Castle":
                town.buildings.fort_lvl = 3
                town.buildings_available[1] = ""
            elif see_price[:10] == "Mage Guild":
                town.buildings.mageGuildLvl = int(see_price[11])
                for spell_ids in cur.execute("SELECT spell_ids FROM kingdom_spells WHERE level = " \
                    + str(town.buildings.mageGuildLvl) + " AND kingdom = '" + town.kingdom.lower() + "'"):
                    ids = spell_ids[0].split(",")
                    for id in ids:
                        for level, element, name, cost, damage, effect, color in cur.execute(
                            "SELECT level, element, name, cost, damage, effect, color FROM spells WHERE id = " + id):
                            town.spellbook.append({"level": level, "element": element, "name": name,
                                "cost": cost, "damage": damage, "effect": effect, "color": color})
                if town.buildings.mageGuildLvl < 5:
                    if town.buildings.mageGuildLvl == 4 and town.kingdom == "Castle":
                        town.buildings_available[2] = ""
                    else:
                        town.buildings_available[2] = see_price[:11].title() + str(town.buildings.mageGuildLvl + 1)
                else:
                    town.buildings_available[2] = ""
            elif type[:2] == "dw":
                for building in vars(town.buildings):
                    if building == type:
                        exec('town.buildings.' + building + ' = True')
                        id = int(type[2])
                        town.buildings_available.remove(town.dw_names[id - 1])
                        if type == "dw3": town.available_units[2] = 6
                        elif type == "dw4": town.available_units[3] = 4
                        elif type == "dw5": town.available_units[4] = 3
                        elif type == "dw6": town.available_units[5] = 2
                        elif type == "dw7": town.available_units[6] = 1
                        break
            for resource in prices.keys():
                if resource in vars(self.resources):
                    vars(self.resources)[resource] -= int(prices.get(resource))
            town.has_built = True


import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn import model_selection
from sklearn.linear_model import LinearRegression
from sklearn.ensemble import GradientBoostingRegressor, RandomForestRegressor, AdaBoostRegressor
from sklearn.preprocessing import LabelEncoder, RobustScaler
from sklearn.impute import SimpleImputer
from sklearn.metrics import mean_squared_error, make_scorer
from sklearn.pipeline import make_pipeline
from sklearn.base import BaseEstimator, TransformerMixin, RegressorMixin, clone
from sklearn.neighbors import KNeighborsRegressor
from sklearn.linear_model import Lasso, BayesianRidge, Ridge
from xgboost import XGBRegressor
from mlxtend.regressor import StackingRegressor

# =============================================================================

#Reading the Data
trainingPath = 'data/train.csv'
initialDF = pd.read_csv(trainingPath)

# Digging more into the target variable i.e., SalePrice
def Target(initialDF):
    target = initialDF.loc[:, "SalePrice"]
    #showing the distribution of data using seaborn
    print(target.describe())

    sns.distplot(target)

# ============================================================================
# Data cleaning - conversion, standardization

def checkCorr(initialDF):

    #corrmat = trainDF.corr()
    #correlations = corrmat["SalePrice"].sort_values(ascending=False)
    #features = correlations.index[0:10]
    #print(features)

    #sns.pairplot(trainDF[features], size = 2.5)
    #plt.show()

    # BEGIN: from https://www.kaggle.com/pmarcelino/comprehensive-data-exploration-with-python
    # EXPLANATION: We are visualzing the correlation matrix here using a heatmap to represent
    # different coefficients by different colors
    corrmat = initialDF.corr()
    f, ax = plt.subplots(figsize=(11,9))
    sns.heatmap(corrmat, vmax=.8, square=True)

    k = 10 #number of variables for heatmap
    cols = corrmat.nlargest(k, 'SalePrice')['SalePrice'].index
    cm = np.corrcoef(initialDF[cols].values.T)
    sns.set(font_scale=1.25)
    hm = sns.heatmap(cm, cbar=True, annot=True, square=True, fmt='.2f', annot_kws={'size': 10}, yticklabels=cols.values, xticklabels=cols.values)
    plt.show()
    # END: from https://www.kaggle.com/pmarcelino/comprehensive-data-exploration-with-python

    '''
    According to the heatmap Garage Cars and the Garage Area are the most correlated attribute followed by
    YearBuilt and GarageYrBlt, GrLivArea and TotRmsAbsGr and 1stFlrSF and TotalBsmtSF

    '''

    most_corr = pd.DataFrame(cols)
    most_corr.columns = ['Most Correlated Features']
    print(most_corr)

    #We will check the collinearity between the attributes and eleminate the attribute that is not helpful in predicting sales price

    corr1 = initialDF.loc[:, "GarageArea"].corr(initialDF.loc[:, "GarageCars"])
    corr2 = initialDF.loc[:, "YearBuilt"].corr(initialDF.loc[:, "GarageYrBlt"])
    corr3 = initialDF.loc[:, "GrLivArea"].corr(initialDF.loc[:, "TotRmsAbvGrd"])
    corr4 = initialDF.loc[:, "1stFlrSF"].corr(initialDF.loc[:, "TotalBsmtSF"])

    print("Collinearity between Garage Area and Garage Cars")
    print(corr1)
    print("Collinearity between Year Built and Garage Year Built")
    print(corr2)
    print("Collinearity between Ground Living Area and Total Rooms Above Ground")
    print(corr3)
    print("Collinearity between 1st Floor SF and Total Basement SF")
    print(corr4)

def checkOutliers(initialDF):

    initialDF = featureEngineering(initialDF)

    # Plotting a scatterplot of GrivArea vs SalePrice
    # BEGIN: from https://www.kaggle.com/pmarcelino/comprehensive-data-exploration-with-python
    # EXPLANATION: Dataframes are concatenated and plotted using bivariate analysis
    SPvsGrLivArea = pd.concat([initialDF.loc[:, 'SalePrice'], initialDF.loc[:, 'GrLivArea']], axis=1)
    SPvsGrLivArea.plot.scatter(x='GrLivArea', y='SalePrice', ylim=(0,800000))

    # END: from https://www.kaggle.com/pmarcelino/comprehensive-data-exploration-with-python

    '''
    By looking at the scatterplot we can conclude that people will pay more for more living area but the two
    points on bottom right look off and so do the two points in the top right that are clustered together.
    We will be removing the outliers manually in the handleOutliers function.
    '''

    # Finding the Ids of the outliers in GrLivArea
    print(initialDF.sort_values(by = 'GrLivArea', ascending = False)[:4])

    SPvsYearsOld = pd.concat([initialDF.loc[:, 'SalePrice'], initialDF.loc[:, 'YearsOld']], axis=1)
    SPvsYearsOld.plot.scatter(x='YearsOld', y='SalePrice', ylim=(0,800000))

    '''
    The four points in the extreme right seem way too expensive for an old house. It can be dropped depending
    on the performance of the model.

    '''
    # Finding the Ids of the outliers in YearsOld
    yearsOldOutlier = (initialDF.loc[:, "YearsOld"] > 110) & (initialDF.loc[:, "SalePrice"] > 300000)
    print(initialDF.loc[yearsOldOutlier])

    SPvsLotArea = pd.concat([initialDF.loc[:, 'SalePrice'], initialDF.loc[:, 'LotArea']], axis=1)
    SPvsLotArea.plot.scatter(x='LotArea', y='SalePrice', ylim=(0,800000))

    '''
    The four points on the extreme right seem way out of the trend in the graph. We will be removing the outliers in the
    handle outliers function.
    '''
    # Finding the Ids of the outliers in vsLotArea
    print(initialDF.sort_values(by = 'LotArea', ascending = False)[:4])

    SPvsTotalBsmtSF = pd.concat([initialDF.loc[:, 'SalePrice'], initialDF.loc[:, 'TotalBsmtSF']], axis=1)
    SPvsTotalBsmtSF.plot.scatter(x='TotalBsmtSF', y='SalePrice', ylim=(0,800000))

    TotalBsmtOutlier = (initialDF.loc[:, "TotalBsmtSF"] > 6000)
    print(initialDF.loc[TotalBsmtOutlier])

    # This outlier was calculated above as well

    '''
    There are probably other outliers in the training dataset but removing outliers is not always safe. It can
    effect the model badly if there are outliers in the test dataset as well. Instead of dropping the outliers we
    will try to make some of our models more robust to tacle them.
    '''

def handleOutliers(initialDF):

    # Dropping the 4 outliers in GrLivArea vs SalePrice and 2 outliers in YearsOld vs SalePrice
    droppingOutliers = (initialDF.loc[:, "Id"] == 1299) | (initialDF.loc[:, "Id"] == 524) | (initialDF.loc[:, "Id"] == 1183) | (initialDF.loc[:, "Id"] == 692) | (initialDF.loc[:, "Id"] == 186) | (initialDF.loc[:, "Id"] == 584) | (initialDF.loc[:, "Id"] == 314) | (initialDF.loc[:, "Id"] == 336) | (initialDF.loc[:, "Id"] == 250) | (initialDF.loc[:, "Id"] == 707)
    initialDF = initialDF.drop(initialDF[droppingOutliers].index)

    return initialDF

def checkMissingValues(initialDF):

    # Check the missing values in the entire training dataset
    # Count the values and sort it in descending order
    total = initialDF.isnull().sum().sort_values(ascending=False)
    percent = (initialDF.isnull().sum()/initialDF.isnull().count()).sort_values(ascending=False)
    missing_data = pd.concat([total, percent], axis=1, keys=['Total', 'Percent'])
    sns.heatmap(initialDF.isnull(), yticklabels=False,cbar=False)
    print("Missing Data", missing_data.head(20))

    '''There are attributes in the dataset that contain NaN values. Here, we are identifying the attributes with a lot
    of missing information
    '''
    for var in initialDF.columns:
        if initialDF[var].isnull().mean()>0.80:
            print(var, initialDF[var].unique())

    '''
    We tried to identify the variables that contain a lot of missing information (NaN) so that we can tacle that later
    when we are dropping the attributes
    '''

def handlingMissing(X):
    # We handled the missing values using the imputer
    # If the entire attribute does not have any values i.e, if the entire column consists of
    # missing values we replace the value in the column by 0
    missing_all = False
    for col in X.columns:
        if X.loc[:, col].isnull().all():
            X.loc[:, col] = 0

    # BEGIN: from https://www.kaggle.com/dansbecker/handling-missing-values
    # EXPLANATION: Imputers can fill in missing values with mean values by default. Filling
    # in missing values is usually better than dropping them entirely because
    # those that are not missing might indicate some valuable patterns.
    imputer = SimpleImputer(missing_values = np.nan , strategy = 'mean')
    imputer = imputer.fit(X)
    X = imputer.transform(X)
    # END: from https://www.kaggle.com/dansbecker/handling-missing-values
    return X

def featureEngineering(originalDF):

    # Replacing yearBuilt to yearsOld so that we can plot the attribute vs SalePrice and check if there are any outliers
    yearBuilt = originalDF.loc[:, "YearBuilt"]
    # subtracting by 2006 since the data was calculated between 2006 and 2010
    originalDF.loc[:, "YearsOld"] = 2006 - originalDF.loc[:, "YearBuilt"]

    # BEGIN: https://www.kaggle.com/serigne/stacked-regressions-top-4-on-leaderboard
    # EXPLANATION: We are replacing the categorical values such as BsmtQual with a numeric value between
    # 0 and the number of class minus 1 by the use of Label Encoder. It is being used because some categorial
    # value might contain some information in the dataset.
    EncoderList = ["KitchenQual", "GarageQual", "BsmtQual", "BsmtCond", "ExterQual", "GarageCond",
                     "OverallCond", "FireplaceQu", "ExterCond", "HeatingQC", "BsmtFinType1", "BsmtFinType2"]
	# Label Encoder
    for column in EncoderList:
        lbl = LabelEncoder()
        lbl.fit(list(initialDF[column].values))
        initialDF[column] = lbl.transform(list(initialDF[column].values))
    # END: https://www.kaggle.com/serigne/stacked-regressions-top-4-on-leaderboard

    return originalDF

def standardize(df):

    Cols = df.select_dtypes(exclude=['object']).columns

    stds = df.loc[:, Cols].std()
    mean = df.loc[:, Cols].mean()

    df.loc[:, Cols] = (df.loc[:, Cols] - mean) / stds

    return df

# ===============================================================================

# The data is experimented with different pre-processing methods
def testResults(initialDF):

    # Build and test Grandient Boosting Regressor
    def testGBR(df, n_estimators=100, max_depth=3):
        y = df.loc[:, "SalePrice"]
        X = df.drop(["SalePrice"], axis=1)
        gbr = GradientBoostingRegressor(n_estimators=n_estimators, max_depth=max_depth)

        X = handlingMissing(X)

        cvScores = model_selection.cross_val_score(gbr, X, y, cv=10,
                                                   scoring = 'neg_mean_squared_error')
        print("\tMean Squared Error:", -1 * cvScores.mean())

    # Build and test Random Forest Regressor
    def testRF(df):
        y = df.loc[:, "SalePrice"]
        X = df.drop(["SalePrice"], axis=1)
        rf = RandomForestRegressor()

        X = handlingMissing(X)

        cvScores = model_selection.cross_val_score(rf, X, y, cv=10,
                                                   scoring = 'neg_mean_squared_error')
        print("\tMean Squared Error:", -1 * cvScores.mean())

    #Perform feature Engineering
    initialDF = featureEngineering(initialDF)

    # Dropping the Outliers
    initialDF = handleOutliers(initialDF)

    # Standardize the Data
    initialDF.loc[:, initialDF.columns != "SalePrice"] = standardize(initialDF.drop(["SalePrice"], axis=1))

    """
    One Hot Encoding and Binary encoding
    """
    # One Hot Encoding
    colNames = ['SalePrice', 'LotArea', 'Neighborhood','OverallQual','GrLivArea','FullBath','GarageCars','YearsOld']
    trainPredictors = initialDF.loc[:, colNames]
    selected_hot_DF = pd.get_dummies(trainPredictors)
    print(selected_hot_DF)
    # The attributues with more than 80% missing values are dropped
    most_hotDF = pd.get_dummies(initialDF.drop(['PoolQC', 'MiscFeature', 'Alley','Fence'], axis=1))
    # The attributes with more than 90% missing values and high correlation (GarageCars and GarageArea) values are dropped
    drop_corrDF = pd.get_dummies(initialDF.drop(['PoolQC', 'MiscFeature', 'Alley', 'GarageArea', 'YearBuilt'], axis=1))

    '''
    Displaying the Gradient Boosting Regressor and Random Forest Regressor Results
    '''

    print("Graident Boosting Regressor with 100 estimators ")
    print("Performing GBR on Selected Columns")
    testGBR(selected_hot_DF)
    print("Performing GBR on all Attributes except for ones with many missing values")
    testGBR(most_hotDF)
    print("Performing GBR on all Attributes except for ones with many missing values or high correlation")
    testGBR(drop_corrDF)

    print()

    print("Graident Boosting Regressor with 200 estimators")
    testGBR(selected_hot_DF, n_estimators=200)
    print(" Performing GBR on all Attributes except for ones that have many missing values")
    testGBR(most_hotDF, n_estimators=200)
    print("Performing GBR on all Attributes except for ones that have many missing values or Highly Correlated Attributes")
    testGBR(drop_corrDF, n_estimators=200)

    # We can see that the Mean Squared Error is redured by increasing the estimators
    print()

    print("Random Forest Regressor")
    print("Performing GBR on Selected Columns")
    testRF(selected_hot_DF)
    print("Performing GBR on all Attributes except for ones that have many missing values")
    testRF(most_hotDF)
    print("Performing GBR on all Attributes except for ones that have many missing values or Highly Correlated Attributes")
    testRF(drop_corrDF)

# The best pre processing is done by One Hot Encoder in the above trails
def preprocess(initialDF):

    # Performing feature engineering
    initialDF = featureEngineering(initialDF)
    # Dropping the outliers
    initialDF = handleOutliers(initialDF)
    # Standardizing the Data
    initialDF.loc[:, initialDF.columns != "SalePrice"] = standardize(initialDF.drop(["SalePrice"], axis=1))

    # The attributues with more than 80% missing values are dropped
    most_hotDF = pd.get_dummies(initialDF.drop(['PoolQC', 'MiscFeature', 'Alley','Fence'], axis=1))

    y = most_hotDF.loc[:, "SalePrice"]
    X = most_hotDF.drop(["SalePrice"], axis=1)
    X = handlingMissing(X)
    y = np.log1p(y)

    return X, y

# Storing X and y as Global variables
X, y = preprocess(initialDF)

# BEGIN: https://github.com/Shitao/Kaggle-House-Prices-Advanced-Regression-Techniques/blob/master/code/single_model/base_model.py
# EXPLANATION: We want the search to evaluate the model's performance using RMSE and we do that by defining a function
# that creates a scorer for GridSearchCV

def mean_squared_error_(ground_truth, predictions):
    return mean_squared_error(ground_truth, predictions) ** 0.5

RMSE = make_scorer(mean_squared_error_, greater_is_better=False)
# END: https://github.com/Shitao/Kaggle-House-Prices-Advanced-Regression-Techniques/blob/master/code/single_model/base_model.py

# Rough hyperparameter tuning is performed one at a time and is done by XSEDE allocation
# Tuning the gradient boosting regressor
def tuneGBR(df):
    X, y = preprocess(df)

    """
    param_test1 = {'min_samples_split':range(2,20)}
    gsearch1 = model_selection.GridSearchCV(
            estimator = GradientBoostingRegressor(
                learning_rate = 0.01,
                n_estimators = 1000,
                min_samples_leaf = 1,
                max_depth = 4,
                max_features = 'sqrt',
                subsample = 0.8,
                random_state = 0
                ),
            param_grid = param_test1,
            scoring = RMSE,
            iid = False,
            cv = 10
        )
    gsearch1.fit(X, y)
    print("Best param and its score", gsearch1.best_params_, -gsearch1.best_score_, sep='\n')

    param_test2 = {'min_samples_leaf':range(2,10)}
    gsearch2 = model_selection.GridSearchCV(
            estimator = GradientBoostingRegressor(
                learning_rate = 0.01,
                n_estimators = 1000,
                min_samples_split = 17,
                max_depth = 4,
                max_features = 'sqrt',
                subsample = 0.8,
                random_state = 0
                ),
            param_grid = param_test2,
            scoring = RMSE,
            iid = False,
            cv = 10
        )
    gsearch2.fit(X, y)
    print("Best param and its score", gsearch2.best_params_, -gsearch2.best_score_, sep='\n')
    """
    """
    param_test3 = {'max_depth':range(2,10)}
    gsearch3 = model_selection.GridSearchCV(
            estimator = GradientBoostingRegressor(
                learning_rate = 0.01,
                n_estimators = 1000,
                min_samples_leaf = 3,
                min_samples_split = 17,
                max_features = 'sqrt',
                subsample = 0.8,
                random_state = 0
                ),
            param_grid = param_test3,
            scoring = RMSE,
            iid = False,
            cv = 10
        )
    gsearch3.fit(X, y)
    print("Best param and its score", gsearch3.best_params_, -gsearch3.best_score_, sep='\n')
    """

    param_test4 = {'subsample': [0.76, 0.78, 0.82, 0.84]}
    gsearch4 = model_selection.GridSearchCV(
            estimator = GradientBoostingRegressor(
                learning_rate = 0.01,
                n_estimators = 1000,
                min_samples_leaf = 3,
                min_samples_split = 17,
                max_depth = 5,
                max_features = 'sqrt',
                random_state = 0
                ),
            param_grid = param_test4,
            scoring = RMSE,
            iid = False,
            cv = 10
        )
    gsearch4.fit(X, y)
    print("Best param and its score", gsearch4.best_params_, -gsearch4.best_score_, sep='\n')

# Making a dictionary of all the models so that we can calculated the RMSE later
models = {

          "gbr": GradientBoostingRegressor(n_estimators=1000,
                                           learning_rate=0.01,
                                           min_samples_split=17,
                                           min_samples_leaf=7,
                                           max_depth=5,
                                           max_features='sqrt',
                                           subsample=0.8,
                                           random_state=0),

          "xgb": XGBRegressor(n_estimators=1000,
                              learning_rate=0.01,
                              min_child_weight=3,
                              max_depth=6,
                              gamma=0,
                              subsample=0.8,
                              colsample_bytree=0.85,
                              random_state=0),
          "rf": RandomForestRegressor(n_estimators=1000,
                                      bootstrap=True,
                                      max_features='sqrt',
                                      max_depth=6,
                                      min_samples_split=3,
                                      min_samples_leaf=1,
                                      random_state=0),
          "knn": KNeighborsRegressor(n_neighbors = 10),
          "ada": AdaBoostRegressor(n_estimators=1000,
                                   learning_rate=0.01,
                                   loss='square',
                                   random_state=0),
          # BEGIN: https://www.kaggle.com/gmishrakec/multi-regression-techniques/code
          # EXPLANATION: We are using the RobustScaler to make the lasso regression more Robust
          # since it is one of the regression model that is very sensitive to outliers
          "lasso": make_pipeline(RobustScaler(), Lasso(alpha =0.0005,
                                                       random_state=0)),
          # END: https://www.kaggle.com/gmishrakec/multi-regression-techniques/code
          "bayridge": BayesianRidge(),
          "ridge": Ridge()
         }

# This function takes a model name in string
def tryModel(modelName):
    try:
        alg = models[modelName]
        X, y = preprocess(initialDF)
        cvScores = model_selection.cross_val_score(alg, X, y, cv=10, scoring = RMSE)

        print("RMSE: {:.6f} ({:.4f})".format(-cvScores.mean(), cvScores.std()))
    except:
        print("This particular model does not exist in the dictionary of models")

# BEGIN: https://www.kaggle.com/serigne/stacked-regressions-top-4-on-leaderboard
# EXPLANATION: We are calculating the final score by taking weighted average
# of the predictions from each model. The code has been modified to calculate the weighted
# average instead of arithmetic average to get a better score
class AveragingModels(BaseEstimator, RegressorMixin, TransformerMixin):
    def __init__(self, models, weights):
        self.models = models
        self.weights = weights
        if len(weights) != len(models):
            print("ERROR: The number of models and weights do not match.")
            return
        if sum(weights) != 1.0:
            print("The sum of weights is required to be 1")
            return

    # we define clones of the original models to fit the data in
    def fit(self, X, y):
        self.models_ = [clone(x) for x in self.models]

        # Train cloned base models
        for model in self.models_:
            model.fit(X, y)

        return self

    #Now we do the predictions for cloned models and average them
    def predict(self, X):
        predictions = np.column_stack([
            model.predict(X) for model in self.models_
        ])
        #return np.mean(predictions, axis=1)
        predictionsDF = pd.DataFrame(data=predictions)
        weightedPredictions = predictionsDF.apply(lambda prediction: prediction * self.weights, axis=1)
        return np.sum(weightedPredictions, axis=1)

# END: https://www.kaggle.com/serigne/stacked-regressions-top-4-on-leaderboard

# An array of model names in string and a meta model name in string is taken as the parameters of the function
def tryStackingModels(modelNames, metaModelName):
    X, y = preprocess(initialDF)
    regs = [models[modelName] for modelName in modelNames]
    meta = models[metaModelName]

    stack = StackingRegressor(regressors = regs,
                              meta_regressor = meta)

    cvScores = model_selection.cross_val_score(stack, X, y, cv=10, scoring = RMSE)

    print("RMSE: {:.6f} ({:.4f})".format(-cvScores.mean(), cvScores.std()))

# An array of model names in string is taken as the parameter
def tryAveragingModels(modelNames, pWeights):
    try:
        X, y = preprocess(initialDF)
        algs = tuple(models[modelName] for modelName in modelNames)
        # This gives an equal weight on every model
        # averaged_models = AveragingModels(models = algs, weights = [1/len(algs) for i in range(len(algs))])
        averaged_models = AveragingModels(models = algs, weights = pWeights)
        cvScores = model_selection.cross_val_score(averaged_models, X, y, cv=10, scoring=RMSE)

        print("RMSE: {:.6f} ({:.4f})".format(-cvScores.mean(), cvScores.std()))
    except:
        print("The specified models do not exist in the models.")

'''
Runs the algorithm on the testing set and writes the results to a csv file.
'''
def doKaggleTest(initialDF):

    print("File Name?")
    filename = input()

    # Reading the test dataset
    testDF = pd.read_csv("data/test.csv")
    testIDs = testDF.loc[:, "Id"]

    # Dropping the Outliers
    initialDF = handleOutliers(initialDF)

    y = initialDF.loc[:, "SalePrice"]
    y = y.values
    trainDF = initialDF.drop(["SalePrice"], axis=1)

    # Concatinate test and initial (=train)
    train_numRow = trainDF.shape[0]
    dataset = pd.concat(objs=[trainDF, testDF], axis=0)

    # created full dataset using One-Hot Encoding and Feature Engineering

    dataset = pd.get_dummies(dataset)
    dataset = featureEngineering(dataset)

    # The numbers of features in the testing dataset and initial dataset (trainDF) needs to match
    # So we split the dataset
    trainDF = dataset.iloc[:train_numRow, :].copy()
    testDF = dataset.iloc[train_numRow:, :].copy()

    trainDF = standardize(trainDF) #standardizing the training dataset

    """ # Weighted Average
    modelNames = ["gbr", "xgb", "lasso", "ridge"]
    algs = tuple(models[modelName] for modelName in modelNames)
    model = AveragingModels(models = algs, weights = [0.24, 0.07, 0.46, 0.09])
    """

    model = models["ridge"]

    trainDF = handlingMissing(trainDF)
    model.fit(trainDF, y)   #fitting the model with trainig data

    # Preprocessing the test dataset
    testDF = standardize(testDF)
    testDF = handlingMissing(testDF)

    predictions = model.predict(testDF)
    # Create a new dataframe with only the columns Kaggle wants from the dataset.
    submission = pd.DataFrame({
        "Id": testIDs,
        "SalePrice": predictions
    })

    # Prepare CSV
    submission.to_csv('data/testResults.csv', index=False)
    # Now, this .csv file can be uploaded to Kaggle


# config : utf-8

import os
import sys
import psutil
import shutil

print ('Hi, Jackson!')
name = input("What's your name?")
print ("Hi, ", name)

answer = ''
while answer != 'q':
    answer = input("Shal we? y/n/q")
    if answer == "y":
        print ("OK")
        print ("1 - вывести инфо о системе")
        print ("2 - список файлов текущей дирректории")
        print ("3 - список ID активных процессов")
        print ("4 - дублирование файлов текущей дирректории")
        print ("5 - удаление дубликатов файлов текущей дирректории")

        do = int(input("Что делаем?  "))

        if do == 1:
            print ("процессоров: ", psutil.cpu_count())
            print ("Платформа: ", sys.platform)
            print ("Пользователь: ", os.getlogin())
        elif do == 2:
            print ("Список файлов: ", os.listdir())
        elif do == 3:
            print ("Списк процессов (ID): ", psutil.pids())
        elif do == 4:
            print("Дублирование файлов указанной дирректории")
            file_list = os.listdir()
            i = 0
            while i < len(file_list):
                if os.path.isfile(file_list[i]):
                    newfile = file_list[i] + '.dupl'
                    shutil.copy(file_list[i], newfile)
                    i += 1
                else:
                    pass

        else:
            pass

    elif answer == "n":
        print ("Sad")
    else:
        print ("Pitty")


#!/usr/bin/env python

from __future__ import unicode_literals, division

__author__ = "Rachel Kurchin, Riley Brandt, Daniil Kitchaev"
__date__ = "May 17, 2017"

from run_scaps_parallel import SCAPSrunner
import numpy as np
from copy import deepcopy
import pickle
import os
import argparse
import json

def scaps_output_processor(return_path):
    """
    Convert output of a SCAPS simulation to a numpy format for further processing
    """
    ii, simList, summaryList, dataLines = 0, [], [], []
    with open(return_path,'r') as f:
        for line in f:
            if 'jtot' in line: simList.append(ii)
            elif 'deduced' in line: summaryList.append(ii)
            ii += 1

    for xi, x in enumerate(simList):
        dataLines.extend(list(range(x + 2, summaryList[xi] - 1)))

    JArray, VArray = np.zeros(len(dataLines)), np.zeros(len(dataLines))

    ii = 0
    with open(return_path,'r') as f:
        for jj, line in enumerate(f):
            if jj in dataLines:
                floats = [float(x) for x in line.split("\t")]
                JArray[ii] = floats[1]
                VArray[ii] = floats[0]
                ii += 1

    return (JArray, VArray)

def scaps_script_generator(calc_param):
    """
    Generate SCAPS simulation input script as a string.
    """
    return "\n".join(["//Script file made by Python",
                       "set quitscript.quitSCAPS",
                       "load allscapssettingsfile {}".format(calc_param['def']),
                       "set errorhandling.overwritefile",
                       "set layer1.mun %f" % calc_param['mu_n_l'],
                       "set layer1.defect1.Ntotal %f" % calc_param['Nt_SnS_l'],
                       "set layer2.chi %f" % calc_param['EA_ZnOS_l'],
                       "set interface1.IFdefect1.Ntotal %f" % calc_param['Nt_i_l'],
                       "action workingpoint.temperature %f" % calc_param['T_l'],
                        "action iv.startv %f" % 0.0,
                        "action iv.stopv %f" % calc_param['V_max'],
                        "action iv.increment %f" % 0.02,
                        "action intensity.T %f" % calc_param['ill_l'],
                        "calculate"])

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('-si', help="Start index for this run", type=int, default=0)
    parser.add_argument('-ni', help="Number of inputs to run here", type=int, default=0)
    parser.add_argument('-node', help="Node index (proc index offset)", type=int, default=0)
    args = parser.parse_args()

    node = args.node

    # Initialize SCAPS runner object
    scaps_runner = SCAPSrunner(ncores=32,
                               input_processor=scaps_script_generator,
                               output_processor=scaps_output_processor)

    baseline_run = {'def': "SnS_base.scaps",
                    'mu_n_l': 60,
                    'Nt_SnS_l': 1e17,
                    'EA_ZnOS_l': 4.0,
                    'Nt_i_l': 1e10,
                    "V_max": 0.5}

    temperatures = np.array([280, 300, 320])
    illuminations = np.array([31, 108])
    mu_n_range = np.linspace(20, 80, 20)
    Nt_SnS_range = np.logspace(16, 18, 20)
    EA_ZnOS_range = np.linspace(3.4, 4.3, 15)
    Nt_i_range = np.logspace(10, 14, 16)

    inputs = {}
    i = 0

    for temp in temperatures:
        for ill in illuminations:
            for Nt_i in Nt_i_range:
                for mu_n in mu_n_range:
                    for Nt in Nt_SnS_range:
                        for EA in EA_ZnOS_range:
                            run=deepcopy(baseline_run)
                            baseline_run['Nt_i_l'] = Nt_i
                            run['mu_n_l'] = mu_n
                            run['Nt_SnS_l'] = Nt
                            run['EA_ZnOS_l'] = EA
                            run['T_l'] = temp
                            run['ill_l'] = ill
                            inputs[i] = run
                            i += 1

    with open("input_parameters.json", 'w') as fout:fout.write(json.dumps(inputs))

    n_batches = 16
    for batch_i in range(n_batches):
        batch_size = int((args.si + args.ni)/n_batches)
        batch_inputs = {}
        for pt_i in range(args.si + batch_i * batch_size, args.si + batch_i * batch_size + batch_size):
            batch_inputs[pt_i] = inputs[pt_i]

        # Run the inputs
        print("[Batch {}] Starting SCAPS runs ({}-{})".format(batch_i, args.si + batch_i * batch_size, args.si + batch_i * batch_size + batch_size))
        outputs = scaps_runner.run_inputs(batch_inputs, print_progress=True)

        # Save outputs
        print("[Batch {}] Saving outputs as pickles...".format(batch_i))
        pickle.dump(outputs, open("simulation_{}_{}_n{}_b{}.pickle".format(args.si + batch_i * batch_size,
                                                                           args.si + batch_i * batch_size + batch_size,
                                                                           node,
                                                                           batch_i),"wb"))


## Authors: Daler Norkulov, Kendall Molas
from scipy import signal
from scipy.io.wavfile import write
import matplotlib.axes
import matplotlib.pyplot as plt
import numpy as np
from scipy.fftpack import fft, rfft

##
# Standard sampling rate of audio cds.
# @input: Some sampling rate that is within the range of the harmonics
sampling_rate = 44100

##
# Notes within the 4 and 5th harmonic range
# Fundamental frequencies determined from https://en.wikipedia.org/wiki/Scientific_pitch_notation
C5_freq = 523.25
B4_freq = 493.88
G4_freq = 392.00
A4_freq = 440.00
F4_freq = 349.23
E4_freq = 329.63
C4_freq = 261.63

'''
Time signature is a 4/4 so each note have specific durations
quarter note: 1s
eighth note with dot notation : 0.75s
eight note: 0.5s
sixteenth note: 0.25s
'''

quarter_note = 1
eighth_note = 0.5
eighth_note_with_dot = 0.75
sixteenth_note = 0.25

# Creates a numpy array with parameters: start, end, number of samples to generate (amount of time sound plays)
# Creation of numpy arrays that will allow the notes to play for the specific durations
quarter_note_sampling_time = np.linspace(0, quarter_note, quarter_note*sampling_rate)
eighth_note_with_dot_sampling_time = np.linspace(0, eighth_note_with_dot, eighth_note_with_dot*sampling_rate)
sixteenth_note_sampling_time = np.linspace(0, sixteenth_note, sixteenth_note*sampling_rate)
eighth_note_sampling_time = np.linspace(0, eighth_note, eighth_note*sampling_rate)

# Measure 1
measure_1_note_1 = signal.chirp(quarter_note_sampling_time, C5_freq, quarter_note, C5_freq)
measure_1_note_2 = signal.chirp(eighth_note_with_dot_sampling_time, G4_freq, eighth_note_with_dot, G4_freq)
measure_1_note_3 = signal.chirp(sixteenth_note_sampling_time, A4_freq, sixteenth_note, A4_freq)
measure_1_note_4 = signal.chirp(quarter_note_sampling_time, B4_freq, quarter_note, B4_freq)
measure_1_note_5 = signal.chirp(eighth_note_sampling_time, E4_freq, eighth_note, E4_freq)
measure_1_note_6 = signal.chirp(eighth_note_sampling_time, E4_freq, eighth_note, E4_freq)

# Measure 2
measure_2_note_1 = signal.chirp(quarter_note_sampling_time, A4_freq, quarter_note, A4_freq)
measure_2_note_2 = signal.chirp(eighth_note_with_dot_sampling_time, G4_freq, eighth_note_with_dot, G4_freq)
measure_2_note_3 = signal.chirp(sixteenth_note_sampling_time, F4_freq, sixteenth_note, F4_freq)
measure_2_note_4 = signal.chirp(quarter_note_sampling_time, G4_freq, quarter_note, G4_freq)
measure_2_note_5 = signal.chirp(eighth_note_sampling_time, C4_freq, eighth_note, C4_freq)
measure_2_note_6 = signal.chirp(eighth_note_sampling_time, C4_freq, eighth_note, C4_freq)

# Combine into one big numpy array...
total_measures = np.hstack((measure_1_note_1, measure_1_note_2, measure_1_note_3, measure_1_note_4,
measure_1_note_5, measure_1_note_6, measure_2_note_1, measure_2_note_2, measure_2_note_3, measure_2_note_4,
measure_2_note_5, measure_2_note_6))

# Output audio clip from frequencies
# Measures are all in continuous time already, so no need to multiply by 2.
write("USSR.wav", sampling_rate, total_measures)

# Duration of the created song
song_duration = np.size(total_measures)/sampling_rate

# X axis for the time based graph
time_sampled_for_time_graph = np.linspace(0, song_duration, np.size(total_measures))

# X axis for the frequency based graph
time_sampled_for_frequency_graph = np.linspace(0, sampling_rate, np.size(total_measures))

##
# Plotting
fig, (time_plot, frq_plot, spectogram_plot) = plt.subplots(3,1, sharex=False, sharey=False, figsize=(5,5))
plt.tight_layout()

#
# Because there is sound constantly playing, the output of this time graph will look like a blue signal
# Time Domain Graph
time_plot.plot(time_sampled_for_time_graph, total_measures)
time_plot.set_xlabel("Time (sec)")
time_plot.set_ylabel("Amplitude")

#
# Frequency Graph
x = abs(fft(total_measures))
frq_plot.plot(time_sampled_for_frequency_graph, x, 'r')
frq_plot.set_xlabel("Frequency (Hz)")
frq_plot.set_ylabel("|Y(jw)|")

#
# Spectrogram graph
f, t, Sxx = signal.spectrogram(total_measures, sampling_rate)

# Plots quadrilateral mesh
spectogram_plot.pcolormesh(t,f,Sxx)
spectogram_plot.set_ylabel("Frequency (Hz)")
spectogram_plot.set_xlabel("Time (sec)")
plt.show()


# QLable

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel
from PyQt5.QtGui import QPixmap

class Lable(QWidget):
    def __init__(self):
        super().__init__()
        self.initGUI()

    def initGUI(self):
        self.setGeometry(100,100,900,700)
        self.setWindowTitle('gui demo')

        self.lable1 = QLabel(self)
        self.lable1.setText('Python Class')
        self.lable1.move(390, 40)

        self.lable2 = QLabel(self)
        self.lable2.setToolTip('http://goo.gl/pB9kmb')
        self.lable2.setText("<a href='http://goo.gl/pB9kmb'> Surprise URL </a>")
        self.lable2.move(390,90)
        self.lable2.setOpenExternalLinks(True)

        self.lable3 = QLabel(self)
        self.lable3.move(80, 130)
        self.lable3.setPixmap(QPixmap('a.png'))

        self.show()

if __name__ == "__main__":
        app = QApplication(sys.argv)
        Lable = Lable()
        sys.exit(app.exec_())


from __future__ import print_function

import sys
import os
import signal
import pwd
import grp
import time
import platform
import re
import subprocess

portosrc = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
portobin = os.getcwd()
portoctl = portobin + "/portoctl"
portod = os.path.abspath(portobin + "/portod")
portotest = portobin + "/portotest"

try:
    import google.protobuf
except ImportError as e:
    print(e)
    sys.exit(0)

def Catch(func, *args, **kwargs):
    try:
        func(*args, **kwargs)
    except:
        return sys.exc_info()[0]
    return None

def Expect(a):
    assert a, "condition does not hold"

def ExpectEq(a, b):
    assert a == b, "{} should be equal {}".format(a, b)

def ExpectNe(a, b):
    assert a != b, "{} should not be equal {}".format(a, b)

def ExpectLe(a, b, descr=""):
    assert a <= b, "{}{} should be less or equal {}".format(descr, a, b)

def ExpectRange(a, l, h):
    assert l <= a <= h, "{} should be within {} .. {}".format(a, l, h)

def ExpectProp(ct, prop, val):
    cur = ct.GetProperty(prop)
    assert cur == val, "{} property {} should be {} not {}".format(ct, prop, val, cur)

def ExpectPropNe(ct, prop, val):
    cur = ct.GetProperty(prop)
    assert cur != val, "{} property {} value {} should be not equal to {}".format(ct, prop, val, cur)

def ExpectPropGe(ct, prop, val):
    cur = int(ct.GetProperty(prop))
    assert cur >= val, "{} property {} should be at least {} not {}".format(ct, prop, val, cur)

def ExpectPropLe(ct, prop, val):
    cur = int(ct.GetProperty(prop))
    assert cur <= val, "{} property {} should be at most {} not {}".format(ct, prop, val, cur)

def ExpectPropRange(ct, prop, low, high):
    cur = int(ct.GetProperty(prop))
    assert low <= cur <= high, "{} property {} should be within {} .. {} not {}".format(ct, prop, low, high, cur)

def ExpectException(func, exc, *args, **kwargs):
    tmp = Catch(func, *args, **kwargs)
    assert tmp == exc, "method {} should throw {} not {}".format(func, exc, tmp)

def ExpectFile(path, mode, dev=0):
    try:
        st = os.lstat(path)
        assert st.st_mode == mode, "file {} mode {} should be {}".format(path, st.st_mode, mode)
        assert st.st_rdev == dev, "device {} {:x} should be {:x}".format(path, st.st_rdev, dev)
    except OSError:
        assert mode == None, "file {} not found".format(path)

def ParseMountinfo(pid="self"):
    ret = {}
    for line in open("/proc/{}/mountinfo".format(pid), "r"):
        l = line.split()
        sep = l.index('-')
        m = { 'mount_id': l[0], 'parent_id': l[1], 'dev': l[2], 'bind': l[3], 'target': l[4], 'flag': l[5].split(','), 'type': l[sep+1], 'source': l[sep+2], 'opt': l[sep+3].split(',') }
        for tag in l[6:sep]:
            if ':' in tag:
                n, v = tag.split(':', 2)
                m[n] = v
            else:
                m[tag] = True
        # override lower mounts
        ret[m['target']] = m
    return ret

def ParseCgroup(pid):
    ret = {}
    for line in open("/proc/{}/cgroup".format(pid), "r"):
        l = line.split(':')
        ret[l[1]] = l[2].strip()
    return ret

def WithSystemd():
    return os.path.islink("/sbin/init") and os.readlink("/sbin/init").endswith("/systemd")

def GetSystemdCg(pid):
    return ParseCgroup(pid).get('name=systemd')

def MemoryStat(ct, stat):
    for line in ct.GetProperty("memory.stat").splitlines():
        k, v = line.split()
        if k == stat:
            return int(v)
    return None

def ExpectMemoryStatLe(ct, stat, val):
    cur = MemoryStat(ct, stat)
    assert cur is not None, "{} memory.stat:{} not found".format(ct, stat)
    assert cur <= val, "{} memory.stat:{} should be at most {} not {}".format(ct, stat, val, cur)

def UserId(name):
    try:
        return pwd.getpwnam(name).pw_uid
    except KeyError:
        return None

def GroupId(name):
    try:
        return grp.getgrnam(name).gr_gid
    except KeyError:
        return None

alice_uid=UserId("porto-alice")
alice_gid=GroupId("porto-alice")

bob_uid=UserId("porto-bob")
bob_gid=GroupId("porto-bob")

charlie_uid=UserId("porto-charlie")
charlie_gid=GroupId("porto-charlie")

david_uid=UserId("porto-david")
david_gid=GroupId("porto-david")

porto_gid=GroupId("porto")

def AsRoot():
    os.setresgid(0, 0, 0)
    os.setresuid(0, 0, 0)
    os.setgroups([0])

def SwitchUser(username, uid, gid):
    os.initgroups(username, uid)
    os.setresgid(gid, gid, 0)
    os.setresuid(uid, uid, 0)

def AsAlice():
    SwitchUser("porto-alice", alice_uid, alice_gid)

def AsBob():
    SwitchUser("porto-bob", bob_uid, bob_gid)

def AsCharlie():
    SwitchUser("porto-charlie", charlie_uid, charlie_gid)

def AsDavid():
    SwitchUser("porto-david", david_uid, david_gid)

def GetPortodPid():
    pid = int(open("/run/portod.pid").read())
    open("/proc/" + str(pid) + "/status").readline().index("portod")
    return pid

def GetMasterPid():
    pid = int(open("/run/portoloop.pid").read())
    open("/proc/" + str(pid) + "/status").readline().index("portod-master")
    return pid

def ReloadPortod():
    pid = GetPortodPid()
    os.kill(GetMasterPid(), signal.SIGHUP)
    try:
        for i in range(3000):
            os.kill(pid, 0)
            time.sleep(0.1)
        raise Exception("cannot reload porto")
    except OSError:
        pass

def StopPortod():
    global portod
    subprocess.check_call([portod, 'stop'])

def RestartPortod():
    # Note that is restart, not reload!
    # Thus we intentionally want to drop state

    global portod
    subprocess.check_call([portod, 'restart'])

def CleanupConfigs():
    for f in os.listdir('/etc/portod.conf.d'):
        os.unlink('/etc/portod.conf.d/%s' % f)

def ConfigurePortod(name, conf):
    path = '/etc/portod.conf.d/{}.conf'.format(name)
    if os.path.exists(path) and open(path).read() == conf:
        return
    if conf:
        if not os.path.exists('/etc/portod.conf.d'):
            os.mkdir('/etc/portod.conf.d', 0o775)
        open(path, 'w').write(conf)
    elif os.path.exists(path):
        os.unlink(path)
    ReloadPortod()

def ProcStatus(pid, key):
    for line in open("/proc/{}/status".format(pid)).readlines():
        k, v = line.split(None, 1)
        if k == key + ":":
            return v.strip()
    return None

def GetState(pid):
    if isinstance(pid, int):
        pid = str(pid)
    ss = open("/proc/" + pid + "/status").readlines()
    for s in ss:
        if s.find("State:") >= 0:
            return s.split()[1]
    return ""

def IsRunning(pid):
    try:
        os.kill(pid, 0)
        state = GetState(pid)
        return state != "Z" and state != "X"
    except:
        return False

def IsZombie(pid):
    return GetState(pid) == "Z"

def KillPid(pid, signal):
    os.kill(pid, signal)
    try:
        ctr = 0
        while ctr < 100:
            time.sleep(0.1)
            os.kill(pid, 0)
            ctr += 1

        raise BaseException("Too long waited for portod to stop")
    except OSError:
        pass

def GetMeminfo(tag):
    meminfo = open("/proc/meminfo", "r").readlines()
    for m in meminfo:
        if m.find(tag) >= 0:
            return int(m.split()[1]) * 1024

def get_kernel_maj_min():
    kver = re.match("([0-9])\.([0-9]{1,2})", platform.uname()[2]).groups()
    return (int(kver[0]), int(kver[1]))

if not os.environ.get('PORTO_TEST_NO_RESTART', None):
    CleanupConfigs()
    RestartPortod()