# Specialist Data Repo

specialists = [
    {   # Leader
        "specname":"Leader",
        "tactics":[
            {
                "tacname":"Lead by Example",
                "speclvl":1,
                "comcost":1,
                "descrip":"Use this tactic when you pick a Leader from your kill team to fight in the Fight phase. Choose another friendly model within 3\" of them that is eligible to fight. You can fight with each of these models, in an order of your choice, before the next player's turn."
            },
            {
                "tacname":"Fire on my Target",
                "speclvl":2,
                "comcost":1,
                "descrip":"Use this Tactic when you pick a Leader of Level 2 or higher from your kill team to shoot in the Shooting phase. Choose another friendly model within 3\" of them that is eligible to shoot. You can make a shooting attack with each of these models, in an order of your choice, before the next player’s turn."
            },
            {
                "tacname":"Force of Will",
                "speclvl":3,
                "comcost":1,
                "descrip":"Use this Tactic at the start of the battle round, if a Leader of Level 3 or higher from your kill team is on the battleeld and not shaken. In this battle round, your kill team does not suer the penalty for being broken."
            },
        ],
        "abilities":[
            {
                "abname":"Resourceful",
                "speclvl":1,
                "ablvl":1,
                "descrip":"As long as this model is on the battlefield and not shaken, you gain an additional Command Point at the beginning of the battle round."
            },
            {
                "abname":"Bold",
                "speclvl":2,
                "ablvl":2,
                "descrip":"This model automatically passes Nerve tests."
            },
            {
                "abname":"Inspiring",
                "speclvl":2,
                "ablvl":2,
                "descrip":"Friendly models within 3\" of this model – as long as it is not shaken – automatically pass Nerve tests."
            },
            {
                "abname":"Paragon",
                "speclvl":3,
                "ablvl":3,
                "descrip":"Re-roll hit rolls of 1 for friendly models within 3\" of this model, as long as it is not shaken."
            },
            {
                "abname":"Tyrant",
                "speclvl":3,
                "ablvl":3,
                "descrip":"Your opponent(s) must add 1 to Nerve tests for any enemy models within 6\" of this model, as long as it is not shaken."
            },
            {
                "abname":"Tactician",
                "speclvl":3,
                "ablvl":3,
                "descrip":"As long as this model is on the battlefield and not shaken, roll a D6 each time you use a Tactic. On a 5+ you gain a Command Point."
            },
            {
                "abname":"Mentor",
                "speclvl":3,
                "ablvl":3,
                "descrip":"Once per battle round, when you choose a friendly model within 3\" of this model to shoot in the Shooting phase – as long as this model is not shaken – you can re-roll failed hit rolls for that model until the end of the phase."
            },
        ],
    },
    {   # Combat
        "specname":"Combat",
        "tactics":[
            {
                "tacname":"Up and At 'em!",
                "speclvl":1,
                "comcost":1,
                "descrip":"Use this Tactic in the Fight phase, after attacking with a model from your kill team. Pick a Combat specialist from your kill team that has not yet attacked this phase: you can immediately fight with them."
            },
            {
                "tacname":"Defensive Fighter",
                "speclvl":2,
                "comcost":1,
                "descrip":"Use this Tactic at the start of the Fight phase. Pick  a Combat specialist of Level 2 or higher from your kill team. Until the end of the phase, you must subtract 2 from that model’s Attacks characteristic (to a minimum of 1), but your opponent(s) must re-roll successful hit rolls made against that model."
            },
            {
                "tacname":"Force of Will",
                "speclvl":3,
                "comcost":1,
                "descrip":"Use this Tactic when a Combat specialist of Level 3 or higher from your kill team nishes a charge move within 1\" of an enemy model. Roll a D6; on a 5+ that enemy model suers 1 mortal wound."
            },
        ],
        "abilities":[
            {
                "abname":"Expert Fighter",
                "speclvl":1,
                "ablvl":1,
                "descrip":"Add 1 to this model’s Attacks characteristic."
            },
            {
                "abname":"Warrior Adept",
                "speclvl":2,
                "ablvl":2,
                "descrip":"Add 1 to hit rolls for this model in the Fight phase."
            },
            {
                "abname":"Deadly Counter",
                "speclvl":2,
                "ablvl":2,
                "descrip":"If any hit rolls of 1 or less are made for a model’s attacks that target this model in the Fight phase, unless this model is shaken, roll a D6. On a 5+, the model that made the attack suffers 1 mortal wound after all of their attacks have been resolved."
            },
            {
                "abname":"Deathblow",
                "speclvl":3,
                "ablvl":3,
                "descrip":"Any wound rolls of 6 you make for this model in the Fight phase inflict 1 mortal wound on the target in addition to any other damage."
            },
            {
                "abname":"Combat Master",
                "speclvl":3,
                "ablvl":3,
                "descrip":"Add 1 to the Attacks characteristic of this model for each enemy model within 1\" of it at the start of the Fight phase, until the end of the phase."
            },
            {
                "abname":"Killer Instinct",
                "speclvl":3,
                "ablvl":3,
                "descrip":"You can re-roll any failed wound rolls you make for this model in the Fight phase."
            },
            {
                "abname":"Bloodlust",
                "speclvl":3,
                "ablvl":3,
                "descrip":"You can re-roll any failed charge rolls you make for this model."
            },
        ],
    },
    {   # Comms
        "specname":"Comms",
        "tactics":[
            {
                "tacname":"Rousing Transmission",
                "speclvl":1,
                "comcost":1,
                "descrip":"Use this Tactic in the Morale phase before taking any Nerve tests. Until the end of the phase you can subtract 1 from Nerve tests for models from your kill team as though the Comms specialist was within 2\" of them."
            },
            {
                "tacname":"Scanner Uplink",
                "speclvl":2,
                "comcost":2,
                "descrip":"Use this Tactic when you pick a model from your kill team that is within 6\" of a friendly Comms specialist of Level 2 or higher to shoot in the Shooting phase. That model can target an enemy model that is not visible to them. If they do so, a 6 is required for a successful hit roll irrespective of the model’s Ballistic Skill or any other modifiers, even if that weapon would normally hit automatically. The target is treated as obscured."
            },
            {
                "tacname":"New Intelligence",
                "speclvl":3,
                "comcost":1,
                "descrip":"Use this Tactic at the end of the Movemen the Movement phase. Pick a model from your kill team within 12\" of a friendly Comms specialist of Level 3 or higher. Ready that model."
            },
        ],
        "abilities":[
            {
                "abname":"Scanner",
                "speclvl":1,
                "ablvl":1,
                "descrip":"Once per Shooting phase, when you pick a model from your kill team to shoot that is within 6\" of this model, if this model is not shaken, you can add 1 to hit rolls for that model in this phase."
            },
            {
                "abname":"Expert",
                "speclvl":2,
                "ablvl":2,
                "descrip":"Roll a D6 at the start of each battle round if this model is not shaken. On a 5+, you gain 1 additional Command Point. This additional Command Point is lost at the end of the battle round if not used."
            },
            {
                "abname":"Static Screech",
                "speclvl":2,
                "ablvl":2,
                "descrip":"Once per battle at the start of the Fight phase, if this model is not shaken, subtract 1 from hit rolls for enemy models that make attacks while they are within 6\" of this model until the end of the phase."
            },
            {
                "abname":"Vox Ghost",
                "speclvl":3,
                "ablvl":3,
                "descrip":"Subtract 1 from the Leadership characteristic of enemy models while this model is on the battlefield, as long as it is not shaken."
            },
            {
                "abname":"Command Relay",
                "speclvl":3,
                "ablvl":3,
                "descrip":"Roll a D6 each time you use a Tactic while this model is on the battlefield and not shaken. On a 6 the Command Points spent on that Tactic are immediately refunded."
            },
            {
                "abname":"Triangulator",
                "speclvl":3,
                "ablvl":3,
                "descrip":"Once per Shooting phase, when you pick a model from your kill team to shoot a Heavy weapon, if this model is not shaken, you can re-roll the dice when determining the number of attacks that model can make."
            },
            {
                "abname":"Vox Hacker",
                "speclvl":3,
                "ablvl":3,
                "descrip":"After each battle in which this model was in your kill team, if this model is not in Convalescence or dead, roll a D6. On a 5+ you gain 1 Intelligence."
            },
        ],
    },
    {   # Demolitions
        "specname":"Demolitions",
        "tactics":[
            {
                "tacname":"Custom Ammo",
                "speclvl":1,
                "comcost":1,
                "descrip":"Use this Tactic when you pick a Demolitions specialist from your kill team to shoot in the Shooting phase. You can add 1 to wound rolls for that model’s ranged weapons in this phase."
            },
            {
                "tacname":"Defensive Fighter",
                "speclvl":2,
                "comcost":1,
                "descrip":"Use this Tactic at the start of the Shooting phase. Pick a Demolitions specialist of Level 2 or higher from your kill team. Roll a D6 each time that model loses a wound in this phase; on a 5+ that wound is not lost."
            },
            {
                "tacname":"Force of Will",
                "speclvl":3,
                "comcost":1,
                "descrip":"Use this Tactic when you pick a Demolitions specialist of Level 3 or higher from your kill team to shoot in the Shooting phase. In this Shooting phase, they can only shoot a single weapon, and that weapon can only fire 1 shot (even if it would normally fire more). However, that weapon’s Damage characteristic is increased by 2. You cannot use this Tactic in the same battle round as the Custom Ammo Tactic."
            },
        ],
        "abilities":[
            {
                "abname":"Breacher",
                "speclvl":1,
                "ablvl":1,
                "descrip":"You can add 1 to this model’s wound rolls against targets that are obscured."
            },
            {
                "abname":"Pyromaniac",
                "speclvl":2,
                "ablvl":2,
                "descrip":"You can re-roll wound rolls of 1 for this model when it is attacking with a weapon that hits automatically."
            },
            {
                "abname":"Grenadier",
                "speclvl":2,
                "ablvl":2,
                "descrip":"Add 3\" to the range of any Grenade weapon this model uses. You can reroll hit rolls of 1 for Grenade weapons this model uses."
            },
            {
                "abname":"Saboteur",
                "speclvl":3,
                "ablvl":3,
                "descrip":"If this model is in your kill team and not out of action when you make your Casualty rolls, roll a D6. On a 5+ choose an opponent who played that mission to lose 1 Materiel."
            },
            {
                "abname":"Sapper",
                "speclvl":3,
                "ablvl":3,
                "descrip":"If this model is in your kill team and you choose the Plant Traps strategy, you can add 1 to the number of pieces of terrain you can booby trap."
            },
            {
                "abname":"Siegemaster",
                "speclvl":3,
                "ablvl":3,
                "descrip":"You can add 1 to Injury rolls caused by this model’s attacks in the Shooting phase if those Injury rolls are for models that are obscured."
            },
            {
                "abname":"Ammo Hound",
                "speclvl":3,
                "ablvl":3,
                "descrip":"If this model is in your kill team and not out of action when you make your Casualty rolls, roll a D6. On a 5+ you gain 1 Materiel."
            },
        ],
    },
    {   # Heavy
        "specname":"Heavy",
        "tactics":[
            {
                "tacname":"More Bullets",
                "speclvl":1,
                "comcost":1,
                "descrip":"Use this Tactic when you pick a Heavy specialist from your kill team to shoot in the Shooting phase. You can add 1 to the number of shots fired by that model’s ranged weapons, with the exception of weapons that would otherwise fire 1 shot (e.g. an Assault 2 weapon would fire 3 shots, but a Rapid Fire 1 weapon at long range would fire 1 shot) in this Shooting phase."
            },
            {
                "tacname":"Overwhelming Firepower",
                "speclvl":2,
                "comcost":2,
                "descrip":"Use this Tactic when you pick a Heavy specialist of Level 2 or higher from your kill team to shoot in the Shooting phase. that model can shoot twice in this Shooting phase; after they have shot a first time, immediately shoot with them again. You cannot use this Tactic in the same battle round as the More Bullets Tactic."
            },
            {
                "tacname":"Unkillable",
                "speclvl":3,
                "comcost":1,
                "descrip":"Use this Tactic at the start of your turn in the Morale phase. Pick a Heavy specialist of Level 3 or higher from your kill team that has one or more flesh wounds. Remove one of that model’s flesh wounds."
            },
        ],
        "abilities":[
            {
                "abname":"Relentless",
                "speclvl":1,
                "ablvl":1,
                "descrip":"This model does not suffer the -1 penalty for shooting with a Heavy weapon after moving in the preceding Movement phase, or for shooting an Assault weapon after Advancing."
            },
            {
                "abname":"Suppressor",
                "speclvl":2,
                "ablvl":2,
                "descrip":"Enemy models that are targeted by this model in the Shooting phase suer a -1 penalty to their hit rolls until the end of the phase."
            },
            {
                "abname":"Extra Armour",
                "speclvl":2,
                "ablvl":2,
                "descrip":"Ignore AP characteristics of -1 for attacks that target this model."
            },
            {
                "abname":"Devastator",
                "speclvl":3,
                "ablvl":3,
                "descrip":"You can reroll the damage for this model’s ranged weapons that have a random Damage characteristic."
            },
            {
                "abname":"Rigorous",
                "speclvl":3,
                "ablvl":3,
                "descrip":"You can re-roll hit rolls of 1 for this model in the Shooting phase."
            },
            {
                "abname":"Indomitable",
                "speclvl":3,
                "ablvl":3,
                "descrip":"Once per battle round, you can make your opponent re-roll the Injury dice for this model."
            },
            {
                "abname":"Heavily Muscled",
                "speclvl":3,
                "ablvl":3,
                "descrip":"You can re-roll wound rolls of 1 for this model in the Fight phase."
            },
        ],
    },
    {   # Medic
        "specname":"Medic",
        "tactics":[
            {
                "tacname":"Stimm-shot",
                "speclvl":1,
                "comcost":1,
                "descrip":"Use this Tactic at the start of the Movemen the Movement phase. Pick a model from your kill team within 2\" of a friendly Medic specialist that is not shaken. You can add 1 to Advance rolls and charge rolls for that model, and add 1 to that model’s Attacks characteristic until the end of the battle round."
            },
            {
                "tacname":"Painkiller",
                "speclvl":2,
                "comcost":2,
                "descrip":"Use this Tactic at the end of the Movemen the Movement phase. Pick a model from your kill team within 2\" of a friendly Medic specialist of Level 2 or higher that is not shaken. Add 2 to that model’s Toughness characteristic until the end of the battle round."
            },
            {
                "tacname":"Emergency Resuscitation",
                "speclvl":3,
                "comcost":2,
                "descrip":"Use this Tactic when a Medic specialist of Level 3 or higher from your kill team that is not shaken is within 2\" of another model from your kill team that suffers an Out of Action Injury roll result. That model suffers a Flesh Wound result instead."
            },
        ],
        "abilities":[
            {
                "abname":"Reassuring",
                "speclvl":1,
                "ablvl":1,
                "descrip":"This model is never treated as being shaken when taking Nerve tests for other models in your kill team."
            },
            {
                "abname":"Field Medic",
                "speclvl":2,
                "ablvl":2,
                "descrip":"Roll a D6 when a friendly model within 3\" of this model suffers a wound, as long as this model is not shaken; on a 6 that wound is not lost."
            },
            {
                "abname":"Anatomist",
                "speclvl":2,
                "ablvl":2,
                "descrip":"Re-roll wound rolls of 1 for this model in the Fight phase."
            },
            {
                "abname":"Trauma Specialist",
                "speclvl":3,
                "ablvl":3,
                "descrip":"When an Injury roll is made for a friendly model within 3\" of this model, as long as this model is not shaken, roll an additional dice and use the lowest result."
            },
            {
                "abname":"Triage Expert",
                "speclvl":3,
                "ablvl":3,
                "descrip":"If this model is in your kill team and not out of action at the end of a battle, and you roll a Dead result when making a Casualty roll for a model from your kill team, you can roll a D6. On a 4+ apply the Convalescence result for that model instead."
            },
            {
                "abname":"Interrogator",
                "speclvl":3,
                "ablvl":3,
                "descrip":"At the end of any battle in which you were victorious, if this model was in your kill team and not out of action, roll a D6. On a 5+ you gain 1 Intelligence."
            },
            {
                "abname":"Toxin Synthesiser",
                "speclvl":3,
                "ablvl":3,
                "descrip":"Before deployment, you can pick up to D3 models from your kill team. Until the end of the battle, add 1 to wound rolls for attacks made with melee weapons those models are armed with."
            },
        ],
    },
    {   # Scout
        "specname":"Scout",
        "tactics":[
            {
                "tacname":"Quick March",
                "speclvl":1,
                "comcost":1,
                "descrip":"Use this Tactic when you pick a Scout specialist from your kill team to move in the Movement phase. You can either increase the model’s Move characteristic by 2\" this phase or you can re-roll the dice when this model Advances in this phase."
            },
            {
                "tacname":"Marked Positions",
                "speclvl":2,
                "comcost":1,
                "descrip":"Use this Tactic at the start of the Shooting phase. Pick an enemy model within 6\" of a Scout specialist of Level 2 or higher from your kill team that is not shaken. You can re-roll hit rolls of 1 for shooting attacks made by models in your kill team that target that enemy model until the end of the phase."
            },
            {
                "tacname":"Move Unseen",
                "speclvl":3,
                "comcost":2,
                "descrip":"Use this Tactic at the start of your turn in the Movement phase. Pick a Scout specialist of Level 3 or higher from your kill team that is not shaken. Remove that model from the battlefield and set it up again anywhere within 18\" of its previous position and more than 3\" from any enemy models. It is considered to have Advanced."
            },
        ],
        "abilities":[
            {
                "abname":"Swift",
                "speclvl":1,
                "ablvl":1,
                "descrip":"You can re-roll Advance rolls for this model."
            },
            {
                "abname":"Forward Scout",
                "speclvl":2,
                "ablvl":2,
                "descrip":"This model automatically passes dangerous terrain tests."
            },
            {
                "abname":"Pathfinder",
                "speclvl":2,
                "ablvl":2,
                "descrip":"If this model is not in Convalescence, you can add or subtract 1 from the result when you roll to determine a mission. If you do, this model must be included in your kill team."
            },
            {
                "abname":"Skirmisher",
                "speclvl":3,
                "ablvl":3,
                "descrip":"Your opponent(s) must subtract 1 from hit rolls for shooting attacks that target this model if the firing model is more than 12\" from this model and this model is not shaken or obscured."
            },
            {
                "abname":"Vanguard",
                "speclvl":3,
                "ablvl":3,
                "descrip":"You can re-roll hit rolls of 1 in the Shooting phase for attacks made by models from your kill team against enemy models that are within 6\" of this model, as long as this model is not shaken."
            },
            {
                "abname":"Observer",
                "speclvl":3,
                "ablvl":3,
                "descrip":"If this model is in your kill team, you can roll a D6 at the start of the Scouting phase. On a 4+ you can pick an additional strategy."
            },
            {
                "abname":"Explorer",
                "speclvl":3,
                "ablvl":3,
                "descrip":"After each battle in which this model was in your kill team, if this model is not in Convalescence, you can roll a D6. On a 5+ you gain 1 Territory."
            },
        ],
    },
    {   # Sniper
        "specname":"Sniper",
        "tactics":[
            {
                "tacname":"Careful Aim",
                "speclvl":1,
                "comcost":1,
                "descrip":"Use this Tactic when you choose a Sniper specialist from your kill team to shoot in the Shooting phase. You can add 1 to hit rolls for that model until the end of the phase."
            },
            {
                "tacname":"Headshot",
                "speclvl":2,
                "comcost":1,
                "descrip":"Use this Tactic when you pick a Sniper specialist of Level 2 or higher from your kill team to shoot in the Shooting phase. Until the end of the phase, when that model shoots at obscured targets they are considered not to be obscured."
            },
            {
                "tacname":"Quick Shot",
                "speclvl":3,
                "comcost":1,
                "descrip":"Use this Tactic when you pick a Sniper specialist of Level 3 or higher from your kill team to shoot in the Shooting phase. In this Shooting phase, double the number of shots fired by that model’s ranged weapons (e.g. an Assault 2 weapon would fire 4 shots), but subtract 1 from hit rolls for that model. You cannot use this Tactic in the same battle round as the Headshot Tactic."
            },
        ],
        "abilities":[
            {
                "abname":"Marksman",
                "speclvl":1,
                "ablvl":1,
                "descrip":"You can re-roll hit rolls of 1 for this model when it makes a shooting attack."
            },
            {
                "abname":"Assassin",
                "speclvl":2,
                "ablvl":2,
                "descrip":"You can re-roll wound rolls of 1 for this model when it makes a shooting attack."
            },
            {
                "abname":"Sharpshooter",
                "speclvl":2,
                "ablvl":2,
                "descrip":"If this model is Readied, add 1 to hit rolls when it makes a shooting attack."
            },
            {
                "abname":"Deadeye",
                "speclvl":3,
                "ablvl":3,
                "descrip":"On an unmodified wound roll of 6 for this model’s shooting attacks, increase the Damage characteristic of that attack by 1."
            },
            {
                "abname":"Armour Piercing",
                "speclvl":3,
                "ablvl":3,
                "descrip":"On an unmodified wound roll of 6 for this model’s shooting attacks, improve the AP characteristic of that attack by 1."
            },
            {
                "abname":"Mobile",
                "speclvl":3,
                "ablvl":3,
                "descrip":"This model does not suffer the -1 penalty for shooting with a Heavy weapon after moving in the preceding Movement phase, or for shooting an Assault weapon after Advancing."
            },
            {
                "abname":"Eagle-eye",
                "speclvl":3,
                "ablvl":3,
                "descrip":"Increase the Range characteristic of all Rapid Fire and Heavy weapons this model is armed with by 6\"."
            },
        ],
    },
    {   # Veteran
        "specname":"Veteran",
        "tactics":[
            {
                "tacname":"Adaptive Tactics",
                "speclvl":1,
                "comcost":1,
                "descrip":"Use this Tactic at the start of the first battle round, but before the Initiative phase. Pick a Veteran specialist from your kill team. They can make a normal move or Advance. You can only use this Tactic once per battle."
            },
            {
                "tacname":"Well Drilled",
                "speclvl":2,
                "comcost":2,
                "descrip":"Use this Tactic at the start of your turn in the Shooting phase. Pick a Veteran specialist of Level 2 or higher from your kill team. Ready them unless they are within 1\" of an enemy. They can shoot in that phase as if they had not moved in the Movement phase."
            },
            {
                "tacname":"Roll with the Hits",
                "speclvl":3,
                "comcost":1,
                "descrip":"Use this Tactic during your opponent’s turn in the Shooting phase. Pick a Veteran specialist of Level 3 or higher from your kill team that has been Injured, before your opponent makes the Injury roll. Your opponent can only roll a single dice for that Injury roll."
            },
        ],
        "abilities":[
            {
                "abname":"Grizzled",
                "speclvl":1,
                "ablvl":1,
                "descrip":"This model ignores penalties to its Leadership characteristic and Nerve tests."
            },
            {
                "abname":"Practised",
                "speclvl":2,
                "ablvl":2,
                "descrip":"You can re-roll one hit roll or wound roll for this model in each battle round."
            },
            {
                "abname":"Seen It All",
                "speclvl":2,
                "ablvl":2,
                "descrip":"You can subtract 1 from Nerve tests for models from your kill team within 3\" of this model, as long as it is not shaken."
            },
            {
                "abname":"Survivor",
                "speclvl":3,
                "ablvl":3,
                "descrip":"You can add 1 to saving throws for this model."
            },
            {
                "abname":"One-man Army",
                "speclvl":3,
                "ablvl":3,
                "descrip":"This model generates 1 Command Point at the beginning of each battle round, unless it is shaken or out of action. This Command Point can only be used for Veteran Tactics."
            },
            {
                "abname":"Battle Scarred",
                "speclvl":3,
                "ablvl":3,
                "descrip":"Enemy models suffer -1 Leadership whilst they are within 6\" of this model, as long as it is not shaken."
            },
            {
                "abname":"Nerves of Steel",
                "speclvl":3,
                "ablvl":3,
                "descrip":"You can re-roll failed hit rolls for this model when it fires Overwatch."
            },
        ],
    },
    {   # Zealot
        "specname":"Zealot",
        "tactics":[
            {
                "tacname":"Killing Frenzy",
                "speclvl":1,
                "comcost":1,
                "descrip":"Use this Tactic when you pick a Zealot specialist from your kill team to fight in the Fight phase. Until the end of the phase, each time you make a hit roll of 6+ for that model you can make an additional attack with the same weapon against the same target. These attacks cannot themselves generate any further attacks."
            },
            {
                "tacname":"Martyr",
                "speclvl":2,
                "comcost":2,
                "descrip":"Use this Tactic when a Zealot specialist of Level 2 or higher from your kill team loses their last wound, before any player rolls on the Injury  table. You may immediately shoot with one of its weapons as if it were the Shooting phase, or pile in and make one attack as if it were the Fight phase."
            },
            {
                "tacname":"Terrifying Rampage",
                "speclvl":3,
                "comcost":2,
                "descrip":"Use this Tactic at the start of the Morale phase. Pick a Zealot specialist of Level 3 or higher from your kill team that took an enemy model out of action in the preceding Fight phase. Each enemy model within 6\" of the Zealot must take a Nerve test. If the test is failed the model is shaken."
            },
        ],
        "abilities":[
            {
                "abname":"Frenzied",
                "speclvl":1,
                "ablvl":1,
                "descrip":"You can add 1 to this model’s Attacks and Strength characteristics in a battle round in which they charged."
            },
            {
                "abname":"Exultant",
                "speclvl":2,
                "ablvl":2,
                "descrip":"Opponents must re-roll unmodified hit rolls of 6 for models from their kill team within 3\" of this model, as long as it is not shaken."
            },
            {
                "abname":"Flagellant",
                "speclvl":2,
                "ablvl":2,
                "descrip":"Roll a D6 each time this model loses a wound. On a 6 the wound is ignored."
            },
            {
                "abname":"Puritan",
                "speclvl":3,
                "ablvl":3,
                "descrip":"You can re-roll hit rolls in the Fight phase for this model against enemy models that do not have a Faction keyword in common with it."
            },
            {
                "abname":"Rousing",
                "speclvl":3,
                "ablvl":3,
                "descrip":"Add 1 to the Leadership characteristic of models from your kill team within 6\" of this model, as long as it is not shaken."
            },
            {
                "abname":"Fanatical",
                "speclvl":3,
                "ablvl":3,
                "descrip":"This model automatically passes Nerve tests."
            },
            {
                "abname":"Strength of Spirit",
                "speclvl":3,
                "ablvl":3,
                "descrip":"Subtract 1 for Injury rolls made for this model."
            },
        ],
    },
],


