From 8966dcb919522a5d00950635a24c549544e436e9 Mon Sep 17 00:00:00 2001 From: awfk <awfkchan@gmail.com> Date: Thu, 23 Feb 2017 11:00:06 +0100 Subject: [PATCH 01/27] :-----------------D --- Sources/swift_exercises.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Sources/swift_exercises.swift b/Sources/swift_exercises.swift index c51721d..1e50f3d 100644 --- a/Sources/swift_exercises.swift +++ b/Sources/swift_exercises.swift @@ -171,3 +171,4 @@ struct State { func battle(trainers: inout [Trainer], behavior: (State, Trainer) -> Move) -> () { // TODO: simulate battle } +//dsfgnsdjhgksmdufhddmusflkughdsmkufhgskdfuhfkughdsfsdkufhgsdf \ No newline at end of file From 2d051ce832f2c7d93496bdb68ff694e401aef35f Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Thu, 23 Feb 2017 11:18:41 +0100 Subject: [PATCH 02/27] test --- Sources/swift_exercises.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/swift_exercises.swift b/Sources/swift_exercises.swift index 1e50f3d..8b8eebc 100644 --- a/Sources/swift_exercises.swift +++ b/Sources/swift_exercises.swift @@ -171,4 +171,4 @@ struct State { func battle(trainers: inout [Trainer], behavior: (State, Trainer) -> Move) -> () { // TODO: simulate battle } -//dsfgnsdjhgksmdufhddmusflkughdsmkufhgskdfuhfkughdsfsdkufhgsdf \ No newline at end of file +//test \ No newline at end of file From d0103f1791928ab1e1f0b28cac01c4ea0357a1fc Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Thu, 23 Feb 2017 22:32:14 +0100 Subject: [PATCH 03/27] implemented kangaskhan species and pokemon, with a full moveset. changed a bunch of let to var, and a couple int to float. also added a few of stubs --- Sources/swift_exercises.swift | 171 +++++++++++++++++++++++++++++++--- 1 file changed, 156 insertions(+), 15 deletions(-) diff --git a/Sources/swift_exercises.swift b/Sources/swift_exercises.swift index 8b8eebc..750e8d0 100644 --- a/Sources/swift_exercises.swift +++ b/Sources/swift_exercises.swift @@ -83,7 +83,7 @@ struct Move : Hashable { let description : String let category : Category let type : Type - let power : Int + var power : Int // let -> var let accuracy : Int let powerpoints : Int let priority : Int @@ -121,34 +121,175 @@ func ==(lhs: Species, rhs: Species) -> Bool { return lhs.id == rhs.id } -// TODO: create some species -// Do you use an enum, a map or constants/variables? -// http://bulbapedia.bulbagarden.net/wiki/List_of_Pokémon_by_National_Pokédex_number + +// create kangaskhan species +let species_kangaskhan = Species( + id: 155, + name: "Kangaskhan", + evolutions: [], + attacks: ["reversal", "earthquake", "ice beam", "sucker punch"], //and a load of others + type: .normal, + base_values: Stats( + hitpoints: 105, + attack: 95, + defense: 80, + special_attack: 40, + special_defense: 80, + speed: 90 + ) +) + + +/* four moves: reversal, earthquake, ice beam, and sucker punch. + +This is actually a decent offensive moveset, geared towards consistent (100% +accuracy) high damage while tanking (kangaskhan has high non-water HP, IVs +willing), rather than endurance (only 40 cumulative PPs, 25 if not counting +reversal) or status, and types are chosen so that there's always at least one +2x move (except against fight and ghost types, both of which are 1x). There +aren't really any STAB moves worth using in this optic (except maybe +frustration/return, but friendship isn't implemented. + +Possible but ultimately inconsistent candidates for powerful STAB would be: + dizzy punch: 1.5x70 with 20% chance of confusion; decent candidate, but ultimately worse than appropriately choosing type-specific moves. yeah, signature move and all + hyper beam: 1.5x150 is very good alpha, but the recovery round and the 90% accuracy screws it up; also, kangaskhan's spatk is relatively low + frustration/return: actually viable with extremely low/high friendship, but that mechanic isn't implemented and probably won't be, given the nature of this assignment + facade: boosted damage (1.5x2x70) seems good, but burn status halves physical damage, paralysis reduces effective damage per round by 25% and completely wrecks speed. If you're dangerously low on health reversal should be more than enough to finish them off (unless you're up against a ghost, in which case yeah tough shit). + giga impact: 1.5x150 is very good alpha, but the recovery round and the 90% accuracy screws it up + double edge: 1.5x120 is good alpha, but 1/3 recoil is just silly + uproar: 1.5x90 is alright, but it uses spatk and multi-turn moves are silly + +Also, keep in mind kangaskhan is normal-type and normal-type attacks are 1x +against everything (except rock and steel (0.5x), and ghost (0x)), normal-type +STAB isn't worth it over a potential 2x type bonus gained through the use of a +move chosen appropriately with regard to type. + +Comparatively high HP will allow for an efficient use of reversal should the +situation get dire, but it shouldn't be relied on earlier on. +*/ + +let move_reversal = Move( + id: 179, + name: "Reversal", + description: "Stronger if the user's HP is low.", + category: .physical, + type: .fighting, + power: 0, // variable base power, calculated when move is used + accuracy: 100, + powerpoints: 15, + priority: 0 +) + +let move_earthquake = Move( + id: 89, + name: "Earthquake", + description: "Tough but useless vs. flying foes.", + category: .physical, + type: .ground, + power: 100, + accuracy: 100, + powerpoints: 10, + priority: 0 +) + +let move_iceBeam = Move( + id: 58, + name: "Ice Beam", + description: "An attack that may freeze the foe.", + category: .special, + type: .ice, + power: 90, + accuracy: 100, + powerpoints: 10, + priority: 0 +) + +let move_suckerPunch = Move( + id: 389, + name: "Sucker Punch", + description: "This move enables the user to attack first. It fails if the foe is not readying an attack, however.", + category: .physical, + type: .fighting, + power: 70, + accuracy: 100, + powerpoints: 5, + priority: 1 +) + struct Pokemon { let nickname : String? - let hitpoints : Int // remaining hitpoints - let size : Int - let weight : Int - let experience : Int - let level : Int + var hitpoints : Int // remaining hitpoints; let -> var + let size : Float // int -> float + let weight : Float // int -> float + var experience : Int // let -> var + var level : Int // let -> var let nature : Nature let species : Species - let moves : [Move: Int] // Move -> remaining powerpoints + var moves : [Move: Int] // Move -> remaining powerpoints + // moves: let -> var let individual_values : Stats - let effort_values : Stats + var effort_values : Stats // let -> var + var effective_stats : Stats // TODO: implement the effective stats as a computed property: // https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html#//apple_ref/doc/uid/TP40014097-CH14-ID259 - // var effective_stats : Stats { - // } } +let kangaskhan = Pokemon( + nickname: "KANGS", + size: 2.2, + weight: 80, + level: 100, // DA VERY BESS + experience: 1000000, // kangaskhan is a med-fast leveler, MFXP = lvl^3 + nature: Nature.rash, + species: species_kangaskhan, + moves: [move_reversal: 15, + move_earthquake: 10, + move_iceBeam: 10, + move_suckerPunch: 5], + /* + // TODO: set arbitrary (but reasonable) IV and EV, compute stats + // or maybe minmax like a huge tryhard idk + // http://bulbapedia.bulbagarden.net/wiki/Individual_values + individual_values: Stats( + hitpoints: 105, + attack: 95, + defense: 80, + special_attack: 40, + special_defense: 80, + speed: 90 + ) + // http://bulbapedia.bulbagarden.net/wiki/Effort_values + effort_values: Stats( + hitpoints: 105, + attack: 95, + defense: 80, + special_attack: 40, + special_defense: 80, + speed: 90 + ) + // http://bulbapedia.bulbagarden.net/wiki/Individual_values#Determination_of_stats_2 + effective_stats: Stats( + hitpoints: 105, + attack: 95, + defense: 80, + special_attack: 40, + special_defense: 80, + speed: 90 + ) + */ + +) + +// TODO: nature stat modifiers +// http://bulbapedia.bulbagarden.net/wiki/Nature + struct Trainer { let pokemons : [Pokemon] } struct Environment { - let weather : Weather + var weather : Weather // let -> var let terrain : Terrain } @@ -171,4 +312,4 @@ struct State { func battle(trainers: inout [Trainer], behavior: (State, Trainer) -> Move) -> () { // TODO: simulate battle } -//test \ No newline at end of file +//test From 24523a57f291d62c287294e6e86b2fae5e82ce8f Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Thu, 23 Feb 2017 23:19:18 +0100 Subject: [PATCH 04/27] a few minor changes; also testing wercker --- Sources/swift_exercises.swift | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/Sources/swift_exercises.swift b/Sources/swift_exercises.swift index 750e8d0..2d19b5b 100644 --- a/Sources/swift_exercises.swift +++ b/Sources/swift_exercises.swift @@ -83,7 +83,7 @@ struct Move : Hashable { let description : String let category : Category let type : Type - var power : Int // let -> var + var power : Int let accuracy : Int let powerpoints : Int let priority : Int @@ -127,7 +127,7 @@ let species_kangaskhan = Species( id: 155, name: "Kangaskhan", evolutions: [], - attacks: ["reversal", "earthquake", "ice beam", "sucker punch"], //and a load of others + attacks: [179, 89, 58, 389], // move id type: .normal, base_values: Stats( hitpoints: 105, @@ -142,7 +142,7 @@ let species_kangaskhan = Species( /* four moves: reversal, earthquake, ice beam, and sucker punch. -This is actually a decent offensive moveset, geared towards consistent (100% +This is actually a decent offensive moveset, geared towards consistent (100% starting accuracy) high damage while tanking (kangaskhan has high non-water HP, IVs willing), rather than endurance (only 40 cumulative PPs, 25 if not counting reversal) or status, and types are chosen so that there's always at least one @@ -174,7 +174,7 @@ let move_reversal = Move( description: "Stronger if the user's HP is low.", category: .physical, type: .fighting, - power: 0, // variable base power, calculated when move is used + power: 0, //can actually calculate power at this stage already accuracy: 100, powerpoints: 15, priority: 0 @@ -219,17 +219,16 @@ let move_suckerPunch = Move( struct Pokemon { let nickname : String? - var hitpoints : Int // remaining hitpoints; let -> var - let size : Float // int -> float - let weight : Float // int -> float - var experience : Int // let -> var - var level : Int // let -> var + var hitpoints : Int // remaining hitpoints + let size : Float + let weight : Float + var experience : Int + var level : Int let nature : Nature let species : Species var moves : [Move: Int] // Move -> remaining powerpoints - // moves: let -> var let individual_values : Stats - var effort_values : Stats // let -> var + var effort_values : Stats var effective_stats : Stats // TODO: implement the effective stats as a computed property: // https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html#//apple_ref/doc/uid/TP40014097-CH14-ID259 @@ -241,12 +240,12 @@ let kangaskhan = Pokemon( weight: 80, level: 100, // DA VERY BESS experience: 1000000, // kangaskhan is a med-fast leveler, MFXP = lvl^3 - nature: Nature.rash, + nature: .rash, species: species_kangaskhan, moves: [move_reversal: 15, move_earthquake: 10, move_iceBeam: 10, - move_suckerPunch: 5], + move_suckerPunch: 5] /* // TODO: set arbitrary (but reasonable) IV and EV, compute stats // or maybe minmax like a huge tryhard idk @@ -289,7 +288,7 @@ struct Trainer { } struct Environment { - var weather : Weather // let -> var + var weather : Weather let terrain : Terrain } @@ -312,4 +311,3 @@ struct State { func battle(trainers: inout [Trainer], behavior: (State, Trainer) -> Move) -> () { // TODO: simulate battle } -//test From 19bb8c64eaa99cc968e90bc87d0041350b465e1e Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Thu, 23 Feb 2017 23:22:19 +0100 Subject: [PATCH 05/27] changed move id to actual names --- Sources/swift_exercises.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/swift_exercises.swift b/Sources/swift_exercises.swift index 2d19b5b..0ecd117 100644 --- a/Sources/swift_exercises.swift +++ b/Sources/swift_exercises.swift @@ -127,7 +127,7 @@ let species_kangaskhan = Species( id: 155, name: "Kangaskhan", evolutions: [], - attacks: [179, 89, 58, 389], // move id + attacks: [move_reversal, move_earthquake, move_iceBeam, move_suckerPunch], type: .normal, base_values: Stats( hitpoints: 105, From 36c62d1df1ede3dd60f9ceae63ad372f03474fde Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Fri, 24 Feb 2017 03:52:23 +0100 Subject: [PATCH 06/27] added function to calculate damage dealt by reversal, changed IV/EV and computed effective stats, and started working on damage function, started fixing a few bugs --- Sources/swift_exercises.swift | 107 +++++++++++++++++++++++----------- 1 file changed, 72 insertions(+), 35 deletions(-) diff --git a/Sources/swift_exercises.swift b/Sources/swift_exercises.swift index 0ecd117..ce4362d 100644 --- a/Sources/swift_exercises.swift +++ b/Sources/swift_exercises.swift @@ -1,3 +1,5 @@ +import Foundation // floor, random, etc + // http://bulbapedia.bulbagarden.net/wiki/Type enum Type { case bug @@ -123,7 +125,7 @@ func ==(lhs: Species, rhs: Species) -> Bool { // create kangaskhan species -let species_kangaskhan = Species( +let Species_kangaskhan = Species( id: 155, name: "Kangaskhan", evolutions: [], @@ -148,7 +150,7 @@ willing), rather than endurance (only 40 cumulative PPs, 25 if not counting reversal) or status, and types are chosen so that there's always at least one 2x move (except against fight and ghost types, both of which are 1x). There aren't really any STAB moves worth using in this optic (except maybe -frustration/return, but friendship isn't implemented. +frustration/return, but friendship isn't implemented) Possible but ultimately inconsistent candidates for powerful STAB would be: dizzy punch: 1.5x70 with 20% chance of confusion; decent candidate, but ultimately worse than appropriately choosing type-specific moves. yeah, signature move and all @@ -168,13 +170,27 @@ Comparatively high HP will allow for an efficient use of reversal should the situation get dire, but it shouldn't be relied on earlier on. */ +func computeReversalPower(currentHitpoints: Int, maxHitpoints: Int) -> Int +{ + // returns damage dealt by the 'reversal' move + // see http://bulbapedia.bulbagarden.net/wiki/Reversal_(move) + HPratio = Double(currentHitpoints) / Double(maxHitpoints) + + if (0.0417 > HPRatio) {return 200} + else if (0.1042 > HPRatio) {return 150} + else if (0.2083 > HPRatio) {return 100} + else if (0.3542 > HPRatio) {return 80} + else if (0.6875 > HPRatio) {return 40} + else {return 20} +} + let move_reversal = Move( id: 179, name: "Reversal", description: "Stronger if the user's HP is low.", category: .physical, type: .fighting, - power: 0, //can actually calculate power at this stage already + power: computeReversalPower(currentHitpoints: kangaskhan.hitpoints, maxHitpoints: kangaskhan.effective_stats.hitpoints), // ? accuracy: 100, powerpoints: 15, priority: 0 @@ -227,11 +243,10 @@ struct Pokemon { let nature : Nature let species : Species var moves : [Move: Int] // Move -> remaining powerpoints + let base_values : Stats let individual_values : Stats var effort_values : Stats var effective_stats : Stats - // TODO: implement the effective stats as a computed property: - // https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html#//apple_ref/doc/uid/TP40014097-CH14-ID259 } let kangaskhan = Pokemon( @@ -239,50 +254,48 @@ let kangaskhan = Pokemon( size: 2.2, weight: 80, level: 100, // DA VERY BESS - experience: 1000000, // kangaskhan is a med-fast leveler, MFXP = lvl^3 + experience: 1000000, // kangaskhan is a medium-fast leveler, MFXP = lvl^3 nature: .rash, species: species_kangaskhan, moves: [move_reversal: 15, move_earthquake: 10, move_iceBeam: 10, - move_suckerPunch: 5] - /* - // TODO: set arbitrary (but reasonable) IV and EV, compute stats - // or maybe minmax like a huge tryhard idk - // http://bulbapedia.bulbagarden.net/wiki/Individual_values + move_suckerPunch: 5], + base_values: species_kangaskhan.base_values, + //IVs and EVs tryharded to hell and back because why not individual_values: Stats( - hitpoints: 105, - attack: 95, - defense: 80, - special_attack: 40, - special_defense: 80, - speed: 90 - ) - // http://bulbapedia.bulbagarden.net/wiki/Effort_values + hitpoints: 31, + attack: 31, + defense: 31, + special_attack: 31, + special_defense: 31, + speed: 31 + ), effort_values: Stats( - hitpoints: 105, - attack: 95, - defense: 80, - special_attack: 40, - special_defense: 80, - speed: 90 - ) + hitpoints: 200, + attack: 200, + defense: 30, + special_attack: 20, + special_defense: 30, + speed: 30 + ), // http://bulbapedia.bulbagarden.net/wiki/Individual_values#Determination_of_stats_2 - effective_stats: Stats( - hitpoints: 105, - attack: 95, - defense: 80, - special_attack: 40, - special_defense: 80, - speed: 90 + // https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html#//apple_ref/doc/uid/TP40014097-CH14-ID259 + effective_stats: Stats( // 'pokemons'? + hitpoints : 10 + level + floor( ( Double( 2 * species.base_values.hitpoints + individual_values.hitpoints + floor(Double(effort_values.hitpoints / 4 ) ) * level ) ) / 100 ), + attack : floor( ( Double( (2 * base_values.attack + individual_values.attack + floor(Double(effort_values.attack) / 4) ) * level) ) / 100 ) * natureMultiplier[nature], + defense : floor( ( Double( (2 * base_values.defense + individual_values.defense + floor(Double(effort_values.defense) / 4) ) * level) ) / 100 ) * natureMultiplier[nature], + special_attack : floor( ( Double( (2 * base_values.special_attack + individual_values.special_attack + floor(Double(effort_values.special_attack) / 4) ) * level) ) / 100 ) * natureMultiplier[nature], + special_defense : floor( ( Double( (2 * base_values.special_defense + individual_values.special_defense + floor(Double(effort_values.special_defense) / 4) ) * level) ) / 100 ) * natureMultiplier[nature], + speed : floor( ( Double( (2 * base_values.speed + individual_values.speed + floor(Double(effort_values.speed) / 4) ) * level) ) / 100 ) * natureMultiplier[nature] ) - */ ) // TODO: nature stat modifiers // http://bulbapedia.bulbagarden.net/wiki/Nature + struct Trainer { let pokemons : [Pokemon] } @@ -300,7 +313,31 @@ func typeModifier(attacking: Type, defending : Type) -> Double { // http://bulbapedia.bulbagarden.net/wiki/Damage func damage(environment : Environment, pokemon: Pokemon, move: Move, target: Pokemon) -> Int { - // TODO + + var STAB : Double = 1 // initialise with non-STAB multiplier value + if (pokemon.species.type == move.type) {var STAB = 1.5} + + // var typeBonus: Double = + + // see http://bulbapedia.bulbagarden.net/wiki/Critical_hit#Probability + var critical: Double = 1 //initialise with non-crit mult value + var randNum: Int = Int(drand48() * 257) // random int between 0 and 256 (included) + var threshold: Int = Int(round(kangaskhan.base_values.speed / 2)) + if ( randNum < threshold) {var critical = ( (2 * kangaskhan.level + 5) / (kangaskhan.level + 5) ) } + + //environmentBonus + + // drand48() returns a random double between 0 and 1 + // but randFactor should be uniformly distributed between 0.85 and 1 + var randFactor: Double = ((drand48() * 0.15) + 0.85) + + // assuming no items or abilities + var modifier : Double = STAB * typeBonus * critical * environmentBonus * randFactor + + // TODO calculate actual damage + // TODO status changes + // TODO recoil damage + return 0 } From 690254a1da621f7f8e15a8cf6a7235a94828c3fd Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Fri, 24 Feb 2017 20:23:55 +0100 Subject: [PATCH 07/27] fixed a bunch of stuff, now it should compile. commented out stat calculation, to be fixed later --- Sources/swift_exercises.swift | 58 ++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/Sources/swift_exercises.swift b/Sources/swift_exercises.swift index ce4362d..6d9c8a1 100644 --- a/Sources/swift_exercises.swift +++ b/Sources/swift_exercises.swift @@ -125,12 +125,12 @@ func ==(lhs: Species, rhs: Species) -> Bool { // create kangaskhan species -let Species_kangaskhan = Species( +let species_kangaskhan: Species = Species( id: 155, name: "Kangaskhan", evolutions: [], attacks: [move_reversal, move_earthquake, move_iceBeam, move_suckerPunch], - type: .normal, + type: (Type.normal, nil), base_values: Stats( hitpoints: 105, attack: 95, @@ -174,7 +174,7 @@ func computeReversalPower(currentHitpoints: Int, maxHitpoints: Int) -> Int { // returns damage dealt by the 'reversal' move // see http://bulbapedia.bulbagarden.net/wiki/Reversal_(move) - HPratio = Double(currentHitpoints) / Double(maxHitpoints) + let HPRatio: Double = Double(currentHitpoints) / Double(maxHitpoints) if (0.0417 > HPRatio) {return 200} else if (0.1042 > HPRatio) {return 150} @@ -184,7 +184,7 @@ func computeReversalPower(currentHitpoints: Int, maxHitpoints: Int) -> Int else {return 20} } -let move_reversal = Move( +let move_reversal: Move = Move( id: 179, name: "Reversal", description: "Stronger if the user's HP is low.", @@ -196,7 +196,7 @@ let move_reversal = Move( priority: 0 ) -let move_earthquake = Move( +let move_earthquake: Move = Move( id: 89, name: "Earthquake", description: "Tough but useless vs. flying foes.", @@ -208,7 +208,7 @@ let move_earthquake = Move( priority: 0 ) -let move_iceBeam = Move( +let move_iceBeam: Move = Move( id: 58, name: "Ice Beam", description: "An attack that may freeze the foe.", @@ -220,7 +220,7 @@ let move_iceBeam = Move( priority: 0 ) -let move_suckerPunch = Move( +let move_suckerPunch: Move = Move( id: 389, name: "Sucker Punch", description: "This move enables the user to attack first. It fails if the foe is not readying an attack, however.", @@ -240,6 +240,7 @@ struct Pokemon { let weight : Float var experience : Int var level : Int + let type : (Type, Type?) let nature : Nature let species : Species var moves : [Move: Int] // Move -> remaining powerpoints @@ -251,10 +252,12 @@ struct Pokemon { let kangaskhan = Pokemon( nickname: "KANGS", + hitpoints: 0, // ? size: 2.2, weight: 80, - level: 100, // DA VERY BESS experience: 1000000, // kangaskhan is a medium-fast leveler, MFXP = lvl^3 + level: 100, // DA VERY BESS + type : (Type.normal, nil), nature: .rash, species: species_kangaskhan, moves: [move_reversal: 15, @@ -279,16 +282,23 @@ let kangaskhan = Pokemon( special_defense: 30, speed: 30 ), + effective_stats: Stats(hitpoints: 0, // temporary, remove this and fix calculations + attack: 0, + defense: 0, + special_attack: 0, + special_defense: 0, + speed: 0) + /* , // http://bulbapedia.bulbagarden.net/wiki/Individual_values#Determination_of_stats_2 // https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html#//apple_ref/doc/uid/TP40014097-CH14-ID259 effective_stats: Stats( // 'pokemons'? - hitpoints : 10 + level + floor( ( Double( 2 * species.base_values.hitpoints + individual_values.hitpoints + floor(Double(effort_values.hitpoints / 4 ) ) * level ) ) / 100 ), - attack : floor( ( Double( (2 * base_values.attack + individual_values.attack + floor(Double(effort_values.attack) / 4) ) * level) ) / 100 ) * natureMultiplier[nature], - defense : floor( ( Double( (2 * base_values.defense + individual_values.defense + floor(Double(effort_values.defense) / 4) ) * level) ) / 100 ) * natureMultiplier[nature], - special_attack : floor( ( Double( (2 * base_values.special_attack + individual_values.special_attack + floor(Double(effort_values.special_attack) / 4) ) * level) ) / 100 ) * natureMultiplier[nature], - special_defense : floor( ( Double( (2 * base_values.special_defense + individual_values.special_defense + floor(Double(effort_values.special_defense) / 4) ) * level) ) / 100 ) * natureMultiplier[nature], - speed : floor( ( Double( (2 * base_values.speed + individual_values.speed + floor(Double(effort_values.speed) / 4) ) * level) ) / 100 ) * natureMultiplier[nature] - ) + hitpoints: Int = 10 + kangaskhan.level + floor( ( Double( 2 * kangaskhan_species.base_values.hitpoints + kangaskhan.individual_values.hitpoints + floor(Double(kangaskhan.effort_values.hitpoints / 4 ) ) * kangaskhan.level ) ) / 100 ), + attack: Int = floor( ( Double( (2 * base_values.attack + individual_values.attack + floor(Double(effort_values.attack) / 4) ) * level) ) / 100 ) * natureMultiplier[kangaskhan.nature], + defense: Int = floor( ( Double( (2 * base_values.defense + individual_values.defense + floor(Double(effort_values.defense) / 4) ) * level) ) / 100 ) * natureMultiplier[kangaskhan.nature], + special_attack: Int = floor( ( Double( (2 * base_values.special_attack + individual_values.special_attack + floor(Double(effort_values.special_attack) / 4) ) * level) ) / 100 ) * natureMultiplier[nature], + special_defense: Int = floor( ( Double( (2 * base_values.special_defense + individual_values.special_defense + floor(Double(effort_values.special_defense) / 4) ) * level) ) / 100 ) * natureMultiplier[nature], + speed: Int = floor( ( Double( (2 * base_values.speed + individual_values.speed + floor(Double(effort_values.speed) / 4) ) * level) ) / 100 ) * natureMultiplier[nature] + )*/ ) @@ -315,24 +325,24 @@ func typeModifier(attacking: Type, defending : Type) -> Double { func damage(environment : Environment, pokemon: Pokemon, move: Move, target: Pokemon) -> Int { var STAB : Double = 1 // initialise with non-STAB multiplier value - if (pokemon.species.type == move.type) {var STAB = 1.5} + if (kangaskhan.type.0 == move.type) {var STAB = 1.5} + else if (kangaskhan.type.1 == move.type) {var STAB = 1.5} - // var typeBonus: Double = + let typeBonus: Double = 1 // actually calculate this - // see http://bulbapedia.bulbagarden.net/wiki/Critical_hit#Probability - var critical: Double = 1 //initialise with non-crit mult value - var randNum: Int = Int(drand48() * 257) // random int between 0 and 256 (included) - var threshold: Int = Int(round(kangaskhan.base_values.speed / 2)) + var critical: Double = 1 // initialise with non-crit mult value + let randNum: Int = Int(drand48() * 257) // random int between 0 and 256 (included) + let threshold: Int = Int(round(Double(kangaskhan.base_values.speed / 2))) if ( randNum < threshold) {var critical = ( (2 * kangaskhan.level + 5) / (kangaskhan.level + 5) ) } - //environmentBonus + let environmentBonus: Double = 1 // actually calculate this // drand48() returns a random double between 0 and 1 // but randFactor should be uniformly distributed between 0.85 and 1 - var randFactor: Double = ((drand48() * 0.15) + 0.85) + let randFactor: Double = ((drand48() * 0.15) + 0.85) // assuming no items or abilities - var modifier : Double = STAB * typeBonus * critical * environmentBonus * randFactor + let modifier : Double = STAB * typeBonus * critical * environmentBonus * randFactor // TODO calculate actual damage // TODO status changes From f5e71207b2a15f4cdbde35c92ae56196da71f3a6 Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Fri, 24 Feb 2017 20:56:53 +0100 Subject: [PATCH 08/27] fixed pokemon/species types, a few small changes, expanded a bit on what should be done in battle(...) --- Sources/swift_exercises.swift | 45 +++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/Sources/swift_exercises.swift b/Sources/swift_exercises.swift index 6d9c8a1..e6a40f6 100644 --- a/Sources/swift_exercises.swift +++ b/Sources/swift_exercises.swift @@ -130,7 +130,7 @@ let species_kangaskhan: Species = Species( name: "Kangaskhan", evolutions: [], attacks: [move_reversal, move_earthquake, move_iceBeam, move_suckerPunch], - type: (Type.normal, nil), + type: (.normal, nil), base_values: Stats( hitpoints: 105, attack: 95, @@ -234,19 +234,19 @@ let move_suckerPunch: Move = Move( struct Pokemon { - let nickname : String? - var hitpoints : Int // remaining hitpoints - let size : Float - let weight : Float - var experience : Int - var level : Int + let nickname : String? + var hitpoints : Int // remaining hitpoints + let size : Float + let weight : Float + var experience : Int + var level : Int let type : (Type, Type?) - let nature : Nature - let species : Species - var moves : [Move: Int] // Move -> remaining powerpoints + let nature : Nature + let species : Species + var moves : [Move: Int] // Move -> remaining powerpoints let base_values : Stats - let individual_values : Stats - var effort_values : Stats + let individual_values : Stats + var effort_values : Stats var effective_stats : Stats } @@ -257,7 +257,7 @@ let kangaskhan = Pokemon( weight: 80, experience: 1000000, // kangaskhan is a medium-fast leveler, MFXP = lvl^3 level: 100, // DA VERY BESS - type : (Type.normal, nil), + type : species_kangaskhan.type, nature: .rash, species: species_kangaskhan, moves: [move_reversal: 15, @@ -325,15 +325,16 @@ func typeModifier(attacking: Type, defending : Type) -> Double { func damage(environment : Environment, pokemon: Pokemon, move: Move, target: Pokemon) -> Int { var STAB : Double = 1 // initialise with non-STAB multiplier value - if (kangaskhan.type.0 == move.type) {var STAB = 1.5} - else if (kangaskhan.type.1 == move.type) {var STAB = 1.5} + if (kangaskhan.type.0 == move.type) {STAB = 1.5} + else if (kangaskhan.type.1 == move.type) {STAB = 1.5} let typeBonus: Double = 1 // actually calculate this var critical: Double = 1 // initialise with non-crit mult value let randNum: Int = Int(drand48() * 257) // random int between 0 and 256 (included) let threshold: Int = Int(round(Double(kangaskhan.base_values.speed / 2))) - if ( randNum < threshold) {var critical = ( (2 * kangaskhan.level + 5) / (kangaskhan.level + 5) ) } + if ( randNum < threshold) + {critical = ( Double(2 * kangaskhan.level + 5) / Double(kangaskhan.level + 5) ) } let environmentBonus: Double = 1 // actually calculate this @@ -345,8 +346,6 @@ func damage(environment : Environment, pokemon: Pokemon, move: Move, target: Pok let modifier : Double = STAB * typeBonus * critical * environmentBonus * randFactor // TODO calculate actual damage - // TODO status changes - // TODO recoil damage return 0 } @@ -357,4 +356,14 @@ struct State { func battle(trainers: inout [Trainer], behavior: (State, Trainer) -> Move) -> () { // TODO: simulate battle + + + /////////////////////// + + // TODO check if enough PP left, error if not + // TODO calculate actual damage ('damage' function) + // TODO status changes? + // TODO recoil damage? + // TODO inflict damage to foe/self if appropriate + // TODO change pokemon status and environment if appropriate } From 49f33945398612f776bed2c0d39465f942a02c20 Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Fri, 24 Feb 2017 22:15:25 +0100 Subject: [PATCH 09/27] a few minor changes, removed huge useless comment blurb, added current_stats --- Sources/swift_exercises.swift | 57 +++++++++++++---------------------- 1 file changed, 21 insertions(+), 36 deletions(-) diff --git a/Sources/swift_exercises.swift b/Sources/swift_exercises.swift index e6a40f6..dd10767 100644 --- a/Sources/swift_exercises.swift +++ b/Sources/swift_exercises.swift @@ -141,34 +141,7 @@ let species_kangaskhan: Species = Species( ) ) - -/* four moves: reversal, earthquake, ice beam, and sucker punch. - -This is actually a decent offensive moveset, geared towards consistent (100% starting -accuracy) high damage while tanking (kangaskhan has high non-water HP, IVs -willing), rather than endurance (only 40 cumulative PPs, 25 if not counting -reversal) or status, and types are chosen so that there's always at least one -2x move (except against fight and ghost types, both of which are 1x). There -aren't really any STAB moves worth using in this optic (except maybe -frustration/return, but friendship isn't implemented) - -Possible but ultimately inconsistent candidates for powerful STAB would be: - dizzy punch: 1.5x70 with 20% chance of confusion; decent candidate, but ultimately worse than appropriately choosing type-specific moves. yeah, signature move and all - hyper beam: 1.5x150 is very good alpha, but the recovery round and the 90% accuracy screws it up; also, kangaskhan's spatk is relatively low - frustration/return: actually viable with extremely low/high friendship, but that mechanic isn't implemented and probably won't be, given the nature of this assignment - facade: boosted damage (1.5x2x70) seems good, but burn status halves physical damage, paralysis reduces effective damage per round by 25% and completely wrecks speed. If you're dangerously low on health reversal should be more than enough to finish them off (unless you're up against a ghost, in which case yeah tough shit). - giga impact: 1.5x150 is very good alpha, but the recovery round and the 90% accuracy screws it up - double edge: 1.5x120 is good alpha, but 1/3 recoil is just silly - uproar: 1.5x90 is alright, but it uses spatk and multi-turn moves are silly - -Also, keep in mind kangaskhan is normal-type and normal-type attacks are 1x -against everything (except rock and steel (0.5x), and ghost (0x)), normal-type -STAB isn't worth it over a potential 2x type bonus gained through the use of a -move chosen appropriately with regard to type. - -Comparatively high HP will allow for an efficient use of reversal should the -situation get dire, but it shouldn't be relied on earlier on. -*/ +// fancy movesets are irrelevant, pick some other moves that aren't just plain damage func computeReversalPower(currentHitpoints: Int, maxHitpoints: Int) -> Int { @@ -236,6 +209,7 @@ let move_suckerPunch: Move = Move( struct Pokemon { let nickname : String? var hitpoints : Int // remaining hitpoints + // eventually remove this, and get HP from current_stats let size : Float let weight : Float var experience : Int @@ -248,11 +222,12 @@ struct Pokemon { let individual_values : Stats var effort_values : Stats var effective_stats : Stats + var current_stats : Stats } let kangaskhan = Pokemon( nickname: "KANGS", - hitpoints: 0, // ? + hitpoints: 0, // eventually remove this, and get HP from current_stats size: 2.2, weight: 80, experience: 1000000, // kangaskhan is a medium-fast leveler, MFXP = lvl^3 @@ -282,12 +257,20 @@ let kangaskhan = Pokemon( special_defense: 30, speed: 30 ), - effective_stats: Stats(hitpoints: 0, // temporary, remove this and fix calculations - attack: 0, - defense: 0, - special_attack: 0, - special_defense: 0, - speed: 0) + effective_stats: Stats( // temporary, remove these and fix calculations + hitpoints: 0, + attack: 0, + defense: 0, + special_attack: 0, + special_defense: 0, + speed: 0), + current_stats: Stats( // temporary, remove these and fix calculations + hitpoints: 0, + attack: 0, + defense: 0, + special_attack: 0, + special_defense: 0, + speed: 0) /* , // http://bulbapedia.bulbagarden.net/wiki/Individual_values#Determination_of_stats_2 // https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html#//apple_ref/doc/uid/TP40014097-CH14-ID259 @@ -298,7 +281,9 @@ let kangaskhan = Pokemon( special_attack: Int = floor( ( Double( (2 * base_values.special_attack + individual_values.special_attack + floor(Double(effort_values.special_attack) / 4) ) * level) ) / 100 ) * natureMultiplier[nature], special_defense: Int = floor( ( Double( (2 * base_values.special_defense + individual_values.special_defense + floor(Double(effort_values.special_defense) / 4) ) * level) ) / 100 ) * natureMultiplier[nature], speed: Int = floor( ( Double( (2 * base_values.speed + individual_values.speed + floor(Double(effort_values.speed) / 4) ) * level) ) / 100 ) * natureMultiplier[nature] - )*/ + ), + // current_stats + */ ) From d7c424b9d251a8c6d0eec9d2f13d098324e1ec8e Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Sat, 25 Feb 2017 01:10:41 +0100 Subject: [PATCH 10/27] lots of detail o nthe working of the battle cycle, added init() header, two small fixes --- Sources/swift_exercises.swift | 66 +++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 10 deletions(-) diff --git a/Sources/swift_exercises.swift b/Sources/swift_exercises.swift index dd10767..148c920 100644 --- a/Sources/swift_exercises.swift +++ b/Sources/swift_exercises.swift @@ -274,7 +274,7 @@ let kangaskhan = Pokemon( /* , // http://bulbapedia.bulbagarden.net/wiki/Individual_values#Determination_of_stats_2 // https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html#//apple_ref/doc/uid/TP40014097-CH14-ID259 - effective_stats: Stats( // 'pokemons'? + effective_stats: Stats( hitpoints: Int = 10 + kangaskhan.level + floor( ( Double( 2 * kangaskhan_species.base_values.hitpoints + kangaskhan.individual_values.hitpoints + floor(Double(kangaskhan.effort_values.hitpoints / 4 ) ) * kangaskhan.level ) ) / 100 ), attack: Int = floor( ( Double( (2 * base_values.attack + individual_values.attack + floor(Double(effort_values.attack) / 4) ) * level) ) / 100 ) * natureMultiplier[kangaskhan.nature], defense: Int = floor( ( Double( (2 * base_values.defense + individual_values.defense + floor(Double(effort_values.defense) / 4) ) * level) ) / 100 ) * natureMultiplier[kangaskhan.nature], @@ -292,7 +292,7 @@ let kangaskhan = Pokemon( struct Trainer { - let pokemons : [Pokemon] + let party : [Pokemon] } struct Environment { @@ -339,16 +339,62 @@ struct State { // TODO: describe a battle state } + func battle(trainers: inout [Trainer], behavior: (State, Trainer) -> Move) -> () { - // TODO: simulate battle + // assume you can either fight or switch pokemon, but nothing more + // struggle????? + // no fancy effects and such, at least for now + + // TODO: + // introductory blah blah + // trainers send out the first respective pokemon + // while both trainers have at least 1 non-KO pokemon: + // display environment if relevant + // trainers pick a move, or switch pokemon + // pokemon: check it's valid and non-KO, priority 6 + // move: check that it's a valid move, and that it has PP left + // check priority and speed to see who goes first + // first to move + // check status conditions, see if move can be executed (can always switch pokemon) + // move changes weather? + // y: set new weather + // move changes pokemon stats? + // y, first: set new first stats (self) + // y, second: set new second stats + // move deals damage? + // calculate damage + // deal damage to second + // second (foe) KO? + // y: opponent tries sending out another pokemon + // n: move has status effects on second? + //y: apply status effects + // deal recoil damage to first (self) if appropriate + // self KO? + // y: first tries sending out another pokemon + // second KO? n: + // check status conditions, see if move can be executed (can always switch pokemon) + // move changes weather? + // y: set new weather + // move changes pokemon stats? + // y, second: set new first stats (self) + // y, first: set new second stats + // move deals damage? + // calculate damage + // deal damage to first + // first (foe) KO? + // y: opponent tries sending out another pokemon + // n: move has status effects on first? + //y: apply status effects + // deal recoil damage to second (self) if appropriate + // self KO? + // y: second tries sending out another pokemon + // nonzero status conditions on either pokemon: apply effects + +} - /////////////////////// - // TODO check if enough PP left, error if not - // TODO calculate actual damage ('damage' function) - // TODO status changes? - // TODO recoil damage? - // TODO inflict damage to foe/self if appropriate - // TODO change pokemon status and environment if appropriate +func init() -> Int { + // call other stuff here + return 0 } From 941756911541c1b0d727c2cc505aa1cf803d7799 Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Sat, 25 Feb 2017 17:05:44 +0100 Subject: [PATCH 11/27] type damage multiplier, also some small changes --- Sources/swift_exercises.swift | 75 ++++++++++++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 6 deletions(-) diff --git a/Sources/swift_exercises.swift b/Sources/swift_exercises.swift index 148c920..de789eb 100644 --- a/Sources/swift_exercises.swift +++ b/Sources/swift_exercises.swift @@ -287,8 +287,10 @@ let kangaskhan = Pokemon( ) -// TODO: nature stat modifiers // http://bulbapedia.bulbagarden.net/wiki/Nature +// let natureMultiplier: [Nature: Stats]( +// +//) struct Trainer { @@ -300,18 +302,79 @@ struct Environment { let terrain : Terrain } +func typeToInt(type: Type) -> Int { + //uses standard ordering + switch type { + case .normal: return 0 + case .fighting: return 1 + case .flying: return 2 + case .poison: return 3 + case .ground: return 4 + case .rock: return 5 + case .bug: return 6 + case .ghost: return 7 + case .steel: return 8 + case .fire: return 9 + case .water: return 10 + case .grass: return 11 + case .electric: return 12 + case .psychic: return 13 + case .ice: return 14 + case .dragon: return 15 + case .dark: return 16 + case .fairy: return 17 + case nil: return -1 // ????? + default: return -2 // + } +} + // http://bulbapedia.bulbagarden.net/wiki/Type/Type_chart -func typeModifier(attacking: Type, defending : Type) -> Double { +func typeModifier(attacking: Type, defending : (Type, Type?))-> Double { // TODO: encode type/type chart - return 1 + + let attackingID: Int = typeToInt(type: attacking) + let defendingID0: Int = typeToInt(type: defending.0) + let defendingID1: Int = typeToInt(type: defending.1!) + + let multiplierMatrix: [[Double]] = [ + [ 1, 1, 1, 1, 1,0.5, 1, 0,0.5, 1, 1, 1, 1, 1, 1, 1, 1, 1], // normal + [ 2, 1,0.5,0.5, 1, 2,0.5, 0, 2, 1, 1, 1, 1,0.5, 2, 1, 2,0.5], // fighting + [ 1, 2, 1, 1, 1,0.5, 2, 1,0.5, 1, 1, 2,0.5, 1, 1, 1, 1, 1], // flying + [ 1, 1, 1,0.5,0.5,0.5, 1,0.5, 0, 1, 1, 2, 1, 1, 1, 1, 1, 2], // poison + [ 1, 1, 0, 2, 1, 2,0.5, 1, 2, 2, 1,0.5, 2, 1, 1, 1, 1, 1], // ground + [ 1,0.5, 2, 1,0.5, 1, 2, 1,0.5, 2, 1, 1, 1, 1, 2, 1, 1, 1], // rock + [ 1,0.5,0.5,0.5, 1, 1, 1,0.5,0.5,0.5, 1, 2, 1, 2, 1, 1, 2,0.5], // bug + [ 0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1,0.5, 1], // ghost + [ 1, 1, 1, 1, 1, 2, 1, 1,0.5,0.5,0.5, 1,0.5, 1, 2, 1, 1, 2], // steel + [ 1, 1, 1, 1, 1,0.5, 2, 1, 2,0.5,0.5, 2, 1, 1, 2,0.5, 1, 1], // fire + [ 1, 1, 1, 1, 2, 2, 1, 1, 1, 2,0.5,0.5, 1, 1, 1,0.5, 1, 1], // water + [ 1, 1,0.5,0.5, 2, 2,0.5, 1,0.5,0.5, 2,0.5, 1, 1, 1,0.5, 1, 1], // grass + [ 1, 1, 2, 1, 0, 1, 1, 1, 1, 1, 2,0.5,0.5, 1, 1,0.5, 1, 1], // electric + [ 1, 2, 1, 2, 1, 1, 1, 1,0.5, 1, 1, 1, 1,0.5, 1, 1, 0, 1], // psychic + [ 1, 1, 2, 1, 2, 1, 1, 1,0.5,0.5,0.5, 2, 1, 1,0.5, 2, 1, 1], // ice + [ 1, 1, 1, 1, 1, 1, 1, 1,0.5, 1, 1, 1, 1, 1, 1, 2, 1, 0], // dragon + [ 1,0.5, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1,0.5,0.5], // dark + [ 1, 2, 1,0.5, 1, 1, 1, 1,0.5,0.5, 1, 1, 1, 1, 1, 2, 2, 1], // fairy + ] + + if (defendingID1 != -1) + {return ( Double(multiplierMatrix[attackingID][defendingID0]) + * Double(multiplierMatrix[attackingID][defendingID1]) )} + else + {return (multiplierMatrix[attackingID][defendingID0])} + + /* + /src/swift-exercises/Sources/swift_exercises.swift:326:3: warning: case will never be executed + case nil: return -1 // ????? + ^ + */ } // http://bulbapedia.bulbagarden.net/wiki/Damage func damage(environment : Environment, pokemon: Pokemon, move: Move, target: Pokemon) -> Int { var STAB : Double = 1 // initialise with non-STAB multiplier value - if (kangaskhan.type.0 == move.type) {STAB = 1.5} - else if (kangaskhan.type.1 == move.type) {STAB = 1.5} + if ( (kangaskhan.type.0 == move.type) || (kangaskhan.type.1 == move.type) ) {STAB = 1.5} let typeBonus: Double = 1 // actually calculate this @@ -394,7 +457,7 @@ func battle(trainers: inout [Trainer], behavior: (State, Trainer) -> Move) -> () } -func init() -> Int { +func initialise() -> Int { // call other stuff here return 0 } From 40a6ef79fc13ac4d6740e6346d0668037f55272d Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Sat, 25 Feb 2017 17:25:41 +0100 Subject: [PATCH 12/27] changed test to match change in source --- Tests/swift-exercisesTests/swift_exercisesTests.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/swift-exercisesTests/swift_exercisesTests.swift b/Tests/swift-exercisesTests/swift_exercisesTests.swift index eab452c..1e7900e 100644 --- a/Tests/swift-exercisesTests/swift_exercisesTests.swift +++ b/Tests/swift-exercisesTests/swift_exercisesTests.swift @@ -2,9 +2,9 @@ import XCTest @testable import swift_exercises class swift_exercisesTests: XCTestCase { - + func test_typeModifier() { - XCTAssertEqual(typeModifier(attacking: Type.normal, defending: Type.normal), 1, "normal/normal should be 1") + XCTAssertEqual(typeModifier(attacking: Type.normal, defending: (Type.normal, nil)), 1, "normal/normal should be 1") } static var allTests : [(String, (swift_exercisesTests) -> () throws -> Void)] { From b5a4566efc82a64ac66f23e8d6f4773c67822b32 Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Sat, 25 Feb 2017 17:55:26 +0100 Subject: [PATCH 13/27] small changes to source and test --- Sources/swift_exercises.swift | 20 +++++++++++++------ .../swift_exercisesTests.swift | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/Sources/swift_exercises.swift b/Sources/swift_exercises.swift index de789eb..de335a2 100644 --- a/Sources/swift_exercises.swift +++ b/Sources/swift_exercises.swift @@ -326,6 +326,13 @@ func typeToInt(type: Type) -> Int { case nil: return -1 // ????? default: return -2 // } + + /* + /src/swift-exercises/Sources/swift_exercises.swift:326:3: warning: case will never be executed + case nil: return -1 // ????? + ^ + */ + } // http://bulbapedia.bulbagarden.net/wiki/Type/Type_chart @@ -334,7 +341,10 @@ func typeModifier(attacking: Type, defending : (Type, Type?))-> Double { let attackingID: Int = typeToInt(type: attacking) let defendingID0: Int = typeToInt(type: defending.0) - let defendingID1: Int = typeToInt(type: defending.1!) + if (defending.1 != nil){ + let defendingID1: Int = typeToInt(type: defending.1!) } + else {let defendingID1: Int = -1} + //let defendingID1: Int = -1 // temporary let multiplierMatrix: [[Double]] = [ [ 1, 1, 1, 1, 1,0.5, 1, 0,0.5, 1, 1, 1, 1, 1, 1, 1, 1, 1], // normal @@ -363,11 +373,7 @@ func typeModifier(attacking: Type, defending : (Type, Type?))-> Double { else {return (multiplierMatrix[attackingID][defendingID0])} - /* - /src/swift-exercises/Sources/swift_exercises.swift:326:3: warning: case will never be executed - case nil: return -1 // ????? - ^ - */ + } // http://bulbapedia.bulbagarden.net/wiki/Damage @@ -395,6 +401,8 @@ func damage(environment : Environment, pokemon: Pokemon, move: Move, target: Pok // TODO calculate actual damage + + return 0 } diff --git a/Tests/swift-exercisesTests/swift_exercisesTests.swift b/Tests/swift-exercisesTests/swift_exercisesTests.swift index 1e7900e..461c343 100644 --- a/Tests/swift-exercisesTests/swift_exercisesTests.swift +++ b/Tests/swift-exercisesTests/swift_exercisesTests.swift @@ -4,7 +4,7 @@ import XCTest class swift_exercisesTests: XCTestCase { func test_typeModifier() { - XCTAssertEqual(typeModifier(attacking: Type.normal, defending: (Type.normal, nil)), 1, "normal/normal should be 1") + XCTAssertEqual(typeModifier(attacking: Type.fighting, defending: (Type.rock, Type.ice), 1, "fighting -> rock/ice should be 4") } static var allTests : [(String, (swift_exercisesTests) -> () throws -> Void)] { From 82ee162ee2f2f7bea76f36453b78dff6b62d8eb2 Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Sat, 25 Feb 2017 18:16:31 +0100 Subject: [PATCH 14/27] small changes, trying to get the type damage modifier thing to work --- Sources/swift_exercises.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Sources/swift_exercises.swift b/Sources/swift_exercises.swift index de335a2..199d4ea 100644 --- a/Sources/swift_exercises.swift +++ b/Sources/swift_exercises.swift @@ -341,10 +341,14 @@ func typeModifier(attacking: Type, defending : (Type, Type?))-> Double { let attackingID: Int = typeToInt(type: attacking) let defendingID0: Int = typeToInt(type: defending.0) + let defendingID1: Int = typeToInt(type: defending.1!) + // let defendingID1: Int = -1 // temporary if (defending.1 != nil){ let defendingID1: Int = typeToInt(type: defending.1!) } else {let defendingID1: Int = -1} - //let defendingID1: Int = -1 // temporary + // initialisation of defendingID1 never used????????? + + let multiplierMatrix: [[Double]] = [ [ 1, 1, 1, 1, 1,0.5, 1, 0,0.5, 1, 1, 1, 1, 1, 1, 1, 1, 1], // normal From 94e4acc0b1f7864bbf85e12813e540e5093b860e Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Sat, 25 Feb 2017 18:19:47 +0100 Subject: [PATCH 15/27] small change to test --- Tests/swift-exercisesTests/swift_exercisesTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/swift-exercisesTests/swift_exercisesTests.swift b/Tests/swift-exercisesTests/swift_exercisesTests.swift index 461c343..eac4cd4 100644 --- a/Tests/swift-exercisesTests/swift_exercisesTests.swift +++ b/Tests/swift-exercisesTests/swift_exercisesTests.swift @@ -4,7 +4,7 @@ import XCTest class swift_exercisesTests: XCTestCase { func test_typeModifier() { - XCTAssertEqual(typeModifier(attacking: Type.fighting, defending: (Type.rock, Type.ice), 1, "fighting -> rock/ice should be 4") + XCTAssertEqual(typeModifier(attacking: Type.fighting, defending: (Type.rock, Type.ice), 1, "fighting -> rock/ice should be 4"), } static var allTests : [(String, (swift_exercisesTests) -> () throws -> Void)] { From edf9d9198290781abc80f86c856055e298b18feb Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Sat, 25 Feb 2017 18:25:03 +0100 Subject: [PATCH 16/27] minor change to test, maybe wercker testing should work now --- Tests/swift-exercisesTests/swift_exercisesTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/swift-exercisesTests/swift_exercisesTests.swift b/Tests/swift-exercisesTests/swift_exercisesTests.swift index eac4cd4..2bea504 100644 --- a/Tests/swift-exercisesTests/swift_exercisesTests.swift +++ b/Tests/swift-exercisesTests/swift_exercisesTests.swift @@ -4,7 +4,7 @@ import XCTest class swift_exercisesTests: XCTestCase { func test_typeModifier() { - XCTAssertEqual(typeModifier(attacking: Type.fighting, defending: (Type.rock, Type.ice), 1, "fighting -> rock/ice should be 4"), + XCTAssertEqual(typeModifier(attacking: Type.fighting, defending: (Type.rock, Type.ice)), 1, "fighting -> rock/ice should be 4") } static var allTests : [(String, (swift_exercisesTests) -> () throws -> Void)] { From 330bbe75759aa587009c9965b5ce7089018edc82 Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Sat, 25 Feb 2017 18:27:08 +0100 Subject: [PATCH 17/27] small fix on previous commit --- Tests/swift-exercisesTests/swift_exercisesTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/swift-exercisesTests/swift_exercisesTests.swift b/Tests/swift-exercisesTests/swift_exercisesTests.swift index 2bea504..7e9ede8 100644 --- a/Tests/swift-exercisesTests/swift_exercisesTests.swift +++ b/Tests/swift-exercisesTests/swift_exercisesTests.swift @@ -4,7 +4,7 @@ import XCTest class swift_exercisesTests: XCTestCase { func test_typeModifier() { - XCTAssertEqual(typeModifier(attacking: Type.fighting, defending: (Type.rock, Type.ice)), 1, "fighting -> rock/ice should be 4") + XCTAssertEqual(typeModifier(attacking: Type.fighting, defending: (Type.rock, Type.ice)), 4, "fighting -> rock/ice should be 4") } static var allTests : [(String, (swift_exercisesTests) -> () throws -> Void)] { From 1ac5e1348d7ee0bf328287830dad77c70bc648e4 Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Mon, 27 Feb 2017 11:36:03 +0100 Subject: [PATCH 18/27] fixed stat computation, changed Stats struct to Double to clean up some clutter (and changed things accordingly), added EV yield (?), changed functions to work in the general case (i.e. 'pokemon' instead of 'kangaskhan' --- Sources/swift_exercises.swift | 127 +++++++++++++----- .../swift_exercisesTests.swift | 1 + 2 files changed, 97 insertions(+), 31 deletions(-) diff --git a/Sources/swift_exercises.swift b/Sources/swift_exercises.swift index 199d4ea..989494c 100644 --- a/Sources/swift_exercises.swift +++ b/Sources/swift_exercises.swift @@ -100,12 +100,12 @@ func ==(lhs: Move, rhs: Move) -> Bool { // http://bulbapedia.bulbagarden.net/wiki/Statistic struct Stats { - let hitpoints : Int - let attack : Int - let defense : Int - let special_attack : Int - let special_defense : Int - let speed : Int + let hitpoints : Double + let attack : Double + let defense : Double + let special_attack : Double + let special_defense : Double + let speed : Double } struct Species : Hashable { @@ -143,11 +143,11 @@ let species_kangaskhan: Species = Species( // fancy movesets are irrelevant, pick some other moves that aren't just plain damage -func computeReversalPower(currentHitpoints: Int, maxHitpoints: Int) -> Int +func computeReversalPower(currentHitpoints: Double, maxHitpoints: Double) -> Int { // returns damage dealt by the 'reversal' move // see http://bulbapedia.bulbagarden.net/wiki/Reversal_(move) - let HPRatio: Double = Double(currentHitpoints) / Double(maxHitpoints) + let HPRatio: Double = currentHitpoints / maxHitpoints if (0.0417 > HPRatio) {return 200} else if (0.1042 > HPRatio) {return 150} @@ -163,7 +163,7 @@ let move_reversal: Move = Move( description: "Stronger if the user's HP is low.", category: .physical, type: .fighting, - power: computeReversalPower(currentHitpoints: kangaskhan.hitpoints, maxHitpoints: kangaskhan.effective_stats.hitpoints), // ? + power: computeReversalPower(currentHitpoints: Double(kangaskhan.hitpoints), maxHitpoints: Double(kangaskhan.effective_stats.hitpoints)), // ? accuracy: 100, powerpoints: 15, priority: 0 @@ -213,7 +213,7 @@ struct Pokemon { let size : Float let weight : Float var experience : Int - var level : Int + var level : Double let type : (Type, Type?) let nature : Nature let species : Species @@ -221,6 +221,7 @@ struct Pokemon { let base_values : Stats let individual_values : Stats var effort_values : Stats + let effort_values_yield: Stats var effective_stats : Stats var current_stats : Stats } @@ -257,6 +258,14 @@ let kangaskhan = Pokemon( special_defense: 30, speed: 30 ), + effort_values_yield: Stats( // are we even supposed to account for EV yield? + hitpoints: 2, + attack: 0, + defense: 0, + special_attack: 0, + special_defense: 0, + speed: 0 + ), effective_stats: Stats( // temporary, remove these and fix calculations hitpoints: 0, attack: 0, @@ -287,6 +296,59 @@ let kangaskhan = Pokemon( ) + + + +func computeStats(pokemon: Pokemon) -> Stats { + //let hitpoints: Int = 10 + kangaskhan.level + floor( ( Double( 2 * species_kangaskhan.base_values.hitpoints + kangaskhan.individual_values.hitpoints + floor(Double(kangaskhan.effort_values.hitpoints / 4 ) ) * kangaskhan.level ) ) / 100 ), + //expressions broken up because they're too long for the compiler + let hitpointsTemp: Double = 2 * pokemon.species.base_values.hitpoints + pokemon.individual_values.hitpoints + let hitpointsTemp2: Double = hitpointsTemp + floor(pokemon.effort_values.hitpoints / 4) + let hitpointsTemp3: Double = floor((hitpointsTemp2 * pokemon.level)/100) + let hitpoints: Double = hitpointsTemp3 + pokemon.level + 10 + + let attackTemp: Double = floor(Double(pokemon.effort_values.attack) / 4) + let attackTemp2: Double = (2 * pokemon.species.base_values.attack + pokemon.individual_values.attack + attackTemp) * pokemon.level + let attackTemp3: Double = floor(attackTemp2 / 100) + let attack: Double = (attackTemp3 + 5) * 1 // natureMultiplier[pokemon] instead of '1', + + let defenseTemp: Double = floor(Double(pokemon.effort_values.defense) / 4) + let defenseTemp2: Double = (2 * pokemon.species.base_values.defense + pokemon.individual_values.defense + defenseTemp) * pokemon.level + let defenseTemp3: Double = floor(defenseTemp2 / 100) + let defense: Double = (defenseTemp3 + 5) * 1 // natureMultiplier[pokemon] instead of '1', + + let special_attackTemp: Double = floor(Double(pokemon.effort_values.special_attack) / 4) + let special_attackTemp2: Double = (2 * pokemon.species.base_values.special_attack + pokemon.individual_values.special_attack + special_attackTemp) * pokemon.level + let special_attackTemp3: Double = floor(special_attackTemp2 / 100) + let special_attack: Double = (special_attackTemp3 + 5) * 1 // natureMultiplier[pokemon] instead of '1', + + let special_defenseTemp: Double = floor(Double(pokemon.effort_values.special_defense) / 4) + let special_defenseTemp2: Double = (2 * pokemon.species.base_values.special_defense + pokemon.individual_values.special_defense + special_defenseTemp) * pokemon.level + let special_defenseTemp3: Double = floor(special_defenseTemp2 / 100) + let special_defense: Double = (special_defenseTemp3 + 5) * 1 // natureMultiplier[pokemon] instead of '1', + + let speedTemp: Double = floor(Double(pokemon.effort_values.speed) / 4) + let speedTemp2: Double = (2 * pokemon.species.base_values.speed + pokemon.individual_values.speed + speedTemp) * pokemon.level + let speedTemp3: Double = floor(speedTemp2 / 100) + let speed: Double = (speedTemp3 + 5) * 1 // natureMultiplier[pokemon] instead of '1', + + return Stats( + hitpoints: hitpoints, + attack: attack, + defense: defense, + special_attack: special_attack, + special_defense: special_defense, + speed: speed) +} + + + + + + + + + // http://bulbapedia.bulbagarden.net/wiki/Nature // let natureMultiplier: [Nature: Stats]( // @@ -384,15 +446,15 @@ func typeModifier(attacking: Type, defending : (Type, Type?))-> Double { func damage(environment : Environment, pokemon: Pokemon, move: Move, target: Pokemon) -> Int { var STAB : Double = 1 // initialise with non-STAB multiplier value - if ( (kangaskhan.type.0 == move.type) || (kangaskhan.type.1 == move.type) ) {STAB = 1.5} + if ( (kangaskhan.type.0 == move.type) || (pokemon.type.1 == move.type) ) {STAB = 1.5} let typeBonus: Double = 1 // actually calculate this var critical: Double = 1 // initialise with non-crit mult value let randNum: Int = Int(drand48() * 257) // random int between 0 and 256 (included) - let threshold: Int = Int(round(Double(kangaskhan.base_values.speed / 2))) + let threshold: Int = Int(round(pokemon.base_values.speed / 2)) if ( randNum < threshold) - {critical = ( Double(2 * kangaskhan.level + 5) / Double(kangaskhan.level + 5) ) } + {critical = ( (2 * pokemon.level + 5) / (pokemon.level + 5) ) } let environmentBonus: Double = 1 // actually calculate this @@ -438,15 +500,16 @@ func battle(trainers: inout [Trainer], behavior: (State, Trainer) -> Move) -> () // y, first: set new first stats (self) // y, second: set new second stats // move deals damage? - // calculate damage - // deal damage to second - // second (foe) KO? - // y: opponent tries sending out another pokemon - // n: move has status effects on second? - //y: apply status effects - // deal recoil damage to first (self) if appropriate - // self KO? - // y: first tries sending out another pokemon + // calculate hit probability + // calculate damage + // deal damage to second + // second (foe) KO? + // y: opponent tries sending out another pokemon + // n: move has status effects on second? // check the order of these + //y: apply status effects + // deal recoil damage to first (self) if appropriate + // self KO? + // y: first tries sending out another pokemon // second KO? n: // check status conditions, see if move can be executed (can always switch pokemon) // move changes weather? @@ -455,16 +518,18 @@ func battle(trainers: inout [Trainer], behavior: (State, Trainer) -> Move) -> () // y, second: set new first stats (self) // y, first: set new second stats // move deals damage? - // calculate damage - // deal damage to first - // first (foe) KO? - // y: opponent tries sending out another pokemon - // n: move has status effects on first? - //y: apply status effects - // deal recoil damage to second (self) if appropriate - // self KO? - // y: second tries sending out another pokemon + // calculate hit probability + // calculate damage + // deal damage to first + // first (foe) KO? + // y: opponent tries sending out another pokemon + // n: move has status effects on first? + //y: apply status effects + // deal recoil damage to second (self) if appropriate + // self KO? + // y: second tries sending out another pokemon // nonzero status conditions on either pokemon: apply effects + // KO? try sending out another pokemon } diff --git a/Tests/swift-exercisesTests/swift_exercisesTests.swift b/Tests/swift-exercisesTests/swift_exercisesTests.swift index 7e9ede8..1055738 100644 --- a/Tests/swift-exercisesTests/swift_exercisesTests.swift +++ b/Tests/swift-exercisesTests/swift_exercisesTests.swift @@ -5,6 +5,7 @@ class swift_exercisesTests: XCTestCase { func test_typeModifier() { XCTAssertEqual(typeModifier(attacking: Type.fighting, defending: (Type.rock, Type.ice)), 4, "fighting -> rock/ice should be 4") + XCTAssertEqual(typeModifier(attacking: Type.normal, defending: (Type.normal, nil)), 1, "normal -> normal should be 1") } static var allTests : [(String, (swift_exercisesTests) -> () throws -> Void)] { From 918510767e8ed2f4dce541da44cd66cc523aeb09 Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Mon, 27 Feb 2017 12:43:31 +0100 Subject: [PATCH 19/27] changed type modifier function, should now work correctly when calculating multiplier against single and double damage type pokemon --- Sources/swift_exercises.swift | 10 +++++----- Tests/swift-exercisesTests/swift_exercisesTests.swift | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Sources/swift_exercises.swift b/Sources/swift_exercises.swift index 989494c..0124bf9 100644 --- a/Sources/swift_exercises.swift +++ b/Sources/swift_exercises.swift @@ -403,15 +403,15 @@ func typeModifier(attacking: Type, defending : (Type, Type?))-> Double { let attackingID: Int = typeToInt(type: attacking) let defendingID0: Int = typeToInt(type: defending.0) - let defendingID1: Int = typeToInt(type: defending.1!) + let defendingID1: Int // let defendingID1: Int = -1 // temporary if (defending.1 != nil){ - let defendingID1: Int = typeToInt(type: defending.1!) } - else {let defendingID1: Int = -1} + defendingID1 = typeToInt(type: defending.1!) } + else { defendingID1 = -1} // initialisation of defendingID1 never used????????? - +// let multiplierMatrix: [[Double]] = [ [ 1, 1, 1, 1, 1,0.5, 1, 0,0.5, 1, 1, 1, 1, 1, 1, 1, 1, 1], // normal [ 2, 1,0.5,0.5, 1, 2,0.5, 0, 2, 1, 1, 1, 1,0.5, 2, 1, 2,0.5], // fighting @@ -430,7 +430,7 @@ func typeModifier(attacking: Type, defending : (Type, Type?))-> Double { [ 1, 1, 2, 1, 2, 1, 1, 1,0.5,0.5,0.5, 2, 1, 1,0.5, 2, 1, 1], // ice [ 1, 1, 1, 1, 1, 1, 1, 1,0.5, 1, 1, 1, 1, 1, 1, 2, 1, 0], // dragon [ 1,0.5, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1,0.5,0.5], // dark - [ 1, 2, 1,0.5, 1, 1, 1, 1,0.5,0.5, 1, 1, 1, 1, 1, 2, 2, 1], // fairy + [ 1, 2, 1,0.5, 1, 1, 1, 1,0.5,0.5, 1, 1, 1, 1, 1, 2, 2, 1] // fairy ] if (defendingID1 != -1) diff --git a/Tests/swift-exercisesTests/swift_exercisesTests.swift b/Tests/swift-exercisesTests/swift_exercisesTests.swift index 1055738..9c5dfa5 100644 --- a/Tests/swift-exercisesTests/swift_exercisesTests.swift +++ b/Tests/swift-exercisesTests/swift_exercisesTests.swift @@ -5,7 +5,7 @@ class swift_exercisesTests: XCTestCase { func test_typeModifier() { XCTAssertEqual(typeModifier(attacking: Type.fighting, defending: (Type.rock, Type.ice)), 4, "fighting -> rock/ice should be 4") - XCTAssertEqual(typeModifier(attacking: Type.normal, defending: (Type.normal, nil)), 1, "normal -> normal should be 1") + XCTAssertEqual(typeModifier(attacking: Type.normal, defending: Type.normal), 1, "normal -> normal should be 1") } static var allTests : [(String, (swift_exercisesTests) -> () throws -> Void)] { From 5e8b38832a6b36cd9a1cb25aca531ed7aee6252a Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Mon, 27 Feb 2017 12:47:27 +0100 Subject: [PATCH 20/27] wercker test --- Tests/swift-exercisesTests/swift_exercisesTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/swift-exercisesTests/swift_exercisesTests.swift b/Tests/swift-exercisesTests/swift_exercisesTests.swift index 9c5dfa5..2a9acc1 100644 --- a/Tests/swift-exercisesTests/swift_exercisesTests.swift +++ b/Tests/swift-exercisesTests/swift_exercisesTests.swift @@ -5,7 +5,7 @@ class swift_exercisesTests: XCTestCase { func test_typeModifier() { XCTAssertEqual(typeModifier(attacking: Type.fighting, defending: (Type.rock, Type.ice)), 4, "fighting -> rock/ice should be 4") - XCTAssertEqual(typeModifier(attacking: Type.normal, defending: Type.normal), 1, "normal -> normal should be 1") + XCTAssertEqual(typeModifier(attacking: Type.normal, defending: (Type.normal, nil?)), 1, "normal -> normal should be 1") } static var allTests : [(String, (swift_exercisesTests) -> () throws -> Void)] { From 79ef4f5e90dc0e3925d14b5ec748182c4b053426 Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Mon, 27 Feb 2017 16:08:18 +0100 Subject: [PATCH 21/27] fixed stat calculation, a few minor changes --- Sources/swift_exercises.swift | 168 +++++++----------- .../swift_exercisesTests.swift | 2 +- 2 files changed, 65 insertions(+), 105 deletions(-) diff --git a/Sources/swift_exercises.swift b/Sources/swift_exercises.swift index 0124bf9..d57a070 100644 --- a/Sources/swift_exercises.swift +++ b/Sources/swift_exercises.swift @@ -100,12 +100,12 @@ func ==(lhs: Move, rhs: Move) -> Bool { // http://bulbapedia.bulbagarden.net/wiki/Statistic struct Stats { - let hitpoints : Double - let attack : Double - let defense : Double - let special_attack : Double - let special_defense : Double - let speed : Double + var hitpoints : Double + var attack : Double + var defense : Double + var special_attack : Double + var special_defense : Double + var speed : Double } struct Species : Hashable { @@ -222,11 +222,60 @@ struct Pokemon { let individual_values : Stats var effort_values : Stats let effort_values_yield: Stats - var effective_stats : Stats - var current_stats : Stats + var effective_stats : Stats { + get { + let stats = computeStats(base_values: base_values, individual_values: individual_values, effort_values: effort_values, level: level) + return stats + } + } +} + + + +func computeStats(base_values: Stats, individual_values: Stats, effort_values: Stats, level: Double) -> Stats { + //expressions broken up because they're too long for the compiler + + let hitpointsTemp: Double = 2 * base_values.hitpoints + individual_values.hitpoints + let hitpointsTemp2: Double = hitpointsTemp + floor(effort_values.hitpoints / 4) + let hitpointsTemp3: Double = floor((hitpointsTemp2 * level)/100) + let hitpoints: Double = hitpointsTemp3 + level + 10 + + let attackTemp: Double = floor(Double(effort_values.attack) / 4) + let attackTemp2: Double = (2 * base_values.attack + individual_values.attack + attackTemp) * level + let attackTemp3: Double = floor(attackTemp2 / 100) + let attack: Double = (attackTemp3 + 5) * 1 // natureMultiplier(attack) instead of '1', + + let defenseTemp: Double = floor(Double(effort_values.defense) / 4) + let defenseTemp2: Double = (2 * base_values.defense + individual_values.defense + defenseTemp) * level + let defenseTemp3: Double = floor(defenseTemp2 / 100) + let defense: Double = (defenseTemp3 + 5) * 1 // natureMultiplier(defense) instead of '1', + + let special_attackTemp: Double = floor(Double(effort_values.special_attack) / 4) + let special_attackTemp2: Double = (2 * base_values.special_attack + individual_values.special_attack + special_attackTemp) * level + let special_attackTemp3: Double = floor(special_attackTemp2 / 100) + let special_attack: Double = (special_attackTemp3 + 5) * 1 // natureMultiplier(special_attack) instead of '1', + + let special_defenseTemp: Double = floor(Double(effort_values.special_defense) / 4) + let special_defenseTemp2: Double = (2 * base_values.special_defense + individual_values.special_defense + special_defenseTemp) * level + let special_defenseTemp3: Double = floor(special_defenseTemp2 / 100) + let special_defense: Double = (special_defenseTemp3 + 5) * 1 // natureMultiplier(special_defense) instead of '1', + + let speedTemp: Double = floor(Double(effort_values.speed) / 4) + let speedTemp2: Double = (2 * base_values.speed + individual_values.speed + speedTemp) * level + let speedTemp3: Double = floor(speedTemp2 / 100) + let speed: Double = (speedTemp3 + 5) * 1 // natureMultiplier(speed) instead of '1', + + return Stats( + hitpoints: hitpoints, + attack: attack, + defense: defense, + special_attack: special_attack, + special_defense: special_defense, + speed: speed) } -let kangaskhan = Pokemon( + +var kangaskhan = Pokemon( nickname: "KANGS", hitpoints: 0, // eventually remove this, and get HP from current_stats size: 2.2, @@ -248,107 +297,24 @@ let kangaskhan = Pokemon( defense: 31, special_attack: 31, special_defense: 31, - speed: 31 - ), + speed: 31), effort_values: Stats( hitpoints: 200, attack: 200, defense: 30, special_attack: 20, special_defense: 30, - speed: 30 - ), + speed: 30), effort_values_yield: Stats( // are we even supposed to account for EV yield? hitpoints: 2, attack: 0, defense: 0, special_attack: 0, special_defense: 0, - speed: 0 - ), - effective_stats: Stats( // temporary, remove these and fix calculations - hitpoints: 0, - attack: 0, - defense: 0, - special_attack: 0, - special_defense: 0, - speed: 0), - current_stats: Stats( // temporary, remove these and fix calculations - hitpoints: 0, - attack: 0, - defense: 0, - special_attack: 0, - special_defense: 0, speed: 0) - /* , - // http://bulbapedia.bulbagarden.net/wiki/Individual_values#Determination_of_stats_2 - // https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html#//apple_ref/doc/uid/TP40014097-CH14-ID259 - effective_stats: Stats( - hitpoints: Int = 10 + kangaskhan.level + floor( ( Double( 2 * kangaskhan_species.base_values.hitpoints + kangaskhan.individual_values.hitpoints + floor(Double(kangaskhan.effort_values.hitpoints / 4 ) ) * kangaskhan.level ) ) / 100 ), - attack: Int = floor( ( Double( (2 * base_values.attack + individual_values.attack + floor(Double(effort_values.attack) / 4) ) * level) ) / 100 ) * natureMultiplier[kangaskhan.nature], - defense: Int = floor( ( Double( (2 * base_values.defense + individual_values.defense + floor(Double(effort_values.defense) / 4) ) * level) ) / 100 ) * natureMultiplier[kangaskhan.nature], - special_attack: Int = floor( ( Double( (2 * base_values.special_attack + individual_values.special_attack + floor(Double(effort_values.special_attack) / 4) ) * level) ) / 100 ) * natureMultiplier[nature], - special_defense: Int = floor( ( Double( (2 * base_values.special_defense + individual_values.special_defense + floor(Double(effort_values.special_defense) / 4) ) * level) ) / 100 ) * natureMultiplier[nature], - speed: Int = floor( ( Double( (2 * base_values.speed + individual_values.speed + floor(Double(effort_values.speed) / 4) ) * level) ) / 100 ) * natureMultiplier[nature] - ), - // current_stats - */ - ) - - -func computeStats(pokemon: Pokemon) -> Stats { - //let hitpoints: Int = 10 + kangaskhan.level + floor( ( Double( 2 * species_kangaskhan.base_values.hitpoints + kangaskhan.individual_values.hitpoints + floor(Double(kangaskhan.effort_values.hitpoints / 4 ) ) * kangaskhan.level ) ) / 100 ), - //expressions broken up because they're too long for the compiler - let hitpointsTemp: Double = 2 * pokemon.species.base_values.hitpoints + pokemon.individual_values.hitpoints - let hitpointsTemp2: Double = hitpointsTemp + floor(pokemon.effort_values.hitpoints / 4) - let hitpointsTemp3: Double = floor((hitpointsTemp2 * pokemon.level)/100) - let hitpoints: Double = hitpointsTemp3 + pokemon.level + 10 - - let attackTemp: Double = floor(Double(pokemon.effort_values.attack) / 4) - let attackTemp2: Double = (2 * pokemon.species.base_values.attack + pokemon.individual_values.attack + attackTemp) * pokemon.level - let attackTemp3: Double = floor(attackTemp2 / 100) - let attack: Double = (attackTemp3 + 5) * 1 // natureMultiplier[pokemon] instead of '1', - - let defenseTemp: Double = floor(Double(pokemon.effort_values.defense) / 4) - let defenseTemp2: Double = (2 * pokemon.species.base_values.defense + pokemon.individual_values.defense + defenseTemp) * pokemon.level - let defenseTemp3: Double = floor(defenseTemp2 / 100) - let defense: Double = (defenseTemp3 + 5) * 1 // natureMultiplier[pokemon] instead of '1', - - let special_attackTemp: Double = floor(Double(pokemon.effort_values.special_attack) / 4) - let special_attackTemp2: Double = (2 * pokemon.species.base_values.special_attack + pokemon.individual_values.special_attack + special_attackTemp) * pokemon.level - let special_attackTemp3: Double = floor(special_attackTemp2 / 100) - let special_attack: Double = (special_attackTemp3 + 5) * 1 // natureMultiplier[pokemon] instead of '1', - - let special_defenseTemp: Double = floor(Double(pokemon.effort_values.special_defense) / 4) - let special_defenseTemp2: Double = (2 * pokemon.species.base_values.special_defense + pokemon.individual_values.special_defense + special_defenseTemp) * pokemon.level - let special_defenseTemp3: Double = floor(special_defenseTemp2 / 100) - let special_defense: Double = (special_defenseTemp3 + 5) * 1 // natureMultiplier[pokemon] instead of '1', - - let speedTemp: Double = floor(Double(pokemon.effort_values.speed) / 4) - let speedTemp2: Double = (2 * pokemon.species.base_values.speed + pokemon.individual_values.speed + speedTemp) * pokemon.level - let speedTemp3: Double = floor(speedTemp2 / 100) - let speed: Double = (speedTemp3 + 5) * 1 // natureMultiplier[pokemon] instead of '1', - - return Stats( - hitpoints: hitpoints, - attack: attack, - defense: defense, - special_attack: special_attack, - special_defense: special_defense, - speed: speed) -} - - - - - - - - - // http://bulbapedia.bulbagarden.net/wiki/Nature // let natureMultiplier: [Nature: Stats]( // @@ -385,8 +351,8 @@ func typeToInt(type: Type) -> Int { case .dragon: return 15 case .dark: return 16 case .fairy: return 17 - case nil: return -1 // ????? - default: return -2 // + // case nil: return -1 // ????? + // default: return -2 // } /* @@ -404,14 +370,10 @@ func typeModifier(attacking: Type, defending : (Type, Type?))-> Double { let attackingID: Int = typeToInt(type: attacking) let defendingID0: Int = typeToInt(type: defending.0) let defendingID1: Int - // let defendingID1: Int = -1 // temporary if (defending.1 != nil){ defendingID1 = typeToInt(type: defending.1!) } else { defendingID1 = -1} - // initialisation of defendingID1 never used????????? - -// let multiplierMatrix: [[Double]] = [ [ 1, 1, 1, 1, 1,0.5, 1, 0,0.5, 1, 1, 1, 1, 1, 1, 1, 1, 1], // normal [ 2, 1,0.5,0.5, 1, 2,0.5, 0, 2, 1, 1, 1, 1,0.5, 2, 1, 2,0.5], // fighting @@ -466,10 +428,8 @@ func damage(environment : Environment, pokemon: Pokemon, move: Move, target: Pok let modifier : Double = STAB * typeBonus * critical * environmentBonus * randFactor // TODO calculate actual damage - - - - return 0 + let damage : Int = Int(modifier) // and other stuff ...... + return damage } struct State { diff --git a/Tests/swift-exercisesTests/swift_exercisesTests.swift b/Tests/swift-exercisesTests/swift_exercisesTests.swift index 2a9acc1..9c5dfa5 100644 --- a/Tests/swift-exercisesTests/swift_exercisesTests.swift +++ b/Tests/swift-exercisesTests/swift_exercisesTests.swift @@ -5,7 +5,7 @@ class swift_exercisesTests: XCTestCase { func test_typeModifier() { XCTAssertEqual(typeModifier(attacking: Type.fighting, defending: (Type.rock, Type.ice)), 4, "fighting -> rock/ice should be 4") - XCTAssertEqual(typeModifier(attacking: Type.normal, defending: (Type.normal, nil?)), 1, "normal -> normal should be 1") + XCTAssertEqual(typeModifier(attacking: Type.normal, defending: Type.normal), 1, "normal -> normal should be 1") } static var allTests : [(String, (swift_exercisesTests) -> () throws -> Void)] { From cc5b63f547caea3d0e265321bcff154902b07037 Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Mon, 27 Feb 2017 17:17:59 +0100 Subject: [PATCH 22/27] fixed type modifier and changed damage function a little, put current_stats back in, added detail to battle cycle, some small fixes --- Sources/swift_exercises.swift | 58 +++++++++---------- .../swift_exercisesTests.swift | 2 +- 2 files changed, 29 insertions(+), 31 deletions(-) diff --git a/Sources/swift_exercises.swift b/Sources/swift_exercises.swift index d57a070..186fa80 100644 --- a/Sources/swift_exercises.swift +++ b/Sources/swift_exercises.swift @@ -126,7 +126,7 @@ func ==(lhs: Species, rhs: Species) -> Bool { // create kangaskhan species let species_kangaskhan: Species = Species( - id: 155, + id: 115, name: "Kangaskhan", evolutions: [], attacks: [move_reversal, move_earthquake, move_iceBeam, move_suckerPunch], @@ -163,7 +163,7 @@ let move_reversal: Move = Move( description: "Stronger if the user's HP is low.", category: .physical, type: .fighting, - power: computeReversalPower(currentHitpoints: Double(kangaskhan.hitpoints), maxHitpoints: Double(kangaskhan.effective_stats.hitpoints)), // ? + power: computeReversalPower(currentHitpoints: Double(kangaskhan.current_stats.hitpoints), maxHitpoints: Double(kangaskhan.effective_stats.hitpoints)), // ? accuracy: 100, powerpoints: 15, priority: 0 @@ -208,11 +208,9 @@ let move_suckerPunch: Move = Move( struct Pokemon { let nickname : String? - var hitpoints : Int // remaining hitpoints - // eventually remove this, and get HP from current_stats let size : Float let weight : Float - var experience : Int + var experience : Int // fix xp/lvl so it's actually calculated var level : Double let type : (Type, Type?) let nature : Nature @@ -228,6 +226,7 @@ struct Pokemon { return stats } } + var current_stats : Stats } @@ -277,7 +276,6 @@ func computeStats(base_values: Stats, individual_values: Stats, effort_values: S var kangaskhan = Pokemon( nickname: "KANGS", - hitpoints: 0, // eventually remove this, and get HP from current_stats size: 2.2, weight: 80, experience: 1000000, // kangaskhan is a medium-fast leveler, MFXP = lvl^3 @@ -306,6 +304,13 @@ var kangaskhan = Pokemon( special_defense: 30, speed: 30), effort_values_yield: Stats( // are we even supposed to account for EV yield? + hitpoints: 2, + attack: 0, + defense: 0, + special_attack: 0, + special_defense: 0, + speed: 0), + current_stats: Stats( hitpoints: 2, attack: 0, defense: 0, @@ -354,25 +359,14 @@ func typeToInt(type: Type) -> Int { // case nil: return -1 // ????? // default: return -2 // } - - /* - /src/swift-exercises/Sources/swift_exercises.swift:326:3: warning: case will never be executed - case nil: return -1 // ????? - ^ - */ - } // http://bulbapedia.bulbagarden.net/wiki/Type/Type_chart -func typeModifier(attacking: Type, defending : (Type, Type?))-> Double { +func typeModifier(attacking: Type, defending : Type)-> Double { // TODO: encode type/type chart let attackingID: Int = typeToInt(type: attacking) - let defendingID0: Int = typeToInt(type: defending.0) - let defendingID1: Int - if (defending.1 != nil){ - defendingID1 = typeToInt(type: defending.1!) } - else { defendingID1 = -1} + let defendingID: Int = typeToInt(type: defending) let multiplierMatrix: [[Double]] = [ [ 1, 1, 1, 1, 1,0.5, 1, 0,0.5, 1, 1, 1, 1, 1, 1, 1, 1, 1], // normal @@ -395,22 +389,20 @@ func typeModifier(attacking: Type, defending : (Type, Type?))-> Double { [ 1, 2, 1,0.5, 1, 1, 1, 1,0.5,0.5, 1, 1, 1, 1, 1, 2, 2, 1] // fairy ] - if (defendingID1 != -1) - {return ( Double(multiplierMatrix[attackingID][defendingID0]) - * Double(multiplierMatrix[attackingID][defendingID1]) )} - else - {return (multiplierMatrix[attackingID][defendingID0])} + return (multiplierMatrix[attackingID][defendingID]) } // http://bulbapedia.bulbagarden.net/wiki/Damage -func damage(environment : Environment, pokemon: Pokemon, move: Move, target: Pokemon) -> Int { +func damage(environment : Environment, pokemon: Pokemon, move: Move, target: Pokemon) -> Double { var STAB : Double = 1 // initialise with non-STAB multiplier value if ( (kangaskhan.type.0 == move.type) || (pokemon.type.1 == move.type) ) {STAB = 1.5} - let typeBonus: Double = 1 // actually calculate this + var typeBonus: Double = typeModifier(attacking: move.type, defending: target.type.0) + if (pokemon.type.1 != nil) + {typeBonus = typeBonus * typeModifier(attacking: move.type, defending: target.type.1!)} var critical: Double = 1 // initialise with non-crit mult value let randNum: Int = Int(drand48() * 257) // random int between 0 and 256 (included) @@ -428,7 +420,7 @@ func damage(environment : Environment, pokemon: Pokemon, move: Move, target: Pok let modifier : Double = STAB * typeBonus * critical * environmentBonus * randFactor // TODO calculate actual damage - let damage : Int = Int(modifier) // and other stuff ...... + let damage : Double = Double(modifier) // and other stuff ...... return damage } @@ -447,11 +439,17 @@ func battle(trainers: inout [Trainer], behavior: (State, Trainer) -> Move) -> () // introductory blah blah // trainers send out the first respective pokemon // while both trainers have at least 1 non-KO pokemon: - // display environment if relevant - // trainers pick a move, or switch pokemon + // display environment info if relevant + // trainers pick a move, or switch pokemon, or use an object // pokemon: check it's valid and non-KO, priority 6 + // obj: check it's valid, priority 6 // move: check that it's a valid move, and that it has PP left - // check priority and speed to see who goes first + // csame priority? + // y: + // both are non-damaging: random order + // one is damaging: non-damaging first + // both are damaging: speed determines order + // n: higher priority first // first to move // check status conditions, see if move can be executed (can always switch pokemon) // move changes weather? diff --git a/Tests/swift-exercisesTests/swift_exercisesTests.swift b/Tests/swift-exercisesTests/swift_exercisesTests.swift index 9c5dfa5..d7b9d0f 100644 --- a/Tests/swift-exercisesTests/swift_exercisesTests.swift +++ b/Tests/swift-exercisesTests/swift_exercisesTests.swift @@ -4,7 +4,7 @@ import XCTest class swift_exercisesTests: XCTestCase { func test_typeModifier() { - XCTAssertEqual(typeModifier(attacking: Type.fighting, defending: (Type.rock, Type.ice)), 4, "fighting -> rock/ice should be 4") + XCTAssertEqual(typeModifier(attacking: Type.fighting, defending: Type.ice), 2, "fighting -> ice should be 2") XCTAssertEqual(typeModifier(attacking: Type.normal, defending: Type.normal), 1, "normal -> normal should be 1") } From 153ef6836d70629a7b349b86b9188da83bc273b5 Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Tue, 7 Mar 2017 11:44:38 +0100 Subject: [PATCH 23/27] started writing out battle function, added item struct, two trainers, another kangaskhan (maybe change this to some other pokemon), finished (sorta, still a bit missing) damage function. a load of small changes all over --- Sources/swift_exercises.swift | 174 +++++++++++++++++++++++++--------- 1 file changed, 130 insertions(+), 44 deletions(-) diff --git a/Sources/swift_exercises.swift b/Sources/swift_exercises.swift index 186fa80..fd4c86b 100644 --- a/Sources/swift_exercises.swift +++ b/Sources/swift_exercises.swift @@ -1,6 +1,5 @@ import Foundation // floor, random, etc -// http://bulbapedia.bulbagarden.net/wiki/Type enum Type { case bug case dark @@ -22,14 +21,12 @@ enum Type { case water } -// http://bulbapedia.bulbagarden.net/wiki/Damage_category enum Category { case physical case special case status } -// http://bulbapedia.bulbagarden.net/wiki/Nature enum Nature { case hardy case lonely @@ -94,6 +91,7 @@ struct Move : Hashable { return self.id } } + func ==(lhs: Move, rhs: Move) -> Bool { return lhs.id == rhs.id } @@ -119,11 +117,11 @@ struct Species : Hashable { return self.id } } + func ==(lhs: Species, rhs: Species) -> Bool { return lhs.id == rhs.id } - // create kangaskhan species let species_kangaskhan: Species = Species( id: 115, @@ -141,10 +139,7 @@ let species_kangaskhan: Species = Species( ) ) -// fancy movesets are irrelevant, pick some other moves that aren't just plain damage - -func computeReversalPower(currentHitpoints: Double, maxHitpoints: Double) -> Int -{ +func computeReversalPower(currentHitpoints: Double, maxHitpoints: Double) -> Int { // returns damage dealt by the 'reversal' move // see http://bulbapedia.bulbagarden.net/wiki/Reversal_(move) let HPRatio: Double = currentHitpoints / maxHitpoints @@ -205,7 +200,6 @@ let move_suckerPunch: Move = Move( priority: 1 ) - struct Pokemon { let nickname : String? let size : Float @@ -229,8 +223,6 @@ struct Pokemon { var current_stats : Stats } - - func computeStats(base_values: Stats, individual_values: Stats, effort_values: Stats, level: Double) -> Stats { //expressions broken up because they're too long for the compiler @@ -273,7 +265,6 @@ func computeStats(base_values: Stats, individual_values: Stats, effort_values: S speed: speed) } - var kangaskhan = Pokemon( nickname: "KANGS", size: 2.2, @@ -281,14 +272,13 @@ var kangaskhan = Pokemon( experience: 1000000, // kangaskhan is a medium-fast leveler, MFXP = lvl^3 level: 100, // DA VERY BESS type : species_kangaskhan.type, - nature: .rash, + nature: .hardy, species: species_kangaskhan, moves: [move_reversal: 15, move_earthquake: 10, move_iceBeam: 10, move_suckerPunch: 5], base_values: species_kangaskhan.base_values, - //IVs and EVs tryharded to hell and back because why not individual_values: Stats( hitpoints: 31, attack: 31, @@ -319,17 +309,78 @@ var kangaskhan = Pokemon( speed: 0) ) +var kangaskhan2 = Pokemon( + nickname: "KANGS2", + size: 2.2, + weight: 80, + experience: 1000000, // kangaskhan is a medium-fast leveler, MFXP = lvl^3 + level: 100, // DA VERY BESS + type : species_kangaskhan.type, + nature: .hardy, + species: species_kangaskhan, + moves: [move_reversal: 15, + move_earthquake: 10, + move_iceBeam: 10, + move_suckerPunch: 5], + base_values: species_kangaskhan.base_values, + individual_values: Stats( + hitpoints: 31, + attack: 31, + defense: 31, + special_attack: 31, + special_defense: 31, + speed: 31), + effort_values: Stats( + hitpoints: 200, + attack: 200, + defense: 30, + special_attack: 20, + special_defense: 30, + speed: 30), + effort_values_yield: Stats( // are we even supposed to account for EV yield? + hitpoints: 2, + attack: 0, + defense: 0, + special_attack: 0, + special_defense: 0, + speed: 0), + current_stats: Stats( + hitpoints: 2, + attack: 0, + defense: 0, + special_attack: 0, + special_defense: 0, + speed: 0) +) -// http://bulbapedia.bulbagarden.net/wiki/Nature -// let natureMultiplier: [Nature: Stats]( -// -//) - +struct Item { + let id: Int + let name: String + let description: String + var amount: Int + let price: Int +} struct Trainer { - let party : [Pokemon] + let name: String + var party : [Pokemon] + var bag: [Item] } +let trainerA: Trainer = Trainer( + name: "Trainer A", + party: [kangaskhan], + bag: [] +) + +let trainerB : Trainer = Trainer( // maybe add some other pokemon + name: "Trainer B", + party: [kangaskhan2], + bag: [] +) + +let trainers: [Trainer] = [trainerA, trainerB] + struct Environment { var weather : Weather let terrain : Terrain @@ -356,15 +407,11 @@ func typeToInt(type: Type) -> Int { case .dragon: return 15 case .dark: return 16 case .fairy: return 17 - // case nil: return -1 // ????? - // default: return -2 // + default: return -1 // } } -// http://bulbapedia.bulbagarden.net/wiki/Type/Type_chart func typeModifier(attacking: Type, defending : Type)-> Double { - // TODO: encode type/type chart - let attackingID: Int = typeToInt(type: attacking) let defendingID: Int = typeToInt(type: defending) @@ -390,9 +437,15 @@ func typeModifier(attacking: Type, defending : Type)-> Double { ] return (multiplierMatrix[attackingID][defendingID]) +} + +// http://bulbapedia.bulbagarden.net/wiki/Nature +// let natureMultiplier: [Nature: Stats]( +// +//) + -} // http://bulbapedia.bulbagarden.net/wiki/Damage func damage(environment : Environment, pokemon: Pokemon, move: Move, target: Pokemon) -> Double { @@ -412,15 +465,18 @@ func damage(environment : Environment, pokemon: Pokemon, move: Move, target: Pok let environmentBonus: Double = 1 // actually calculate this - // drand48() returns a random double between 0 and 1 - // but randFactor should be uniformly distributed between 0.85 and 1 - let randFactor: Double = ((drand48() * 0.15) + 0.85) + let randFactor: Double = ((drand48() * 0.15) + 0.85) // uniformly distributed between 0.85 and 1 - // assuming no items or abilities let modifier : Double = STAB * typeBonus * critical * environmentBonus * randFactor - // TODO calculate actual damage - let damage : Double = Double(modifier) // and other stuff ...... + let tempDamage: Double = (2 * pokemon.level + 10) / 250 + + let attDef: Double + if (move.category == .physical) { attDef = pokemon.effective_stats.attack / target.effective_stats.defense } + else if (move.category == .special) { attDef = pokemon.effective_stats.special_attack / target.effective_stats.special_defense } + else { attDef = 0 } + + let damage : Double = (tempDamage * attDef * Double(move.power) * 2) * modifier return damage } @@ -428,25 +484,55 @@ struct State { // TODO: describe a battle state } - func battle(trainers: inout [Trainer], behavior: (State, Trainer) -> Move) -> () { - // assume you can either fight or switch pokemon, but nothing more - // struggle????? - // no fancy effects and such, at least for now - // TODO: - // introductory blah blah - // trainers send out the first respective pokemon - // while both trainers have at least 1 non-KO pokemon: - // display environment info if relevant + print("intro blah blah goes here") + + var partyA: [Pokemon]? = trainers[0].party // player + var partyB: [Pokemon]? = trainers[1].party // pc + var KOPartyA: [Pokemon]? = [] + var KOPartyB: [Pokemon]? = [] + + print("trainer a sent out", partyA![0], "trainer B sent out", partyB![0]) + + while (partyA != nil && partyB != nil) { + + // get environment info + // print if non-default + + + print("what to do? [F]ight, [B]ag, [P]okemon") //pick player move + var playerMove = readLine() + + if ( playerMove == ("F") || playerMove == ("f") || playerMove == ("Fight") || playerMove == ("fight") ) { + // print list of index (1-4), move names, descriptions, power and accuracy + print() + var playerMove = readLine() + + + } + else if ( playerMove == ("B") || playerMove == ("b") || playerMove == ("Bag") || playerMove == ("bag") ) { + // print contents of bag with an index + // tell player to choose the index of the item + + } + else if ( playerMove == ("P") || playerMove == ("p") || playerMove == ("Pokemon") || playerMove == ("pokemon") ) { + // print pokemon, their level, HP, and status condition + //check that pokemon isn't Ko before sending it out + } + else { + //... + } + + // trainers pick a move, or switch pokemon, or use an object // pokemon: check it's valid and non-KO, priority 6 // obj: check it's valid, priority 6 // move: check that it's a valid move, and that it has PP left - // csame priority? + // same priority? // y: - // both are non-damaging: random order + // both are non-damaging: random order (or determined by speed??) // one is damaging: non-damaging first // both are damaging: speed determines order // n: higher priority first @@ -488,7 +574,7 @@ func battle(trainers: inout [Trainer], behavior: (State, Trainer) -> Move) -> () // y: second tries sending out another pokemon // nonzero status conditions on either pokemon: apply effects // KO? try sending out another pokemon - + } } From 85a572bcec4cfcc3e6c37f2b0ea18a6222a29d57 Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Sat, 11 Mar 2017 20:05:01 +0100 Subject: [PATCH 24/27] added stat/weather effect stubs to move struct, separated moves and remaining PPs in pokemon struct, some work on battle function --- Sources/swift_exercises.swift | 58 ++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/Sources/swift_exercises.swift b/Sources/swift_exercises.swift index fd4c86b..89db4de 100644 --- a/Sources/swift_exercises.swift +++ b/Sources/swift_exercises.swift @@ -75,14 +75,16 @@ enum Terrain { case misty } -// http://bulbapedia.bulbagarden.net/wiki/Move struct Move : Hashable { let id : Int let name : String let description : String let category : Category let type : Type - var power : Int + let power : Int + // let selfStatChange: Stats + // let foeStatChange: Stats + // let weatherChange: ? let accuracy : Int let powerpoints : Int let priority : Int @@ -209,7 +211,8 @@ struct Pokemon { let type : (Type, Type?) let nature : Nature let species : Species - var moves : [Move: Int] // Move -> remaining powerpoints + var moves : [Move] // Move + var movePowerPoint : [Int] // remaining powerpoints let base_values : Stats let individual_values : Stats var effort_values : Stats @@ -274,10 +277,8 @@ var kangaskhan = Pokemon( type : species_kangaskhan.type, nature: .hardy, species: species_kangaskhan, - moves: [move_reversal: 15, - move_earthquake: 10, - move_iceBeam: 10, - move_suckerPunch: 5], + moves: [move_reversal, move_earthquake, move_iceBeam, move_suckerPunch], + movePowerPoint: [15,10,10,5], base_values: species_kangaskhan.base_values, individual_values: Stats( hitpoints: 31, @@ -318,10 +319,8 @@ var kangaskhan2 = Pokemon( type : species_kangaskhan.type, nature: .hardy, species: species_kangaskhan, - moves: [move_reversal: 15, - move_earthquake: 10, - move_iceBeam: 10, - move_suckerPunch: 5], + moves: [move_reversal, move_earthquake, move_iceBeam, move_suckerPunch], + movePowerPoint: [15,10,10,5], base_values: species_kangaskhan.base_values, individual_values: Stats( hitpoints: 31, @@ -407,7 +406,7 @@ func typeToInt(type: Type) -> Int { case .dragon: return 15 case .dark: return 16 case .fairy: return 17 - default: return -1 // + //default: return -1 //never executed } } @@ -484,6 +483,8 @@ struct State { // TODO: describe a battle state } + + func battle(trainers: inout [Trainer], behavior: (State, Trainer) -> Move) -> () { // TODO: @@ -491,8 +492,8 @@ func battle(trainers: inout [Trainer], behavior: (State, Trainer) -> Move) -> () var partyA: [Pokemon]? = trainers[0].party // player var partyB: [Pokemon]? = trainers[1].party // pc - var KOPartyA: [Pokemon]? = [] - var KOPartyB: [Pokemon]? = [] + + // check nicknames, if they exist use them instead of standard names print("trainer a sent out", partyA![0], "trainer B sent out", partyB![0]) @@ -501,30 +502,45 @@ func battle(trainers: inout [Trainer], behavior: (State, Trainer) -> Move) -> () // get environment info // print if non-default - + /* print("what to do? [F]ight, [B]ag, [P]okemon") //pick player move var playerMove = readLine() - if ( playerMove == ("F") || playerMove == ("f") || playerMove == ("Fight") || playerMove == ("fight") ) { - // print list of index (1-4), move names, descriptions, power and accuracy - print() - var playerMove = readLine() + if ( playerMove == "F" || playerMove == "f" || playerMove == "Fight" || playerMove == "fight" ) { + // if sum of PP = 0 + // struggle + // else + // print index (1-4), move names, descriptions, power, accuracy, PP + // ask for user input + // check move has PP left + // damage + effects } - else if ( playerMove == ("B") || playerMove == ("b") || playerMove == ("Bag") || playerMove == ("bag") ) { + else if ( playerMove == "B" || playerMove == "b" || playerMove == "Bag" || playerMove == "bag" ) { // print contents of bag with an index // tell player to choose the index of the item } - else if ( playerMove == ("P") || playerMove == ("p") || playerMove == ("Pokemon") || playerMove == ("pokemon") ) { + else if ( playerMove == "P" || playerMove == "p" || playerMove == "Pokemon" || playerMove == "pokemon" ) { // print pokemon, their level, HP, and status condition + // ask for user input, pick a pokemon //check that pokemon isn't Ko before sending it out } else { //... } + */ + + // the "move" is just randomly chosen between the known moves, eventually expand this to allow for user input and to change pokemon and use items + var moveAIndex: Int = Int(drand48()*5) // does this round or truncate? also assumes a pokemon knows four moves + var moveBIndex: Int = Int(drand48()*5) + var moveA: Move = partyA![0].moves[moveAIndex] + var moveB: Move = partyB![0].moves[moveBIndex] + let firstToMove, secondToMove: Trainer + if (moveA.priority > moveB.priority) + { } // trainers pick a move, or switch pokemon, or use an object // pokemon: check it's valid and non-KO, priority 6 From 0a6881371b9fda45bc1c719d3ed4e641136cb8e6 Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Sun, 12 Mar 2017 17:47:37 +0100 Subject: [PATCH 25/27] worked on battle functions, some other changes to smooth out type compatibility. also small screwup with versions but whatever --- Sources/main.swift | 6 + ..._exercises.swift => swift-exercises.swift} | 160 +++++++++++++----- 2 files changed, 119 insertions(+), 47 deletions(-) create mode 100644 Sources/main.swift rename Sources/{swift_exercises.swift => swift-exercises.swift} (78%) diff --git a/Sources/main.swift b/Sources/main.swift new file mode 100644 index 0000000..0c55878 --- /dev/null +++ b/Sources/main.swift @@ -0,0 +1,6 @@ +import Foundation // floor, random, etc + + +print("test") + +battle(trainers: &trainers) diff --git a/Sources/swift_exercises.swift b/Sources/swift-exercises.swift similarity index 78% rename from Sources/swift_exercises.swift rename to Sources/swift-exercises.swift index 89db4de..59c7eb7 100644 --- a/Sources/swift_exercises.swift +++ b/Sources/swift-exercises.swift @@ -160,6 +160,7 @@ let move_reversal: Move = Move( description: "Stronger if the user's HP is low.", category: .physical, type: .fighting, + // fix this so it actually uses the pokemon's hitpoints, whether it is this specific kangaskhan or not power: computeReversalPower(currentHitpoints: Double(kangaskhan.current_stats.hitpoints), maxHitpoints: Double(kangaskhan.effective_stats.hitpoints)), // ? accuracy: 100, powerpoints: 15, @@ -203,6 +204,7 @@ let move_suckerPunch: Move = Move( ) struct Pokemon { + let name : String let nickname : String? let size : Float let weight : Float @@ -213,6 +215,11 @@ struct Pokemon { let species : Species var moves : [Move] // Move var movePowerPoint : [Int] // remaining powerpoints + var statusCondition : [Int] // only major ones + // [burn, freeze, paralysis, (bad)poison, sleep, confusion] + // 0 if not affected, 1 if affected + // poison is 1, bad poison is 2 + // for sleep and confusion, the Int is the number of turns that have passed while the condition was active let base_values : Stats let individual_values : Stats var effort_values : Stats @@ -269,6 +276,7 @@ func computeStats(base_values: Stats, individual_values: Stats, effort_values: S } var kangaskhan = Pokemon( + name: "Kangaskhan", nickname: "KANGS", size: 2.2, weight: 80, @@ -279,6 +287,7 @@ var kangaskhan = Pokemon( species: species_kangaskhan, moves: [move_reversal, move_earthquake, move_iceBeam, move_suckerPunch], movePowerPoint: [15,10,10,5], + statusCondition: [0, 0, 0, 0, 0, 0], base_values: species_kangaskhan.base_values, individual_values: Stats( hitpoints: 31, @@ -302,7 +311,7 @@ var kangaskhan = Pokemon( special_defense: 0, speed: 0), current_stats: Stats( - hitpoints: 2, + hitpoints: 0, attack: 0, defense: 0, special_attack: 0, @@ -311,6 +320,7 @@ var kangaskhan = Pokemon( ) var kangaskhan2 = Pokemon( + name: "Kangaskhan", nickname: "KANGS2", size: 2.2, weight: 80, @@ -321,6 +331,7 @@ var kangaskhan2 = Pokemon( species: species_kangaskhan, moves: [move_reversal, move_earthquake, move_iceBeam, move_suckerPunch], movePowerPoint: [15,10,10,5], + statusCondition: [0, 0, 0, 0, 0, 0], base_values: species_kangaskhan.base_values, individual_values: Stats( hitpoints: 31, @@ -344,7 +355,7 @@ var kangaskhan2 = Pokemon( special_defense: 0, speed: 0), current_stats: Stats( - hitpoints: 2, + hitpoints: 0, attack: 0, defense: 0, special_attack: 0, @@ -366,6 +377,10 @@ struct Trainer { var bag: [Item] } +func ==(lhs: Trainer, rhs: Trainer) -> Bool { + return lhs.name == rhs.name +} + let trainerA: Trainer = Trainer( name: "Trainer A", party: [kangaskhan], @@ -378,7 +393,7 @@ let trainerB : Trainer = Trainer( // maybe add some other pokemon bag: [] ) -let trainers: [Trainer] = [trainerA, trainerB] +var trainers: [Trainer] = [trainerA, trainerB] struct Environment { var weather : Weather @@ -447,14 +462,21 @@ func typeModifier(attacking: Type, defending : Type)-> Double { // http://bulbapedia.bulbagarden.net/wiki/Damage -func damage(environment : Environment, pokemon: Pokemon, move: Move, target: Pokemon) -> Double { +// add environment effect +func damage(pokemon: Pokemon, move: Move, target: Pokemon) -> Double { var STAB : Double = 1 // initialise with non-STAB multiplier value - if ( (kangaskhan.type.0 == move.type) || (pokemon.type.1 == move.type) ) {STAB = 1.5} + if ( (pokemon.type.0 == move.type) || (pokemon.type.1 == move.type) ) {STAB = 1.5} var typeBonus: Double = typeModifier(attacking: move.type, defending: target.type.0) if (pokemon.type.1 != nil) - {typeBonus = typeBonus * typeModifier(attacking: move.type, defending: target.type.1!)} + { typeBonus *= typeModifier(attacking: move.type, defending: target.type.1!) } + if (typeBonus == 0) + { print("It doesn't affect", target, "...") } + else if ((typeBonus == 0.25) || (typeBonus == 0.5)) + { print("It's not very effective...") } + else if ((typeBonus == 2) || (typeBonus == 4)) + { print("It's super effective!") } var critical: Double = 1 // initialise with non-crit mult value let randNum: Int = Int(drand48() * 257) // random int between 0 and 256 (included) @@ -466,41 +488,51 @@ func damage(environment : Environment, pokemon: Pokemon, move: Move, target: Pok let randFactor: Double = ((drand48() * 0.15) + 0.85) // uniformly distributed between 0.85 and 1 - let modifier : Double = STAB * typeBonus * critical * environmentBonus * randFactor - - let tempDamage: Double = (2 * pokemon.level + 10) / 250 + let others: Double = 1 // actually calculate this. burn, items, etc. - let attDef: Double - if (move.category == .physical) { attDef = pokemon.effective_stats.attack / target.effective_stats.defense } - else if (move.category == .special) { attDef = pokemon.effective_stats.special_attack / target.effective_stats.special_defense } - else { attDef = 0 } + let modifier : Double = STAB * typeBonus * critical * environmentBonus * randFactor * others - let damage : Double = (tempDamage * attDef * Double(move.power) * 2) * modifier + let tempDamage: Double = (2 * pokemon.level + 10) / 250 + let attDefRatio: Double + if (move.category == .physical) { attDefRatio = pokemon.effective_stats.attack / target.effective_stats.defense } + else if (move.category == .special) { attDefRatio = pokemon.effective_stats.special_attack / target.effective_stats.special_defense } + else { attDefRatio = 0 } + let damage : Double = (tempDamage * attDefRatio * Double(move.power) * 2) * modifier return damage } struct State { // TODO: describe a battle state + // is this even needed? all factors are already accounted for, unless you go into some VERY specific details } -func battle(trainers: inout [Trainer], behavior: (State, Trainer) -> Move) -> () { +func battle(trainers: inout [Trainer]) -> () { - // TODO: print("intro blah blah goes here") var partyA: [Pokemon]? = trainers[0].party // player var partyB: [Pokemon]? = trainers[1].party // pc + //var partyAFainted: [Pokemon]? = nil + //var partyBFainted: [Pokemon]? = nil + + + for _ in partyA! { // sets pokemon stats to their "default" level (all pokemon, for both trainers) + partyA![0].current_stats = partyA![0].effective_stats + } + for _ in partyB! { + partyB![0].current_stats = partyB![0].effective_stats + } + - // check nicknames, if they exist use them instead of standard names + // TODO: check nicknames, if they exist use them instead of standard names - print("trainer a sent out", partyA![0], "trainer B sent out", partyB![0]) + print("trainer A sent out", partyA![0].name, "trainer B sent out", partyB![0].name) while (partyA != nil && partyB != nil) { - // get environment info - // print if non-default + // TODO: get environment info, print if non-default /* print("what to do? [F]ight, [B]ag, [P]okemon") //pick player move @@ -514,8 +546,6 @@ func battle(trainers: inout [Trainer], behavior: (State, Trainer) -> Move) -> () // ask for user input // check move has PP left // damage + effects - - } else if ( playerMove == "B" || playerMove == "b" || playerMove == "Bag" || playerMove == "bag" ) { // print contents of bag with an index @@ -532,26 +562,67 @@ func battle(trainers: inout [Trainer], behavior: (State, Trainer) -> Move) -> () } */ + // get moves // the "move" is just randomly chosen between the known moves, eventually expand this to allow for user input and to change pokemon and use items - var moveAIndex: Int = Int(drand48()*5) // does this round or truncate? also assumes a pokemon knows four moves - var moveBIndex: Int = Int(drand48()*5) - var moveA: Move = partyA![0].moves[moveAIndex] - var moveB: Move = partyB![0].moves[moveBIndex] - - let firstToMove, secondToMove: Trainer - if (moveA.priority > moveB.priority) - { } - - // trainers pick a move, or switch pokemon, or use an object - // pokemon: check it's valid and non-KO, priority 6 - // obj: check it's valid, priority 6 - // move: check that it's a valid move, and that it has PP left - // same priority? - // y: - // both are non-damaging: random order (or determined by speed??) - // one is damaging: non-damaging first - // both are damaging: speed determines order - // n: higher priority first + let moveAIndex: Int = Int(drand48()*5) // assumes a pokemon knows four moves; fix this to get real move count + let moveBIndex: Int = Int(drand48()*5) + let moveA: Move = partyA![0].moves[moveAIndex] + let moveB: Move = partyB![0].moves[moveBIndex] + + // TODO: check PPs! + + // TODO: print("A's pokemon used", moveA) + + // compute move order for the current turn + // priority: non-damaging + // higher move priority + // higher pokemon speed + let firstToMove: Trainer + if ( (moveA.power == 0) || (moveB.power != 0) ) + {firstToMove = trainerA} + else if ( (moveA.power != 0) || (moveB.power == 0) ) + {firstToMove = trainerB} + else { + if (moveA.priority > moveB.priority) + {firstToMove = trainerA} + else if (moveA.priority < moveB.priority) + {firstToMove = trainerB} + else { + if (partyA![0].effective_stats.speed > partyB![0].effective_stats.speed) + {firstToMove = trainerA} + else if (partyA![0].effective_stats.speed < partyB![0].effective_stats.speed) + {firstToMove = trainerB} + else { //same speed and priority -> random order + if (drand48() > 0.5) + {firstToMove = trainerA} + else + {firstToMove = trainerA} + } + } + + // TODO: check if move changes weather, act accordingly + // TODO: check if move changes stats, act accordingly + + // first deals damage to second + // TODO: rly ugly, fix + if firstToMove == trainerA { + let damageDone = damage(pokemon: trainers[0].party[0], move: moveA, target: trainers[1].party[0]) + trainers[1].party[0].current_stats.hitpoints -= damageDone + print(trainers[1].party[0], "HP:", trainers[1].party[0].current_stats.hitpoints, "/", trainers[1].party[0].current_stats.hitpoints) + // TODO: recoil + if (trainers[1].party[0].current_stats.hitpoints == 0) { + print(trainers[1].party[0], "fainted!") + swap(&trainers[1].party[0], &trainers[1].party[1]) + //if + } + } + else { + // trainerB goes first + } + + + + // first to move // check status conditions, see if move can be executed (can always switch pokemon) // move changes weather? @@ -590,11 +661,6 @@ func battle(trainers: inout [Trainer], behavior: (State, Trainer) -> Move) -> () // y: second tries sending out another pokemon // nonzero status conditions on either pokemon: apply effects // KO? try sending out another pokemon + } } } - - -func initialise() -> Int { - // call other stuff here - return 0 -} From 449035f13ed09be376b921c037411c1dd026501e Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Sun, 12 Mar 2017 22:41:14 +0100 Subject: [PATCH 26/27] finished up basic version of battle function --- Sources/main.swift | 7 ++- ...-exercises.swift => swift_exercises.swift} | 53 ++++++++++++------- 2 files changed, 37 insertions(+), 23 deletions(-) rename Sources/{swift-exercises.swift => swift_exercises.swift} (93%) diff --git a/Sources/main.swift b/Sources/main.swift index 0c55878..e78c685 100644 --- a/Sources/main.swift +++ b/Sources/main.swift @@ -1,6 +1,5 @@ -import Foundation // floor, random, etc - - -print("test") +print("starting...") battle(trainers: &trainers) + +print("done!") diff --git a/Sources/swift-exercises.swift b/Sources/swift_exercises.swift similarity index 93% rename from Sources/swift-exercises.swift rename to Sources/swift_exercises.swift index 59c7eb7..899ca4b 100644 --- a/Sources/swift-exercises.swift +++ b/Sources/swift_exercises.swift @@ -514,8 +514,10 @@ func battle(trainers: inout [Trainer]) -> () { var partyA: [Pokemon]? = trainers[0].party // player var partyB: [Pokemon]? = trainers[1].party // pc - //var partyAFainted: [Pokemon]? = nil - //var partyBFainted: [Pokemon]? = nil + let partyASize: Int = partyA!.count + let partyBSize: Int = partyB!.count + var partyAFainted: Int = 0 + var partyBFainted: Int = 0 for _ in partyA! { // sets pokemon stats to their "default" level (all pokemon, for both trainers) @@ -525,12 +527,10 @@ func battle(trainers: inout [Trainer]) -> () { partyB![0].current_stats = partyB![0].effective_stats } - // TODO: check nicknames, if they exist use them instead of standard names + print("trainer A sent out", partyA![0].nickname as Any, "trainer B sent out", partyB![0].nickname as Any) - print("trainer A sent out", partyA![0].name, "trainer B sent out", partyB![0].name) - - while (partyA != nil && partyB != nil) { + while ( (partyASize != partyAFainted) && (partyBSize != partyBFainted) ) { // TODO: get environment info, print if non-default @@ -570,7 +570,6 @@ func battle(trainers: inout [Trainer]) -> () { let moveB: Move = partyB![0].moves[moveBIndex] // TODO: check PPs! - // TODO: print("A's pokemon used", moveA) // compute move order for the current turn @@ -604,23 +603,39 @@ func battle(trainers: inout [Trainer]) -> () { // TODO: check if move changes stats, act accordingly // first deals damage to second - // TODO: rly ugly, fix - if firstToMove == trainerA { - let damageDone = damage(pokemon: trainers[0].party[0], move: moveA, target: trainers[1].party[0]) - trainers[1].party[0].current_stats.hitpoints -= damageDone - print(trainers[1].party[0], "HP:", trainers[1].party[0].current_stats.hitpoints, "/", trainers[1].party[0].current_stats.hitpoints) + let first: Int; let second: Int + if firstToMove == trainerA { first = 0; second = 1 } + else { first = 1; second = 0 } + + var attacker = first; var defender = second + + for index in (0...1) { // loops twice, once per pokemon attack + + if (index == 1) { // if second half of turn, swaps attacker and defender + var swap: Int + swap = defender + defender = attacker + attacker = swap + } + + let damageDone = damage(pokemon: trainers[attacker].party[0], move: moveA, target: trainers[defender].party[0]) + trainers[defender].party[0].current_stats.hitpoints -= damageDone + print(trainers[defender].party[0], "HP:", trainers[defender].party[0].current_stats.hitpoints, "/", trainers[defender].party[0].current_stats.hitpoints) // TODO: recoil if (trainers[1].party[0].current_stats.hitpoints == 0) { - print(trainers[1].party[0], "fainted!") - swap(&trainers[1].party[0], &trainers[1].party[1]) - //if + print(trainers[1].name, "'s ", trainers[1].party[0], "fainted!") + partyBFainted += 1 + // change pokemon + // skip next half of turn (second can't actually attack if he got KO'd) + if (trainers[0].party[0].current_stats.hitpoints == 0) { + print(trainers[0].name, "'s ", trainers[0].party[0], "fainted!") + partyAFainted += 1 + // change pokemon + } } } - else { - // trainerB goes first - } - +// // first to move From f13a9047fd0b51a0da6ff4503ae7d899ab2a1b3a Mon Sep 17 00:00:00 2001 From: tullio iacobucci <awfkchan@gmail.com> Date: Sun, 12 Mar 2017 22:53:49 +0100 Subject: [PATCH 27/27] some small changes to battle function, also a few minor chnages throughout --- Sources/swift_exercises.swift | 53 ++++++++++++++++------------------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/Sources/swift_exercises.swift b/Sources/swift_exercises.swift index 899ca4b..6e09030 100644 --- a/Sources/swift_exercises.swift +++ b/Sources/swift_exercises.swift @@ -421,7 +421,6 @@ func typeToInt(type: Type) -> Int { case .dragon: return 15 case .dark: return 16 case .fairy: return 17 - //default: return -1 //never executed } } @@ -447,7 +446,7 @@ func typeModifier(attacking: Type, defending : Type)-> Double { [ 1, 1, 2, 1, 2, 1, 1, 1,0.5,0.5,0.5, 2, 1, 1,0.5, 2, 1, 1], // ice [ 1, 1, 1, 1, 1, 1, 1, 1,0.5, 1, 1, 1, 1, 1, 1, 2, 1, 0], // dragon [ 1,0.5, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1,0.5,0.5], // dark - [ 1, 2, 1,0.5, 1, 1, 1, 1,0.5,0.5, 1, 1, 1, 1, 1, 2, 2, 1] // fairy + [ 1, 2, 1,0.5, 1, 1, 1, 1,0.5,0.5, 1, 1, 1, 1, 1, 2, 2, 1] // fairy ] return (multiplierMatrix[attackingID][defendingID]) @@ -496,16 +495,11 @@ func damage(pokemon: Pokemon, move: Move, target: Pokemon) -> Double { let attDefRatio: Double if (move.category == .physical) { attDefRatio = pokemon.effective_stats.attack / target.effective_stats.defense } else if (move.category == .special) { attDefRatio = pokemon.effective_stats.special_attack / target.effective_stats.special_defense } - else { attDefRatio = 0 } + else { attDefRatio = 0 } // stat-only; 0 damage as safety let damage : Double = (tempDamage * attDefRatio * Double(move.power) * 2) * modifier return damage } -struct State { - // TODO: describe a battle state - // is this even needed? all factors are already accounted for, unless you go into some VERY specific details -} - func battle(trainers: inout [Trainer]) -> () { @@ -570,7 +564,8 @@ func battle(trainers: inout [Trainer]) -> () { let moveB: Move = partyB![0].moves[moveBIndex] // TODO: check PPs! - // TODO: print("A's pokemon used", moveA) + // TODO: print("A's pokemon used", moveA), etc. + // compute move order for the current turn // priority: non-damaging @@ -610,27 +605,27 @@ func battle(trainers: inout [Trainer]) -> () { var attacker = first; var defender = second for index in (0...1) { // loops twice, once per pokemon attack + if trainers[defender].party[0].current_stats.hitpoints >= 0 { //skips second half of turn if second pokemon got KO'd by first + if (index == 1) { // if second half of turn, swaps attacker and defender + var swap: Int + swap = defender + defender = attacker + attacker = swap + } - if (index == 1) { // if second half of turn, swaps attacker and defender - var swap: Int - swap = defender - defender = attacker - attacker = swap - } - - let damageDone = damage(pokemon: trainers[attacker].party[0], move: moveA, target: trainers[defender].party[0]) - trainers[defender].party[0].current_stats.hitpoints -= damageDone - print(trainers[defender].party[0], "HP:", trainers[defender].party[0].current_stats.hitpoints, "/", trainers[defender].party[0].current_stats.hitpoints) - // TODO: recoil - if (trainers[1].party[0].current_stats.hitpoints == 0) { - print(trainers[1].name, "'s ", trainers[1].party[0], "fainted!") - partyBFainted += 1 - // change pokemon - // skip next half of turn (second can't actually attack if he got KO'd) - if (trainers[0].party[0].current_stats.hitpoints == 0) { - print(trainers[0].name, "'s ", trainers[0].party[0], "fainted!") - partyAFainted += 1 - // change pokemon + let damageDone = damage(pokemon: trainers[attacker].party[0], move: moveA, target: trainers[defender].party[0]) + trainers[defender].party[0].current_stats.hitpoints -= damageDone + print(trainers[defender].party[0], "HP:", trainers[defender].party[0].current_stats.hitpoints, "/", trainers[defender].party[0].effective_stats.hitpoints) + // TODO: recoil + if (trainers[1].party[0].current_stats.hitpoints <= 0) { + print(trainers[1].name, "'s ", trainers[1].party[0], "fainted!") + partyBFainted += 1 + // change pokemon + if (trainers[0].party[0].current_stats.hitpoints <= 0) { + print(trainers[0].name, "'s ", trainers[0].party[0], "fainted!") + partyAFainted += 1 + // change pokemon + } } } }