import enchant
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import re
import seaborn as sns

from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from spellchecker import SpellChecker

sns.set(style = "whitegrid",
        color_codes = True,
        font_scale = 1.5)

def words_in_texts(words, texts):
    '''
    Args:
        words (list): words to find
        texts (Series): strings to search in

    Returns:
        NumPy array of 0s and 1s with shape (n, p) where n is the
        number of texts and p is the number of words.
    '''
    indicator_array = []
    for i in words:
        indicator_array.append(texts.str.contains(i).values.astype(int))
    indicator_array = np.asarray(indicator_array)
    indicator_array = np.transpose(indicator_array)
    return indicator_array

def count_misspellings(words):
    '''
    Args:
        words (list): words to determine if misspelled

    Returns:
        the ratio of misspelled words to total words in email
    '''
    words = re.sub(r'[^a-zA-Z]', ' ', words)
    words = words.lower().split()
    count = 0
    misspellings = spell.unknown(words)
    for word in words:
        if word in misspellings:
            count += 1
    return count/len(words)

def prepare_set(x):
    x['subject'] = x['subject'].fillna('')
    x['full'] = x['subject'] + ' ' + x['email']

    x_train = words_in_texts(final_words, x['full'])

    X = pd.DataFrame(x_train)
    X['no_of_symbols'] = x['full'].apply(lambda x: sum(not i.isalpha() and not i.isdigit() for i in x))
    X['no_of_digits'] = x['full'].apply(lambda x: sum(i.isdigit() for i in x))
    X['no_of_cap_letters'] = x['full'].apply(lambda x: sum(i.isupper() for i in x))
    X['is_re/fwd'] = x['full'].str.contains(r'Re:|Fw:').astype(int)
    X['ratio_misspellings'] = x['full'].apply(lambda x: count_misspellings(x))

    x_train = X.to_numpy()
    return x_train

original_training_data = pd.read_csv('data/train.csv')
test = pd.read_csv('data/test.csv')

# Convert the emails to lower case as a first step to processing the text
original_training_data['email'] = original_training_data['email'].str.lower()
test['email'] = test['email'].str.lower()

original_training_data.head()

# Handle null values in data
original_training_data['subject'] = original_training_data['subject'].fillna('')

# Split the data into training and test sets
train, val = train_test_split(original_training_data, test_size=0.1, random_state=42)

# Find frequency of some example words in Spam emails
my_words = ['@', '#', '%', '!', 'html']
t = train[['spam']]
found_words = words_in_texts(my_words, train['email'])
t['@'] = found_words[:, 0]
t['#'] = found_words[:, 1]
t['%'] = found_words[:, 2]
t['!'] = found_words[:, 3]
t['html'] = found_words[:, 4]
t = t.melt('spam')
t['spam'] = t['spam'].replace({0:'Not Spam', 1:'Spam'})
plt.figure(figsize=(12, 8))
ax = sns.barplot(x=t['variable'], y=t['value'], hue=t['spam'], data=t, ci=None)
legend = ax.legend()
plt.title('Frequency of Words in Spam Emails')
plt.xlabel('Words')
plt.ylabel('Proportion of Emails')
plt.ylim(0.0, 1.0)
plt.show()

# We must do this in order to preserve the ordering of emails to labels for words_in_texts
train = train.reset_index(drop=True)
val = val.reset_index(drop=True)

# Common words in spam emails
final_words = ['please', 'html', 'free', 'urgent', 'help', 'loan', 'quick', 'money', 'drug', 'sex', 'win', 'act now',
 'bonus', 'order', 'limited','special', 'shipping', 'url', '!', '#', '@', '%', '\$']

spell = SpellChecker()

X_train_f = prepare_set(train.copy())
Y_train_f = train['spam']

X_val_f = prepare_set(val.copy())
Y_val_f = val['spam']

final_model = LogisticRegression(max_iter=5000)
final_model.fit(X_train_f, Y_train_f)
final_model.predict(X_train_f)

final_model_training_accuracy = final_model.score(X_train_f, Y_train_f)
final_model_val_accuracy = final_model.score(X_val_f, Y_val_f)
print("Training Accuracy: ", final_model_training_accuracy)
print("Validation Accuracy: ", final_model_val_accuracy)


# -*- coding: utf-8 -*-
import logging
import os
import sys
logger = logging.getLogger(__name__)
sys.path.append(os.path.join(os.path.dirname(__file__), "../"))
___file___ = __file__
import json
from TickerFeed import TickerFeed
import data_loader
from model1 import Predict_model
import gdax
import datetime
import pandas as pd
import argparse

parser = argparse.ArgumentParser(description='Simulator crypto prices')
parser.add_argument('-r', '--realtime', action='store_const',
                   const=True, default=False,
                   help='Only visualize results of previously saved model')

parser.add_argument('-p', '--perfect', action='store_const',
                   const=True, default=False,
                   help='Use a perfect model to evaluate buyer')

args = parser.parse_args()

modelName = "model2.256lstmx2.stateful"

public_client = gdax.PublicClient()

class Simulator(object):
    def __init__(self, cryptoCoin='ETH', buyPercentage=0.5, initialUsd = 1000.0, initialCrypto = 1.0, isRealTime=True):
        self.initialCrypto = initialCrypto
        self.initialUsd = initialUsd
        self.isRealTime = isRealTime

        self.startTime = datetime.datetime.now().isoformat()
        self.usd = initialUsd
        self.crypto = initialCrypto
        self.cryptoCoin = cryptoCoin
        self.coinPair = '{}-USD'.format(self.cryptoCoin)
        self.buyPercentage = buyPercentage

        self.predictor = Predict_model(modelName)
        self.pastCurrentPrice = None
        self.pastPastCurrentPrice = None
        self.predictedDelta = None
        self.predictPrice = None

        self.valueHistory = []

        startingData = data_loader.getCandles('ETH-USD', 60, save=False)[['open']]

        for currentPrice in startingData.values:
            if self.pastCurrentPrice:
                self.predictor.get_model(self.pastCurrentPrice, currentPrice)

            self.pastPastCurrentPrice = self.pastCurrentPrice
            self.pastCurrentPrice = currentPrice

    def process(self, data, nextData=None):
        currPrice = data['price']
        time = data['time']
        if self.pastCurrentPrice:
            if self.predictPrice:
                err = currPrice - self.predictPrice
                logger.info('Previous prediction error: {}'.format(err))

# #            if self.pastPastCurrentPrice and abs(err)>0.09:
#             if self.pastPastCurrentPrice:
#                 self.predictor.training(self.pastPastCurrentPrice, self.pastCurrentPrice, currPrice)

            if not nextData:
                self.predictedDelta = self.predictor.get_model(self.pastCurrentPrice, currPrice)
            else:
                self.predictedDelta = nextData['delta']

            logger.info('Current Price: {}'.format(currPrice))
            self.predictPrice = self.predictedDelta*currPrice
            logger.info('Predicted Price: {}'.format(self.predictPrice))

            decision = self.predictor.buyer(self.predictedDelta)

            # TODO instead of taking price, take best bid for buys and best ask for sells
            if self.isRealTime:
                price = float(public_client.get_product_ticker(product_id=self.coinPair)['price'])
            else:
                price = currPrice

            if decision == 'buy':
                self.buy(self.usd * self.buyPercentage, price)

            elif decision == 'sell':
                self.sell(self.crypto * self.buyPercentage, price)

            logger.info('Current Holdings:\nUSD: {}\n{}: {}'.format(self.usd, self.cryptoCoin, self.crypto))

            currentValue = (price * self.crypto) + self.usd
            initialValue = (price * self.initialCrypto) + self.initialUsd

            logger.info('Total USD Value: {}'.format((price * self.crypto) + self.usd))

            logger.info('Change: {}usd, {}%'.format(currentValue - initialValue, (currentValue / initialValue) * 100))
            self.valueHistory.append([time, currentValue])
            if len(self.valueHistory) > 0 and len(self.valueHistory) % 30 == 0:
                with open(os.path.join(os.path.dirname(___file___), "../prediction/checkpoint/{}/stats_{}.json".format(modelName, self.startTime)), 'w') as f:
                    json.dump(self.valueHistory, f)

        self.pastPastCurrentPrice = self.pastCurrentPrice
        self.pastCurrentPrice =  currPrice
        logger.info("")

    def buy(self, amountInUsd, price):
        # TODO take into account exchange fees
        amountInCrypto = amountInUsd / price
        logger.info('Buying {} {} for {} USD ({})'.format(amountInCrypto, self.cryptoCoin, amountInUsd, price))

        self.usd -= amountInUsd
        self.crypto += amountInCrypto

    def sell(self, amountInCrypto, price):
        # TODO take into account exchange fees
        amountInUsd = amountInCrypto * price
        logger.info('Selling {} {} for {} USD ({})'.format(amountInCrypto, self.cryptoCoin, amountInUsd, price))

        self.usd += amountInUsd
        self.crypto -= amountInCrypto

if __name__ == '__main__':

    if args.realtime:
        logging.basicConfig(level=logging.INFO)
        sim = Simulator()
        tickerFeed = TickerFeed(sim.coinPair, 60)
        tickerFeed.onTickerReceived(sim.process)
        tickerFeed.run()
    elif args.perfect:
        logging.basicConfig(level=logging.INFO)
        logging.info('USING A PERFECT MODEL')
        sim = Simulator(isRealTime=False)
        simTestData = data_loader.getCandles('ETH-USD', 60, start='2018-02-14T00:00:25+01:00', end='2018-03-14T00:00:25+01:00', save=True)[['open']]

        for i in range(0, len(simTestData) - 1):
            item = simTestData.iloc[i]
            price = item[0]
            time = item.name.isoformat()

            nextItem = simTestData.iloc[i+1]
            nextPrice = nextItem[0]
            sim.process({
                    'price': price,
                    'time': time
            }, {'delta': nextPrice/price})

    else:
        # sim = Simulator(isRealTime=False)
        # simTestData = data_loader.getCandles(sim.coinPair, 60, start=(datetime.datetime.now() - datetime.timedelta(days=3)).isoformat(), save=True)[['open']]
        # for (time, price) in simTestData.iterrows():
        #     price = price.item()
        #     time = time.isoformat()
        #     sim.process({
        #             'price': price,
        #             'time': time
        #     })
        logging.basicConfig(level=logging.WARN)
        sim = Simulator(isRealTime=False)
        with open(os.path.join(os.path.dirname(__file__), '../data/candles/ETH-USD_60_2018-02-14T00:00:25+01:00_2018-03-14T00:00:25+01:00.json'), 'r') as f:
            simTestData = pd.DataFrame(json.load(f))

        for (key, row) in simTestData.iterrows():
            time = pd.to_datetime(row[0], unit='s').isoformat()
            price = row[1]
            sim.process({
                    'price': price,
                    'time': time
            })


from ..Commons import *
from ..Language.DataStructure import *
from ..Language.Syntax import *

def formule_prod(self, VALE, VALE_C, **args):
    if args.get('__all__'):
        return (formule, formule_c)
    if VALE is not None:
        return formule
    elif VALE_C is not None:
        return formule_c

FORMULE=FORM(nom="FORMULE",
             op=-5,
             sd_prod=formule_prod,
             fr=tr("Définit une formule réelle ou complexe à partir de son expression mathématique"),
    regles = (UN_PARMI('VALE', 'VALE_C',),),
    VALE     = SIMP(statut='f', typ='TXM'),
    VALE_C   = SIMP(statut='f', typ='TXM'),
    NOM_PARA = SIMP(statut='o', typ='TXM', max='**'),
)


from flask import Blueprint, jsonify
from flask_login import login_required, current_user
from app.models import User, UserLike

user_routes = Blueprint('users', __name__)

@user_routes.route('/')
@login_required
def users():
    """
    Query for all users and returns them in a list of user dictionaries
    """
    users = User.query.all()
    return {'users': [user.to_dict() for user in users]}

## Getting the current user's likes
@user_routes.route('/current/likes')
@login_required
def get_user_likes():
    video_likes = UserLike.query.filter(UserLike.user_id == current_user.id).all()
    return [likes.to_dict_video() for likes in video_likes]

@user_routes.route('/<int:id>')
@login_required
def user(id):
    """
    Query for a user by id and returns that user in a dictionary
    """
    user = User.query.get(id)
    return user.to_dict()


import random
import time

from locust import HttpUser, task, events
import requests
import json
from faker import Faker

import prepare_env_utils

fake = Faker()

addresses = [
    "Bukowińska 26C, 02-703 Warszawa",
    "Cypryjska 70, 02-762 Warszawa",
    "Oskara Langego 8, 02-685 Warszawa"
]

# TODO create users using auth0 API

class OrderingUser(HttpUser):
    def on_start(self):
        # auth0_user_email = prepare_env_utils.create_auth0_user("ORDERING_USER")
        # self.client.headers["Authorization"] = f"Bearer {prepare_env_utils.get_access_token(auth0_user_email)}"
        self.client.headers["X-User-Id"] = fake.uuid4()

        self._create_user()
        self._create_delivery_address()

        # print(f"ORDERING Created user with id {self.user_id} and delivery address with id {self.delivery_address_id}")

    @task
    def e2e(self):
        restaurants = self.client.get("/restaurants").json()
        if len(restaurants) == 0:
            time.sleep(10)
            return

        selected_restaurant = random.choice(restaurants)

        order_id = self.client.post("/orders", json={
            "restaurantId": selected_restaurant.get("id")
        }).json().get("id")

        number_of_products = random.randint(1, 5)
        menu = selected_restaurant.get("menu")

        if len(menu) == 0:
            return

        for _ in range(number_of_products):
            selected_product = random.choice(menu)
            self.client.post(f"/orders/{order_id}/items", json={
                "productId": selected_product.get("id")
            })

        self.client.put(f"/orders/{order_id}/finalize", json={
            "deliveryAddressId": self.delivery_address_id
        })

        time.sleep(10)

        order = self.client.get(f"/orders/{order_id}").json()
        payment_id = order.get("paymentId")
        self.client.put(f"/payments/{payment_id}/pay")

        # print(f"ORDERING Paid for order {order_id}")

        while True:
            order = self.client.get(f"/orders/{order_id}").json()
            # print(f"ORDERING Order status: {order.get('status')}")
            if order.get("status") == "DELIVERED":
                # print(f"ORDERING Order delivered")
                break
            time.sleep(10)  # refreshing every 10 seconds

    def _create_user(self):
        # TODO may already exist
        self.client.post("/users", json={
            "name": fake.name(),
            "email": "contact@rasztabiga.me"
        })

        time.sleep(5)

        self.user_id = self.client.get("/users/me").json().get("id")

    def _create_delivery_address(self):
        self.delivery_address_id = self.client.post(f"/users/{self.user_id}/addresses", json={
            "address": random.choice(addresses),
            "additionalInfo": "additional info",
        }).json().get("id")

class RestaurantManager(HttpUser):
    def on_start(self):
        # auth0_user_email = prepare_env_utils.create_auth0_user("RESTAURANT_MANAGER")
        # self.client.headers["Authorization"] = f"Bearer {prepare_env_utils.get_access_token(auth0_user_email)}"
        self.client.headers["X-User-Id"] = fake.uuid4()

        self._create_restaurant()

        # print(f"RESTAURANT Created restaurant with id {self.restaurant_id}")

    @task
    def e2e(self):
        restaurant_orders = self.client.get(f"/restaurants/{self.restaurant_id}/orders").json()
        restaurant_orders = list(filter(lambda order: order.get("status") == "NEW", restaurant_orders))
        if len(restaurant_orders) == 0:
            time.sleep(10)
            return

        selected_order = random.choice(restaurant_orders)

        self.client.put(f"/restaurants/{self.restaurant_id}/orders/{selected_order.get('restaurantOrderId')}/accept")
        # print(f"RESTAURANT Accepted order")

        sleep_time = random.randint(60, 5 * 60)
        # print(f"RESTAURANT Sleeping for {sleep_time} seconds")
        time.sleep(sleep_time)

        self.client.put(f"/restaurants/{self.restaurant_id}/orders/{selected_order.get('restaurantOrderId')}/prepare")
        # print(f"RESTAURANT Prepared order")

    def _create_restaurant(self):
        self.restaurant_id = self.client.post("/restaurants", json={
            "id": fake.uuid4(),
            "name": fake.name(),
            "email": "contact@rasztabiga.me",
            "address": random.choice(addresses)
        }).json().get("id")

        self.client.put(f"/restaurants/{self.restaurant_id}/availability", json={
            "availability": "OPEN"
        })

        self.client.put(f"/restaurants/{self.restaurant_id}/menu", json={
            "menu": [
                {
                    "name": "Product #1",
                    "description": "Description",
                    "price": 21.37
                },
                {
                    "name": "Product #2",
                    "description": "Description 2",
                    "price": 23.37
                }
            ]
        })

class DeliveryCourier(HttpUser):
    def on_start(self):
        # auth0_user_email = prepare_env_utils.create_auth0_user("DELIVERY_COURIER")
        # self.client.headers["Authorization"] = f"Bearer {prepare_env_utils.get_access_token(auth0_user_email)}"
        self.client.headers["X-User-Id"] = fake.uuid4()

        self._create_courier()

        # print(f"DELIVERY Created courier with id {self.courier_id}")

    @task
    def e2e(self):
        with self.client.get(f"/deliveries/offer?courierAddress={self.courier_address}",
                             catch_response=True) as response:
            if response.status_code == 404:
                response.success()
                time.sleep(10)
                return
            else:
                offer = response.json()
                response.success()

        # print(f"DELIVERY Found offer {offer}")

        if random.random() < 0.1:
            self.client.put(f"/deliveries/{offer.get('id')}/reject")
            # print(f"DELIVERY Rejected offer {offer}")
            return

        self.client.put(f"/deliveries/{offer.get('id')}/accept")
        # print(f"DELIVERY Accepted offer {offer}")

        sleep_time = random.randint(60, 5 * 60)
        # print(f"DELIVERY Sleeping for {sleep_time} seconds")
        time.sleep(sleep_time)

        while True:
            try:
                self.client.put(f"/deliveries/{offer.get('id')}/pickup")
                # print(f"DELIVERY Picked up order {offer}")
                break
            except:
                time.sleep(30)
                continue

        sleep_time = random.randint(60, 5 * 60)
        # print(f"DELIVERY Sleeping for {sleep_time} seconds")
        time.sleep(sleep_time)

        self.client.put(f"/deliveries/{offer.get('id')}/deliver")
        # print(f"DELIVERY Delivered order {offer}")

    def _create_courier(self):
        # TODO may already exist
        self.client.post("/couriers", json={
            "name": fake.name(),
            "email": "contact@rasztabiga.me"
        }).json().get("id")

        time.sleep(5)

        self.courier_id = self.client.get("/couriers/me").json().get("id")

        self.courier_address = random.choice(addresses)

@events.test_stop.add_listener
def on_test_stop(environment, **kwargs):
    print("Deleting all tmp auth0 users")
    prepare_env_utils.delete_all_tmp_auth0_users()


from projectile import Projectile

def getInputs():
    a = eval(input("Enter the launch angle (in degrees): "))
    v = eval(input("Enter the initial velocity (in meters/sec): "))
    h = eval(input("Enter the initial height (in meters): "))
    t = eval(input(
        "Enter the time interval between position calculations: "))
    return a, v, h, t

def main():
    angle, vel, h0, time = getInputs()
    cball = Projectile(angle, vel, h0)
    maxY = 0
    while cball.getY() >= 0:
        cball.update(time)
        if cball.getY() > maxY:
            maxY = cball.getY()
    print("\nDistance traveled: {0:0.1f} meters.".format(cball.getX()))
    print("Max height: {0:0.1f} meters.".format(maxY))

main()


import tkinter as tk
from tkinter import ttk
from tkinter.messagebox import showerror

class SettingsGui(tk.Toplevel):
    def __init__(self, parent, settings):
        super().__init__(parent)

        self.settings = settings

        self.geometry('500x350')
        self.title('Simulation Settings')
        settings.set_points_amount(210)

        self.resizable(False,False)

        self.columnconfigure(0,weight=1)
        self.columnconfigure(1,weight=1)
        self.columnconfigure(2,weight=1)
        self.columnconfigure(3,weight=1)

        self.labels()
        self.speed_spinbox()
        self.colors_radio()
        self.apply_button()

    def labels(self):
        self.label_speed = ttk.Label(self,text="Speed")
        self.label_points_amount = ttk.Label(self,text="Points amount")
        self.axes_length = ttk.Label(self,text="Axes lenght")

        self.label_points_color = ttk.Label(self, text="Points colors")
        self.label_axes_colors = ttk.Label(self,text="Axes colors")

        self.label_speed.grid(column=0, row=0, padx=10,pady=10)
        self.label_points_amount.grid(column=0, row=1, padx=10,pady=10)
        self.axes_length.grid(column=0, row=2, padx=10,pady=10)

        self.label_points_color.grid(column=0, row=3, padx=10,pady=10)
        self.label_axes_colors.grid(column=0, row=5, padx=10,pady=10)

    def speed_spinbox(self):

        self.current_value = tk.StringVar()
        self.current_value.set("10")
        self.spinbox = ttk.Spinbox(self,from_=1,to=15,increment=1,textvariable=self.current_value,wrap=True)
        self.spinbox.grid(column=1, row=0, padx=10,pady=10)

        self.current_value_2 = tk.StringVar()
        self.current_value_2.set("200")
        self.spinbox_2 = ttk.Spinbox(self,from_=50,to=1000,increment=50,textvariable=self.current_value_2,wrap=True)
        self.spinbox_2.grid(column=1, row=1, padx=10,pady=10)

        self.current_value_3 = tk.StringVar()
        self.current_value_3.set("2000")
        self.spinbox_3 = ttk.Spinbox(self,from_=500,to=5000,increment=500,textvariable=self.current_value_3,wrap=True)
        self.spinbox_3.grid(column=1, row=2, padx=10,pady=10)

    def colors_radio(self):
        colors = (("White",0),("Green",1),("Yellow",2),("Red",3),("Blue",4),("Purple",5))
        self.selected_color = tk.StringVar()

        r = 3
        c = 1

        for color in colors:
            if(c == 4):
                c = 1
                r += 1

            rb = ttk.Radiobutton(self,text=color[0], value=color[1], variable=self.selected_color, command= lambda:print(self.selected_color.get()))
            rb.grid(column=c, row=r, padx=10,pady=10)
            c +=1

        self.selected_color.set(colors[1][1])

        self.selected_color_2 = tk.StringVar()

        r = 5
        c = 1

        for color in colors:
            if(c == 4):
                c = 1
                r += 1

            rb = ttk.Radiobutton(self,text=color[0], value=color[1], variable=self.selected_color_2,command= lambda:print(self.selected_color_2.get()))
            rb.grid(column=c, row=r, padx=10,pady=10)
            c +=1

        self.selected_color_2.set(colors[0][1])

    def apply_button(self):
        apply = tk.Button(self, text= "Apply", command=self.quit)
        apply.grid(column=0, row=7, pady = 10, padx = 10)

    def quit(self):
        tmp = self.check_setting()
        if(tmp[0]):
            self.apply_settings()
            self.destroy()
        else:
            #TODO moze to wyswietylanie info
            showerror(title="Error", message=tmp[1])

    def check_setting(self):
        true_or_false = True
        msg = ""
        try:
            int(self.current_value.get())
        except:
            true_or_false =  False
            msg+= "Invalid speed data type\n"
        try:
            int(self.current_value_2.get())
        except:
            true_or_false =  False
            msg+= "Invalid points amount data type\n"
        try:
            int(self.current_value_3.get())
        except:
            true_or_false =  False
            msg+= "Invalid axes lenght data type\n"

        if(true_or_false):
            if(int(self.current_value_3.get()) >5000 or int(self.current_value_3.get()) < 500 ):
                true_or_false =  False
                msg+="Axes lenght is greater than 5000 or less than 500\n"

            if(int(self.current_value_2.get())>1000 or int(self.current_value_2.get()) < 50 ):
                true_or_false =  False
                msg += "Points amount is greater than 1000 or less than 50\n"

            if( int(self.current_value.get()) >15 or  int(self.current_value.get()) < 1 ):
                true_or_false =  False
                msg += "Speed is greater than 15 or less than 1"

        return (true_or_false, msg)

    def apply_settings(self):
        self.settings.set_points_color(int(self.selected_color.get()))
        self.settings.set_axes_color(int(self.selected_color_2.get()))

        self.settings.set_speed(int(self.current_value.get()))
        self.settings.set_points_amount(int(self.current_value_2.get()))
        self.settings.set_axes_length(int(self.current_value_3.get()))


import sys

file_name = sys.argv[1]

with open(file_name) as mp:
    program = mp.readlines()

commands = ["varbl", "write", "if", "end", "calc", "check", "\n"]
stack = {}          # For holding simple variables
signs = ["+", "-", "*", "/", "**"]  # For arithmetic operations
cmp_signs = [">", "<", "=", "!=", "&", "|", "!"]  # For comparisons
reserved = ["write", "calc", "varbl", "TRUE", "FALSE", "begin cond", "end cond", "begin loop", "end loop"]
# Reserved words that cannot be used as a variable name

"""A Function to make simple arithmetic operations"""
def calc(*args):
    op1 = args[0]
    op2 = args[2]
    sign = args[1]
    if sign == "+":
        print(op1 + op2)
        return op1 + op2
    elif sign == "-":
        print(op1 - op2)
        return op1 - op2
    elif sign == "*":
        print(op1 * op2)
        return op1 * op2
    elif sign == "/":
        print(op1 / op2)
        return op1 / op2
    elif sign == "**":
        print(op1 ** op2)
        return op1 ** op2

"""A function for declaring variables and storing them in the stack"""
def var_declaring(lst):
    name = lst[1]
#    print(name)
    assert not name[0].isnumeric()   # A variable cannot start with a number
    assert name not in reserved
    assert lst[2] == "->"
    value = lst[3]
#    print(value)
    try:
        float(value)
    except:
        if len(lst) > 4:
            if lst[-1] == ' "':
                lst[-2] += lst[-1]

            else:
                if lst[3][0] == '"':
                    for i in range(4, len(lst)):
                        if "{" in lst[i] and "}" in lst[i]:
                            var = lst[i].strip()[1:-1]
                            if var in stack:
                                lst[i] = stack[var]
#                                print(lst)
                                value += ' ' + lst[i]
                        else:
                            value += ' ' + lst[i]
                            # print(value)
                    stack[name] = value[1:-1]
                else:
                    if lst[3] in stack.keys() and lst[5] in stack.keys():
                        res = calc(float(stack[lst[3]]), lst[4], float(stack[lst[5]]))
                        stack[name] = res
                    elif lst[3] in stack.keys() and lst[5] not in stack.keys():
                        res = calc(float(stack[lst[3]]), lst[4], float(lst[5]))
                        stack[name] = res
                    elif lst[3] not in stack.keys() and lst[5] in stack.keys():
                        res = calc(float(lst[3]), lst[4], float(stack[lst[5]]))
                        stack[name] = res

        else:
            if value == "TRUE" or value == "FALSE":
                stack[name] = value
            elif value in stack.keys():
                stack[name] = stack[value]
            else:
                stack[name] = value[1:-1]
    else:
        if len(lst) == 4:
            stack[name] = float(value)
        else:
            if lst[4] in signs:
                try:
                    float(lst[3]) and float(lst[5]) and lst[4] in signs
                except:
                    if lst[5] in stack.keys():
                        res = calc(float(lst[3]), lst[4], float(stack[lst[5]]))
                        stack[name] = res
                    else:
                        print("Error!")
                else:
                    res = calc(float(lst[3]), lst[4], float(lst[5]))
                    stack[name] = res

"""A Function for comparisons"""
def check(condition):
    cmp_lst = condition.split()
#    print(cmp_lst)
    assert cmp_lst[1] in cmp_signs
    if cmp_lst[0] not in stack.keys() and cmp_lst[2] not in stack.keys():
        try:
            float(cmp_lst[0]) and float(cmp_lst[2])
        except:
            if cmp_lst[0][0] == '"' and cmp_lst[0][-1] == '"' and cmp_lst[2][0] == '"' and cmp_lst[2][-1] == '"':
                if cmp_lst[1] == ">":
                    if cmp_lst[0] > cmp_lst[2]:
                        return True
                    else:
                        return False
                elif cmp_lst[1] == "<":
                    if cmp_lst[0] < cmp_lst[2]:
                        return True
                    else:
                        return False
                elif cmp_lst[1] == "==":
                    if cmp_lst[0] == cmp_lst[2]:
                        return True
                    else:
                        return False
                elif cmp_lst[1] == "!=":
                    if cmp_lst[0] != cmp_lst[2]:
                        return True
                    else:
                        return False
            else:
                print("Error,can't compare the values")
        else:
            if(cmp_lst[1]) == ">":
                if float(cmp_lst[0]) > float(cmp_lst[2]):
                    return True
                else:
                    return False
            elif(cmp_lst[1]) == "<":
                if float(cmp_lst[0]) < float(cmp_lst[2]):
                    return True
                else:
                    return False
            elif(cmp_lst[1]) == "==":
                if float(cmp_lst[0]) == float(cmp_lst[2]):
                    return True
                else:
                    return False
            elif cmp_lst[1] == "!=":
                if float(cmp_lst[0]) != float(cmp_lst[2]):
                    return True
                else:
                    return False

    elif cmp_lst[0] in stack.keys():
        if cmp_lst[2] in stack.keys():
            if cmp_lst[1] == ">":
                if stack[cmp_lst[0]] > stack[cmp_lst[2]]:
                    return True
                else:
                    return False
            elif cmp_lst[1] == "<":
                if stack[cmp_lst[0]] < stack[cmp_lst[2]]:
                    return True
                else:
                    return False
            elif cmp_lst[1] == "==":
                if stack[cmp_lst[0]] == stack[cmp_lst[2]]:
                    return True
                else:
                    return False
            elif cmp_lst[1] == "!=":
                if stack[cmp_lst[0]] != stack[cmp_lst[2]]:
                    return True
                else:
                    return False

        else:
            try:
                float(cmp_lst[2])
            except:
                if cmp_lst[1] == ">":
                    if stack[cmp_lst[0]] > cmp_lst[2]:
                        return True
                    else:
                        return False
                elif cmp_lst[1] == "<":
                    if stack[cmp_lst[0]] < cmp_lst[2]:
                        return True
                    else:
                        return False
                elif cmp_lst[1] == "==":
                    if stack[cmp_lst[0]] == cmp_lst[2]:
                        return True
                    else:
                        return False
                elif cmp_lst[1] == "!=":
                    if stack[cmp_lst[0]] != cmp_lst[2]:
                        return True
                    else:
                        return False
            else:
                if cmp_lst[1] == ">":
                    if stack[cmp_lst[0]] > float(cmp_lst[2]):
                        return True
                    else:
                        return False
                elif cmp_lst[1] == "<":
                    if stack[cmp_lst[0]] < float(cmp_lst[2]):
                        return True
                    else:
                        return False
                elif cmp_lst[1] == "==":
                    if stack[cmp_lst[0]] == float(cmp_lst[2]):
                        return True
                    else:
                        return False
                elif cmp_lst[1] == "!=":
                    if stack[cmp_lst[0]] != float(cmp_lst[2]):
                        return True
                    else:
                        return False
    else:
        try:
            float(cmp_lst[0])
        except:
            if cmp_lst[1] == ">":
                if cmp_lst[0] > stack[cmp_lst[2]]:
                    return True
                else:
                    return False
            elif cmp_lst[1] == "<":
                if cmp_lst[0] < stack[cmp_lst[2]]:
                    return True
                else:
                    return False
            elif cmp_lst[1] == "==":
                if cmp_lst[0] == stack[cmp_lst[2]]:
                    return True
                else:
                    return False
            elif cmp_lst[1] == "!=":
                if cmp_lst[0] != stack[cmp_lst[2]]:
                    return True
                else:
                    return False

        else:
            if cmp_lst[1] == ">":
                if float(cmp_lst[0]) > stack[cmp_lst[2]]:
                    return True
                else:
                    return False
            elif cmp_lst[1] == "<":
                if float(cmp_lst[0]) < stack[cmp_lst[2]]:
                    return True
                else:
                    return False
            elif cmp_lst[1] == "==":
                if float(cmp_lst[0]) == stack[cmp_lst[2]]:
                    return True
                else:
                    return False
            elif cmp_lst[1] == "!=":
                if float(cmp_lst[0]) != stack[cmp_lst[2]]:
                    return True
                else:
                    return False

"""A Function for conditionals"""
def conditional(start, end):
    cond_block = program[start:end]
#   print(cond_block)
    cond_block[0] = cond_block[0].strip()
#   print(cond_block[0])
    if cond_block[0][0:2] == "if" and cond_block[0][3] == "(" and cond_block[0][-3] == ")" and cond_block[0][-1] == "[":
        cond_start_index = cond_block[0].index("(") + 1
        cond_end_index = cond_block[0].index(")")
        condd = cond_block[0][cond_start_index:cond_end_index]
        if check(condd):
            for k in range(start, end+1):
                del program[start-1]
#               print(program)
#           print(cond_block)
            loop_end = cond_block.index("]\n")
            for j in cond_block[1:loop_end]:
                main(j)
        else:
#           print(cond_block.index("]\n")+1)
            for k in range(start, start+cond_block.index("]\n")+1):
                del program[start]
#               print(program)
            main(program[start-1])
    elif cond_block[0][0:4] == "elif" and cond_block[0][5] == "(" and cond_block[0][-3] == ")" and cond_block[0][-1]=="[":
        cond_start_index = cond_block[0].index("(") + 1
        cond_end_index = cond_block[0].index(")")
        condd = cond_block[0][cond_start_index:cond_end_index]
#       print(cond_block)
        if check(condd):
            for k in range(start, end+1):
                del program[start-1]
#               print(program)
            loop_end = cond_block.index("]\n")
            for j in cond_block[1:loop_end]:
                main(j)
        else:
#           print(cond_block.index("]\n")+1)
            for k in range(start, start+cond_block.index("]\n")+1):
                del program[start]
#               print(program)
            main(program[start-1])
    elif cond_block[0][0:4] == "else" and cond_block[0][-1]=="[":
        for k in range(start, end + 1):
            del program[start - 1]
#           print(program)
        loop_end = cond_block.index("]\n")
        for j in cond_block[1:loop_end]:
            main(j)

"""A Function that makes an output"""
def write(raw, text=''):
    assert raw[0] == '"' and raw[-1] == '"'

    plain_txt = raw[1:-1].split()
    for i in plain_txt:
        if "{" not in i or "}" not in i:
            text += ' ' + i
        else:
            assert i[1:-1] in stack
            current = stack[i[1:-1]]
            if(type(current)) == "str":
                text += ' ' + current
            else:
                text += ' ' + f"{current}"
    print(text)

"""A Function for handling loops"""
def loop(start_l, end_l):
#   print(start_l, end_l)
#   print(program[start_l:end_l])
    loop_block = program[start_l:end_l]
    loop_cond_body = loop_block[0]
    loop_lst = loop_cond_body.split()
    varr = loop_lst[0]
#   print(loop_lst)
    assert varr in stack
    assert loop_lst[1] == varr and loop_lst[4] == varr
    assert loop_lst[5] in signs

    cond1 = varr + ' ' + loop_lst[2] + ' ' + loop_lst[3]
#   print(cond1)
    if loop_lst[6] not in stack:
        cond1_res = check(cond1)
        if cond1_res:
            block_size = end_l - start_l - 2
            for i in range(block_size):
                main(loop_block[i])
            stack[varr] += float(loop_lst[6])
            main(program[start_l - 1])
        else:
            for l in range(start_l - 1, end_l):
                del program[start_l - 1]
    else:
        cond1_res = check(cond1)
        if cond1_res:
            block_size = end_l - start_l - 2
            for i in range(block_size):
                main(loop_block[i])
            stack[varr] += stack[loop_lst[6]]
            main(program[start_l - 1])
        else:
            for l in range(start_l - 1, end_l):
                del program[start_l - 1]

def main(line):
    # print(main_pr)
    lst = line.split()
    # print(lst)
    if lst:

        if lst[0] == "varbl":
            var_declaring(lst)

        elif lst[0][:5] == "write":
            raw = line[6:].strip()
            write(raw)

        elif lst[0] == "calc":
            if lst[1] in stack.keys() and lst[3] in stack.keys():
                calc(float(stack[lst[1]]), lst[2], float(stack[lst[3]]))
            elif lst[1] in stack.keys() and lst[3] not in stack.keys():
                calc(float(stack[lst[1]]), lst[2], float(lst[3]))
            elif lst[1] not in stack.keys() and lst[3] in stack.keys():
                calc(float(lst[1]), lst[2], float(stack[lst[3]]))
            else:
                calc(float(lst[1]), lst[2], float(lst[3]))

        elif lst[0] == "begin" and lst[1] == "cond":
            start = program.index("begin cond\n") + 1
#           print(start)
            end = program.index("end cond\n") + 1
#           print(end)
#           print(program)
            conditional(start, end)

        elif lst[0] == "begin" and lst[1] == "loop":
            start_l = program.index("begin loop\n") + 1
            end_l = program.index("end loop\n") + 1
            loop(start_l, end_l)

        elif lst[0][:2] == "**":
            pass

for line in program:
    main(line)

# for key, value in stack.items():  # Printing the variable/value table
#    print(key, ":", value)


# Code in this file is copied and adapted from
# https://github.com/openai/evolution-strategies-starter.

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

from collections import namedtuple
import logging
import numpy as np
import time

import ray
from ray.rllib.agents import Agent, with_common_config

from ray.rllib.agents.ga_eps import optimizers
from ray.rllib.agents.ga_eps import policies
from ray.rllib.agents.ga_eps import utils
from ray.rllib.agents.ga_eps import tf_util
from ray.rllib.utils import FilterManager

import gym
import tensorflow as tf
from ray.rllib.env.atari_wrappers import is_atari, get_wrapper_by_cls, MonitorEnv, EpisodicLifeEnv, wrap_deepmind

logger = logging.getLogger(__name__)

Result = namedtuple("Result", [
    "noise_indices", "noisy_returns", "noisy_acc_returns","sign_noisy_returns", "noisy_lengths",
    "eval_returns", "eval_acc_returns","eval_lengths","novelty","policy_weights"])

# yapf: disable
# __sphinx_doc_begin__
DEFAULT_CONFIG = with_common_config({
    "l2_coeff": 0.005,
    "noise_stdev": 0.02,
    "noise_stdevGA": 0.02,
    "episodes_per_batch": 7,
    "train_batch_size": 1000,
    "eval_prob": 0.003,
    "return_proc_mode": "centered_rank",
    "num_workers": 7,#10
    "stepsize": 0.01,
    "observation_filter": "MeanStdFilter",
    "noise_size": 250000000,
    "report_length": 10,
    "pop_size": 1,
    "population_size":20,
    "bf_sz":2000,
    "k":10,
    "epsilon":0.5,
    "neinum":10,
    "eta_c":20
})
# __sphinx_doc_end__
# yapf: enable

@ray.remote
def create_shared_noise(count):
    """Create a large array of noise to be shared by all workers."""
    seed = 123
    noise = np.random.RandomState(seed).randn(count).astype(np.float32)
    return noise

class SharedNoiseTable(object):
    def __init__(self, noise):
        self.noise = noise
        assert self.noise.dtype == np.float32

    def get(self, i, dim):
        return self.noise[i:i + dim]

    def sample_index(self, dim):
        return np.random.randint(0, len(self.noise) - dim + 1)

# def get_ref_batch(env, batch_size):
#     ref_batch = []
#     observation = env.reset()
#     while len(ref_batch) < batch_size:
#         observation, rew, done, info= env.step(env.action_space.sample())
#         ref_batch.append(observation)
#         if done:
#             observation = env.reset()
#     return ref_batch

def _monitor(env, path):
    return gym.wrappers.Monitor(env, path, resume=True)

@ray.remote
class Worker(object):
    def __init__(self,
                 config,
                 policy_params,
                 env_creator,
                 noise,
                 monitor_path,
                 min_task_runtime=0.2):
        self.min_task_runtime = min_task_runtime
        self.config = config
        self.policy_params = policy_params
        self.noise = SharedNoiseTable(noise)

        self.monitor_path = monitor_path
        self.env = env_creator(config["env_config"])
        self.memory=[]

        if is_atari(self.env):
            self.env = wrap_deepmind(
                    self.env,
                    dim=84,
                    framestack=4)

        if np.random.uniform()<0.5:
          if self.monitor_path:
             self.env = _monitor(self.env, self.monitor_path)
        else:
           self.env = env_creator(config["env_config"])
           if is_atari(self.env):
                self.env = wrap_deepmind(
                    self.env,
                    dim=84,
                    framestack=4)

        self.env2=env_creator(config["env_config"])
        if is_atari(self.env2):
                self.env2 = wrap_deepmind(
                    self.env2,
                    dim=84,
                    framestack=4)

        from ray.rllib import models
        self.preprocessor = models.ModelCatalog.get_preprocessor(
            self.env, config["model"])

        self.sess = utils.make_session(single_threaded=True)

        self.policy = policies.GenericPolicy(
            self.sess, self.env,self.env2,self.env.action_space, self.env.observation_space,
            self.preprocessor, config["observation_filter"], config["model"],
            **policy_params)
        #self.sess.run(tf.global_variables_initializer())

        #self.sess1 = utils.make_session(single_threaded=True)

        # self.policymax = policies.GenericPolicy(
        #     self.sess, self.env,self.env2,self.env.action_space, self.env.observation_space,
        #     self.preprocessor, config["observation_filter"], config["model"],
        #     **policy_params)
        self.sess.run(tf.global_variables_initializer())

    @property
    def filters(self):
        return {"default": self.policy.get_filter()}

    def sync_filters(self, new_filters):
        for k in self.filters:
            self.filters[k].sync(new_filters[k])

    def get_filters(self, flush_after=False):
        return_filters = {}
        for k, f in self.filters.items():
            return_filters[k] = f.as_serializable()
            if flush_after:
                f.clear_buffer()
        return return_filters

    def rollout(self, timestep_limit, add_noise=True):

        novelty,rollout_returns,rollout_rewards, rollout_length= policies.rollout(
            self.policy,
            self.config,
            self.env,
            timestep_limit=timestep_limit,
            add_noise=add_noise)
        return novelty,rollout_returns,rollout_rewards, rollout_length

    def do_rollouts(self, params, population,timestep_limit=None):

        # Set the network weights.
        self.policy.set_weights(params)

        noise_indices, acc_returns,returns, sign_returns, lengths,novelty,rew_chgs,entro_chgs,distances = [], [], [], [], [],[],[],[],[]
        eval_acc_returns,eval_returns, eval_lengths = [], [], []
        policy_weights=[]

        # Perform some rollouts with noise.
        task_tstart = time.time()
        while (len(noise_indices) == 0
               or time.time() - task_tstart < self.min_task_runtime):

            if np.random.uniform() < self.config["eval_prob"]:
                # Do an evaluation run with no perturbation.
                #print("enter <")
                self.policy.set_weights(params)
                nov,acc_rewards,rewards, length= self.rollout(timestep_limit,add_noise=False)
                eval_acc_returns.append(acc_rewards.sum())
                eval_returns.append(rewards.sum())
                eval_lengths.append(length)

            else:
                noise_index = self.noise.sample_index(self.policy.num_params)

                perturbation = self.config["noise_stdevGA"] * self.noise.get(
                    noise_index, self.policy.num_params)

                if len(population)==0:
                	v=self.noise.get(noise_index,self.policy.num_params)
                else:
                    v1=population[np.random.randint(len(population))][0]
                    v2=population[np.random.randint(len(population))][0]

                    u=np.random.rand(1)
                    u=u[0]
                    if u<=0.5:
                    	beta=(2*u)**(1.0/(self.config["eta_c"]+1))
                    else:
                    	beta=(1.0/(2*(1-u)))**(1.0/(self.config["eta_c"]+1))
                    #print('v1 is {}'.format(v1))
                    v1=np.array(v1)
                    v2=np.array(v2)
                    v=0.5*((1+beta)*v1+(1-beta)*v2)
                    v=v.tolist()
                    #v=population[0][0]

                v=v+perturbation

                self.policy.set_weights(v)

                nov_pos,acc_rewards_pos,rewards_pos, lengths_pos= self.rollout(timestep_limit)
                policy_pos=self.policy.get_weights()

                noise_indices.append(noise_index)
                returns.append(rewards_pos.sum())
                acc_returns.append(acc_rewards_pos.sum())
                sign_returns.append(
                    [np.sign(rewards_pos).sum()])
                lengths.append([lengths_pos])
                novelty.append([nov_pos[0]])
                policy_weights.append([policy_pos])

                #cross_entros=np.array(cross_entros,dtype=np.float32)

        return Result(
            noise_indices=noise_indices,
            noisy_returns=returns,
            noisy_acc_returns=acc_returns,
            sign_noisy_returns=sign_returns,
            noisy_lengths=lengths,
            eval_returns=eval_returns,
            eval_acc_returns=eval_acc_returns,
            eval_lengths=eval_lengths,
            novelty=novelty,
            policy_weights=policy_weights)

class ESAgent(Agent):
    """Large-scale implementation of Evolution Strategies in Ray."""

    _agent_name = "GA_eps"
    _default_config = DEFAULT_CONFIG

    def _init(self):
        policy_params = {"action_noise_std": 0.01}
        self.theta_dict = []
        self.policymax=[]
        self.curr_parent = 0
        self.population=[]
        self.returns_n2=[]
        self.ret=[]

        env = self.env_creator(self.config["env_config"])
        self.monitor_path=self.logdir if self.config["monitor"] else None
        if is_atari(env):
            env = wrap_deepmind(
                    env,
                    dim=84,
                    framestack=4)

        env2=self.env_creator(self.config["env_config"])
        if is_atari(env2):
                env2 = wrap_deepmind(
                    env2,
                    dim=84,
                    framestack=4)

        from ray.rllib import models
        preprocessor = models.ModelCatalog.get_preprocessor(env)

        for p in range(self.config["pop_size"]):
            with tf.Graph().as_default():
                self.sess = utils.make_session(single_threaded=False)
                self.policy = policies.GenericPolicy(self.sess, env,env2,env.action_space, env.observation_space, preprocessor, self.config["observation_filter"], self.config["model"],**policy_params)
                tf_util.initialize(self.sess)
                theta= self.policy.get_weights()
                self.theta_dict.append(theta)

        self.optimizer = optimizers.Adam(self.policy, self.config["stepsize"])
        self.report_length = self.config["report_length"]
        # Create the shared noise table.
        logger.info("Creating shared noise table.")
        noise_id = create_shared_noise.remote(self.config["noise_size"])
        self.noise = SharedNoiseTable(ray.get(noise_id))

        # for p in range(self.config["population_size"]):
        #     noise_index = self.noise.sample_index(self.policy.num_params)
        #     self.population.append(self.noise.get(noise_index, self.policy.num_params))

        # Create the actors.
        logger.info("Creating actors.")
        self.workers = [
            Worker.remote(self.config, policy_params, self.env_creator,
                          noise_id, self.monitor_path) for _ in range(self.config["num_workers"])
        ]

        self.episodes_so_far = 0
        self.reward_list1 = []
        self.reward_list2 = []
        self.reward_list3 = []
        self.tstart = time.time()

        self.noisy_rew_max1=-1000
        self.noisy_rew_mean1=-1000
        self.noisy_rew_max2=-1000
        self.noisy_rew_mean2=-1000
        self.noisy_rew_max3=-1000
        self.noisy_rew_mean3=-1000
        self.noisy_rew_max4=-1000
        self.noisy_rew_mean4=-1000

        self.reward_mean1=-1000
        self.reward_mean2=-1000
        self.reward_mean3=-1000

        self.maxrew=[]
        self.maxrew2=[]

    def _collect_results(self, theta_id, min_episodes, min_timesteps):
        num_episodes, num_timesteps = 0, 0
        reward_mean,reward_max,reward_min=0,0,0
        results = []
        r1=[]
        r2=[]
        policy_candidate1=[]
        if self.curr_parent==0:
            rewmax=self.noisy_rew_max1
            rewmean=self.noisy_rew_mean1
            self.policymax=[]
            self.maxrew=[]
            self.maxrew2=[]
        elif self.curr_parent==1:
        	rewmax=self.noisy_rew_max2
        	rewmean=self.noisy_rew_mean2
        elif self.curr_parent==2:
        	rewmax=self.noisy_rew_max3
        	rewmean=self.noisy_rew_mean3
        elif self.curr_parent==3:
        	rewmax=self.noisy_rew_max4
        	rewmean=self.noisy_rew_mean4

        while num_episodes < min_episodes or num_timesteps < min_timesteps:
            logger.info(
                "Iteration {}, collected {} episodes {} timesteps so far this iter, cur_par={},rew_max={}, rew_mean={}, rew_min={}, last rew_max1={}, rew_mean1={},rew_max2={}, rew_mean2={},rew_max3={}, rew_mean3={},rew_max4={}, rew_mean4={}".format(
                    self.iteration+1,num_episodes, num_timesteps,self.curr_parent, reward_max,reward_mean,reward_min,self.noisy_rew_max1,self.noisy_rew_mean1,self.noisy_rew_max2,self.noisy_rew_mean2,self.noisy_rew_max3,self.noisy_rew_mean3,self.noisy_rew_max4,self.noisy_rew_mean4))
            rollout_ids = [
                worker.do_rollouts.remote(theta_id,self.population) for worker in self.workers
            ]
            # Get the results of the rollouts.
            #print('start')
            for result in ray.get(rollout_ids):
                results.append(result)
                r1+=result.noisy_returns
                r2+=result.noisy_acc_returns
                policy_candidate1+=result.policy_weights
                # if len(result.eval_returns)>0:
                #     r1+=result.eval_returns
                # Update the number of episodes and the number of timesteps
                # keeping in mind that result.noisy_lengths is a list of lists,
                # where the inner lists have length 2.
                num_episodes += sum(len(pair) for pair in result.noisy_lengths)
                num_timesteps += sum(
                    sum(pair) for pair in result.noisy_lengths)
            r=np.array(r1)
            r_acc=np.array(r2)
            #print('shape of r is {}'.format(r.shape))
            #print('policy_candidate1 is {}'.format(np.array(policy_candidate1).shape))
            reward_mean=np.mean(r)
            reward_max=np.max(r)
            reward_min=np.min(r)

        if self.curr_parent is not self.config["pop_size"]-1:
           r_acc_flat=r_acc.flatten()
           idx=np.argmax(r_acc_flat)
           policy_candidate=policy_candidate1[idx]

           self.policymax.append(policy_candidate)
           self.maxrew.append(r_acc_flat[idx])   #acc_return

           idx2=np.argmax(r.flatten())
           self.maxrew2.append(r.flatten()[idx2])   #return

           	   # if self.maxrew[1]>self.maxrew[0]:
           	   # 	  temp=self.maxrew[0]
           	   # 	  temppolicy=self.policymax[0]
           	   # 	  self.maxrew[0]=self.maxrew[1]
           	   # 	  self.policymax[0]=self.policymax[1]
           	   # 	  self.maxrew[1]=temp
           	   # 	  self.policymax[1]=temppolicy

        if self.curr_parent==0:
        	self.noisy_rew_max1=reward_max
        	self.noisy_rew_mean1=reward_mean
        elif self.curr_parent==1:
        	self.noisy_rew_max2=reward_max
        	self.noisy_rew_mean2=reward_mean
        elif self.curr_parent==2:
        	self.noisy_rew_max3=reward_max
        	self.noisy_rew_mean3=reward_mean
        elif self.curr_parent==3:
        	self.noisy_rew_max4=reward_max
        	self.noisy_rew_mean4=reward_mean

        return results, num_episodes, num_timesteps,self.policymax,self.maxrew

    def _train(self):
        config = self.config

        theta = self.theta_dict[self.curr_parent]
        #print('theta shape is {}'.format(np.array(theta).shape))
        self.policy.set_weights(theta)
        assert theta.dtype == np.float32

        # Put the current policy weights in the object store.
        theta_id = ray.put(theta)
        # Use the actors to do rollouts, note that we pass in the ID of the
        # policy weights.
        results, num_episodes, num_timesteps, self.policymax, self.rewmax= self._collect_results(
            theta_id, config["episodes_per_batch"], config["train_batch_size"])

        all_noise_indices = []
        all_training_returns = []
        all_training_lengths = []
        all_eval_returns = []
        all_eval_lengths = []
        all_training_acc_returns=[]
        all_eval_acc_returns=[]
        all_policy_weight=[]
        all_novelty=[]
        all_rew_chgs=[]
        all_entro_chgs=[]
        all_distances=[]

        # Loop over the results.
        for result in results:
            all_eval_returns += result.eval_returns
            all_eval_lengths += result.eval_lengths
            all_eval_acc_returns+=result.eval_acc_returns

            all_noise_indices += result.noise_indices
            all_training_returns += result.noisy_returns
            all_training_lengths += result.noisy_lengths
            all_training_acc_returns+=result.noisy_acc_returns

            all_policy_weight+= result.policy_weights

            all_novelty+=result.novelty

        assert len(all_eval_returns) == len(all_eval_lengths)
        assert (len(all_noise_indices) == len(all_training_returns) ==
                len(all_training_lengths))

        self.episodes_so_far += num_episodes

        # Assemble the results.
        eval_returns = np.array(all_eval_returns)
        eval_lengths = np.array(all_eval_lengths)
        noise_indices = np.array(all_noise_indices)
        noisy_returns = np.array(all_training_returns)
        noisy_lengths = np.array(all_training_lengths)
        novelty_entropy=np.array(all_novelty)

        eval_acc_returns=np.array(all_eval_acc_returns)
        noisy_acc_returns=np.array(all_training_acc_returns)

        # Process the returns.

        # Compute and take a step.

           #print('enter1')
        population=self.population
        returns_n2=self.returns_n2
        ret=self.ret
        population.extend(all_policy_weight)
        #returns_n2.extend(all_training_returns)

        returns_n2.extend(all_training_acc_returns)
        ret.extend(all_training_returns)
        population.extend(self.policymax)
        returns_n2.extend(self.maxrew)
        ret.extend(self.maxrew2)

        population2=np.array(population)
        returns2_n2=np.array(returns_n2)
        ret2=np.array(ret)

        returns2_n2,indices=np.unique(returns2_n2,return_index=True)
        #population2=population2[indices]

        ret2,ind=np.unique(ret2,return_index=True)
        population2=population2[ind]
        #print('enter2')
        #print('population shape is {}'.format(population2.shape))
        print('returns_n2 is {}'.format(returns_n2))
        print('ret2 is {}'.format(ret2))
        print('returns2_n2 shape is {}'.format(returns2_n2.shape))
        if population2.shape[0]>=config["population_size"]:
            if len(returns2_n2.tolist())>=config["population_size"]:
               idx = np.argpartition(returns2_n2, (-config["population_size"], -1))[-1:-config["population_size"]-1:-1]
	           #population2 = population2[idx]
               returns2_n2=returns2_n2[idx]

            if len(ret2.tolist())>=config["population_size"]:
               idx2 = np.argpartition(ret2, (-config["population_size"], -1))[-1:-config["population_size"]-1:-1]
               ret2=ret2[idx2]
               population2=population2[idx2]

        #print('enter3')
        theta=population2[0][0]
        #print('shape of theta is {}'.format(theta.shape))
        self.population=population2.tolist()
        self.returns_n2=returns2_n2.tolist()
        self.ret=ret2.tolist()

        print("returns_n2 is {}".format(self.returns_n2))
        print("ret2 is {}".format(ret2))

        g=-1000
        update_ratio=-1000

        # Set the new weights in the local copy of the policy.
        self.policy.set_weights(theta)
        self.theta_dict[self.curr_parent] = self.policy.get_weights()

        # Store the rewards
        if len(all_eval_returns)>0:
	        if self.curr_parent == 0:
	            self.reward_list1.append(np.mean(eval_returns))

	        if self.curr_parent == 1:
	            self.reward_list2.append(np.mean(eval_returns))

	        if self.curr_parent == 2:
	            self.reward_list3.append(np.mean(eval_returns))

        # Now sync the filters
        FilterManager.synchronize({
            "default": self.policy.get_filter()
        }, self.workers)

        info = {
            "weights_norm": np.square(theta).sum(),
            "grad_norm": np.square(g).sum(),
            "update_ratio": update_ratio,
            "episodes_this_iter": noisy_lengths.size,
            "episodes_so_far": self.episodes_so_far,
        }
        #self.iteration

        if self.curr_parent==0:
            self.reward_mean1 = np.mean(self.reward_list1[-self.report_length:])
            # if len(self.reward_list1)>=self.report_length:
	           #   reward_max1=np.max(self.reward_list1[-self.report_length:])
	           #   reward_min1=np.min(self.reward_list1[-self.report_length:])
        if self.curr_parent==1:
            self.reward_mean2 = np.mean(self.reward_list2[-self.report_length:])
            # if len(self.reward_list2)>=self.report_length:
	           #   reward_max2=np.max(self.reward_list2[-self.report_length:])
	           #   reward_min2=np.min(self.reward_list2[-self.report_length:])
        if self.curr_parent==2:
	        self.reward_mean3 = np.mean(self.reward_list3[-self.report_length:])
             # if len(self.reward_list3)>=self.report_length:
	            #  reward_max3=np.max(self.reward_list3[-self.report_length:])
	            #  reward_min3=np.min(self.reward_list3[-self.report_length:])
        # reward_mean_noise=np.mean(all_training_returns)
        # reward_max_noise=np.max(all_training_returns)
        # reward_min_noise=np.min(all_training_returns)
        result = dict(
            #episode_reward_min1=reward_min1,
            episode_reward_mean1=self.reward_mean1,
            #episode_reward_max1=reward_max1,
            #episode_reward_min2=reward_min2,
            episode_reward_mean2=self.reward_mean2,
            #episode_reward_max2=reward_max2,
            #episode_reward_min3=reward_min3,
            episode_reward_mean3=self.reward_mean3,
            #episode_reward_max3=reward_max3,
            # noise_reward_min=reward_min_noise,
            # noise_reward_mean=reward_mean_noise,
            # noise_reward_max=reward_max_noise,
            episode_len_mean=eval_lengths.mean(),
            timesteps_this_iter=noisy_lengths.sum(),
            info=info)
        self.curr_parent = (self.curr_parent + 1) % config["pop_size"]

        return result

    def _stop(self):
        # workaround for https://github.com/ray-project/ray/issues/1516
        for w in self.workers:
            w.__ray_terminate__.remote()

    def __getstate__(self):
        return {
            "weights": self.policy.get_weights(),
            "filter": self.policy.get_filter(),
            "episodes_so_far": self.episodes_so_far,
        }

    def __setstate__(self, state):
        self.episodes_so_far = state["episodes_so_far"]
        self.policy.set_weights(state["weights"])
        self.policy.set_filter(state["filter"])
        FilterManager.synchronize({
            "default": self.policy.get_filter()
        }, self.workers)

    def compute_action(self, observation):
        return self.policy.compute(observation, update=False)[0]


fi = open("square.in")
fo = open("square.out", "w+")
stuff = fi.read().split("\n")
r1 = stuff[0].split(" ")
r2 = stuff[1].split(" ")
r1 = [int(x) for x in r1]
r2 = [int(x) for x in r2]
maxX = int(max(r1[0], r1[2], r2[0], r2[2]))
minX = int(min(r1[0], r1[2], r2[0], r2[2]))
maxY = int(max(r1[1], r1[3], r2[1], r2[3]))
minY = int(min(r1[1], r1[3], r2[1], r2[3]))
maxDist = max(abs(maxX-minX), abs(maxY-minY))
area = pow(maxDist,2)
print >>fo, area
fi.close()
fo.close()


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

# In[8]:

import pandas as pd

# Load the dataset
data = pd.read_csv('house_rental_data.csv')

# Display the first few rows of the dataset
print(data.head())

# Display basic statistics of the dataset
print(data.describe())

# Display information about the dataset (data types, missing values, etc.)
print(data.info())

import matplotlib.pyplot as plt
import seaborn as sns

# Pairplot to visualize relationships between numerical variables
sns.pairplot(data)
plt.show()

# Histogram of the 'price' column
plt.figure(figsize=(8, 6))
sns.histplot(data['Price'], bins=20, kde=True)
plt.title('Distribution of Prices')
plt.xlabel('Price')
plt.ylabel('Frequency')
plt.show()

# Correlation heatmap
plt.figure(figsize=(10, 8))
sns.heatmap(data.corr(), annot=True, cmap='coolwarm')
plt.title('Correlation Heatmap')
plt.show()

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

# Selecting features and target variable
X = data.drop(['Price'], axis=1)
y = data['Price']

# Splitting the data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Standardize features using StandardScaler
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# In[ ]: