gizmola Posted June 22, 2011 Share Posted June 22, 2011 This is a nice thread at this point, as it offers a procedural solution and an oop solution to the same problem. Quote Link to comment https://forums.phpfreaks.com/topic/239936-struggling-graduate/page/2/#findComment-1233164 Share on other sites More sharing options...
Daniel0 Posted June 22, 2011 Share Posted June 22, 2011 I suppose I might as well post the solution I made yesterday as well. I didn't bother creating a web front end, so run it from a terminal...  <?php class Player {   private $name;   private $health;   private $attack;   private $defence;   private $speed;   private $evade;   private $maxHealth;   public function __construct($name, $health, $attack, $defence, $speed, $evade)   {     $this->name = $name;     $this->health = $this->maxHealth = $health;     $this->attack = $attack;     $this->defence = $defence;     $this->speed = $speed;     $this->evade = $evade;   }   public function isAlive()   {     return $this->health > 0;   }   public function getName()   {     return $this->name;   }   public function getHealth()   {     return $this->health;   }   public function getMaxHealth()   {     return $this->maxHealth;   }   public function getAttack()   {     return $this->attack;   }   public function getDefence()   {     return $this->defence;   }   public function getSpeed()   {     return $this->speed;   }   public function getEvade()   {     return $this->evade / 100;   }   public function attack(Player $opponent)   {     if (!$opponent->doEvadeRoll($this)) {       $opponent->wound($this->getAttack() - $opponent->getDefence(), $opponent);     }   }   public function wound($hp, Player $opponent)   {     $this->health = max(0, $this->health - $hp);   }   public function heal($hp)   {     $this->health = min($this->getMaxHealth(), $this->health + $hp);   }   public function doEvadeRoll(Player $opponent)   {     return mt_rand(1, 100) <= $this->evade;   }   public function __toString()   {     return sprintf('%s (%d)', $this->getName(), $this->getHealth());   } } class Ninja extends Player {   public function __construct($name)   {     parent::__construct($name,       mt_rand(40, 60),       mt_rand(60, 70),       mt_rand(20, 30),       mt_rand(90, 100),       mt_rand(30, 100)     );   }   public function getAttack()   {     $attack = parent::getAttack();     if (mt_rand(1, 100) <= 5) {       $attack *= 2;     }     return $attack;   } } class Samurai extends Player {   public function __construct($name)   {     parent::__construct($name,       mt_rand(60, 100),       mt_rand(75, 80),       mt_rand(35, 40),       mt_rand(60, 80),       mt_rand(30, 40)     );   }   public function doEvadeRoll(Player $opponent)   {     $evaded = parent::doEvadeRoll($opponent);     if ($evaded && mt_rand(1, 100) <= 10) {       $this->heal(10);     }     return $evaded;   } } class Brawler extends Player {   public function __construct($name)   {     parent::__construct($name,       mt_rand(90, 100),       mt_rand(65, 75),       mt_rand(40, 50),       mt_rand(40, 65),       mt_rand(30, 35)     );   }   public function getDefence()   {     $def = parent::getDefence();     if ($this->getHealth()/$this->getMaxHealth() < 0.2) {       $def += 10;     }     return $def;   } } class Game {   private $player1;   private $player2;   private $maxRounds;   private $rounds;   public function __construct(Player $player1, Player $player2, $maxRounds = 30)   {     $this->player1 = $player1;     $this->player2 = $player2;     $this->maxRounds = $maxRounds;     $this->rounds = 0;   }   public function gameOver()   {     return $this->rounds == $this->maxRounds || !$this->player1->isAlive() || !$this->player2->isAlive();   }   public function getWinner()   {     if (!$this->gameOver()) {       throw new Exception('Game not over yet.');     }     if (!$this->player2->isAlive()) {       return $this->player1;     }     else if (!$this->player1->isAlive()) {       return $this->player2;     }     else {       return null; // draw     }   }   private function comparePlayers(Player $a, Player $b)   {     $s1 = $a->getSpeed();     $s2 = $b->getSpeed();     if ($s1 === $s2) {       return $a->getDefence() - $b->getDefence();     }     else {       return $s1 - $s2;     }   }   public function doRound()   {     if ($this->gameOver()) {       throw new Exception('Cannot do more rounds when game is over.');     }     ++$this->rounds;     $players = array($this->player1, $this->player2);     usort($players, array($this, 'comparePlayers'));     $players[0]->attack($players[1]);     $players[1]->attack($players[0]);   }   public function getRound()   {     return $this->rounds + 1;   } } $classes = array('Ninja', 'Samurai', 'Brawler'); list($p1, $p2) = array_rand($classes, 2); $player1 = new $classes[$p1]($classes[$p1]); $player2 = new $classes[$p2]($classes[$p2]); $game = new Game($player1, $player2, 30); while (!$game->gameOver()) {   echo 'Round ' . $game->getRound() . ':' . PHP_EOL;   echo $player1 . PHP_EOL;   echo $player2 . PHP_EOL;   echo PHP_EOL;   $game->doRound(); } $winner = $game->getWinner(); if ($winner === null) {   echo 'Draw.'; } else {   echo 'Winner: ' . $winner->getName(); } echo PHP_EOL;  I estimate that I used ~40 minutes. Quote Link to comment https://forums.phpfreaks.com/topic/239936-struggling-graduate/page/2/#findComment-1233232 Share on other sites More sharing options...
spiderwell Posted June 22, 2011 Share Posted June 22, 2011 I'm loving this thread, I plan to try out and check everyones versions later, and heck maybe even try make one my self Quote Link to comment https://forums.phpfreaks.com/topic/239936-struggling-graduate/page/2/#findComment-1233367 Share on other sites More sharing options...
ignace Posted June 22, 2011 Share Posted June 22, 2011 I typed it as I read the task description:  class BattleRecorder {  private static $instance;   private function __construct() {}  private function __clone() {}   public static function get() {   if (is_null(self::$instance)) {    self::$instance = new self();   }   return self::$instance;  }   public function record($msg) {   echo $msg, PHP_EOL;  } } abstract class Warrior {  public $name;  public $health;  public $attack;  public $defence;  public $speed;  public $evade;   public $turns;  public $recorder;   public static function get($warrior, $name) {   $className = ucfirst(strtolower($warrior));   return new $className($name);  }   public function __construct($name) {   $this->name = $name;     $this->_init();  }   public function isDefeated() {   return !$this->isAlive() || !$this->hasTurnsLeft();  }   public function isAlive() {   return $this->health > 0;  }   public function hasTurnsLeft() {   return $this->turns > 0;  }   public function evadedAttack() {   return $this->evade == mt_rand(1, 100) / 100;  }   public abstract function attack(Warrior $w);  public abstract function defend($attack);   protected abstract function _init(); } class Ninja extends Warrior {  public function attack(Warrior $w) {   --$this->turns;     $damage = $this->attack * (0.05 == mt_rand(1,100) / 100 ? 2 : 1);     $this->recorder->record($this->name . ' dealt ' . $damage . ' damage.');     $w->defend($damage);  }   public function defend($attack) {   if ($this->evadedAttack()) {    $this->recorder->record($this->name . ' evaded the attack.');    return;   }     $damage = $attack - $this->defence;   if ($damage > 0)    $this->health -= $damage;      $this->recorder->record($this->name . ' defended, but lost ' . $damage . ' health.');  }   protected function _init() {   $this->health = mt_rand(40, 60);   $this->attack = mt_rand(60, 70);   $this->defence = mt_rand(20, 30);   $this->speed = mt_rand(90, 100);   $this->evade = mt_rand(30, 50) / 100;  } } class Arena {  public static function fight(Warrior $w1, Warrior $w2) {   $w1->turns = 30;   $w1->recorder = BattleRecorder::get();     $w2->turns = 30;   $w2->recorder = BattleRecorder::get();     list($w1, $w2) = self::drawFirstBlood($w1, $w2);   while (!$w1->isDefeated() && !$w2->isDefeated()) {    $w1->attack($w2);    $w2->attack($w1);   }     if ($w1->isAlive() && $w2->isAlive())    BattleRecorder::get()->record('draw!');   elseif ($w1->isAlive())    BattleRecorder::get()->record($w1->name . ' won!');   else    BattleRecorder::get()->record($w2->name . ' won!');  }   protected static function drawFirstBlood(Warrior $w1, Warrior $w2) {   $r = array($w1, $w2);   if ($w1->speed > $w2->speed) {    $w1->attack($w2);    $r = array($w2, $w1);   } else if ($w1->speed == $w2->speed) {    if ($w1->defence < $w2->defence) {     $w1->attack($w2);     $r = array($w2, $w1);    } else {     $w2->attack($w1);    }   } else {    $w2->attack($w1);   }   return $r;  } }  Might not be a good example as for best practices Took me around 40 minutes I think.  Call like:  Arena::fight(  Warrior::get('Ninja', 'Foo'),  Warrior::get('Ninja', 'Bar') ); Quote Link to comment https://forums.phpfreaks.com/topic/239936-struggling-graduate/page/2/#findComment-1233461 Share on other sites More sharing options...
Daniel0 Posted June 22, 2011 Share Posted June 22, 2011 Warriors' stats can change during the course of the battle, so you're not necessarily first because you were first in the first round. Easily fixed by sorting inside the loop instead of outside though. Quote Link to comment https://forums.phpfreaks.com/topic/239936-struggling-graduate/page/2/#findComment-1233497 Share on other sites More sharing options...
Alex Posted June 22, 2011 Share Posted June 22, 2011 I interpreted a few things differently, but seeing as how everyone else interpreted them that way I updated my code. Quote Link to comment https://forums.phpfreaks.com/topic/239936-struggling-graduate/page/2/#findComment-1233504 Share on other sites More sharing options...
.josh Posted June 22, 2011 Share Posted June 22, 2011 The spec defines how to determine who goes first initially. The way it is worded...yes, technically doing it before the battle loops will work, and be within spec. But then each warrior has a stat-changing ability that is triggered based on the battle. Technically there are currently no speed-changing abilities defined in this spec, so technically you are within spec. But the point of OOP is to be able to think ahead and expand. It makes more sense to code the abilities in a way that any stat can be changed for whatever reason. For instance, say I want to give ninjas a 10% chance of a speed boost, that would affect whether or not they go first. But that stat change won't work if you are determining who will go first only once, before the first battle. So I don't think it was "misinterpreted" per se..just that IMO it is better to code with the mentality of "xyz is in the spec...I could technically do it one way, but if I do it this other way, it will make it easier for me to add more things later". I've never really sat down and formerly learned OOP but I think that's what's called keeping your coupling loose or something. Quote Link to comment https://forums.phpfreaks.com/topic/239936-struggling-graduate/page/2/#findComment-1233507 Share on other sites More sharing options...
Alex Posted June 22, 2011 Share Posted June 22, 2011 Not sure if that was at me, or what. But anyway, at first I interpreted it as the stats determine who goes first, as in starts off the entire battle, from which point it just goes back and forth between the two. In which case a change in stats during the battle wouldn't matter. Quote Link to comment https://forums.phpfreaks.com/topic/239936-struggling-graduate/page/2/#findComment-1233511 Share on other sites More sharing options...
Daniel0 Posted June 22, 2011 Share Posted June 22, 2011 Technically there are currently no speed-changing abilities defined in this spec, so technically you are within spec. Â The brawler gets a defence boost when on low health. Defence was the secondary stat to check when determining who goes first. Quote Link to comment https://forums.phpfreaks.com/topic/239936-struggling-graduate/page/2/#findComment-1233523 Share on other sites More sharing options...
.josh Posted June 22, 2011 Share Posted June 22, 2011 Not sure if that was at me, or what. But anyway, at first I interpreted it as the stats determine who goes first, as in starts off the entire battle, from which point it just goes back and forth between the two. In which case a change in stats during the battle wouldn't matter.  Yes, you're supposed to let whoever has more speed (failing that, less defense...failing that...unspecified (I just flip a coin at that point)) attack first. And technically it doesn't say "check speed before every round," and technically there are no speed-altering abilities in the spec. So it's within one's rights to write it exactly like that: check stats initially, do all 30 rounds based on initial stat check (..except for defense...see Dan's point, which does apply)  HOWEVER... there are specs for abilities that cause stats to change, which does affect each round of the battle.  Ninja: "With each attack there is a 5% chance of doubling the attack strength." This very explicitly states that an altered stat should affect each fighting round.  Samurai: "When a samurai evades an attack there is a 10% chance of regaining 10 health" What would be the point in increasing health if it's not supposed to be applied to subsequent rounds of the fight?  Brawler: "When a brawler’s health falls to less than 20% their defence increases by 10" What would be the point in increasing defense if that increased defense is not going to be used in subsequent rounds?  The specs state to alter specific stats for specific warriors, to be applied to each (subsequent) round of a fight. If you stuck to the exact current specs, it does not say to do anything with speed, so it is "safe" to check speed before the rounds begin, and then never check it again.  But if you look at the specs in a broader term of "script should be able to alter stats for warriors and be applied to subsequent rounds," then you are fucking yourself on the speed stat. If tomorrow you are tasked with the following:  Ninja: "Each attack there is a 10% chance of increasing speed by 20%."  Since the current spec is check speed to determine who hits first, this new ability would give ninjas an increased chance to hit first on each round. But since you don't do a speed check every round, you're going to have to recode what you did, to accommodate this new ability. Isn't that the whole point of Object Oriented Programming? To write code in more abstract terms so that there is less work involved in adding new stuff later on?  Technically there are currently no speed-changing abilities defined in this spec, so technically you are within spec.  The brawler gets a defence boost when on low health. Defence was the secondary stat to check when determining who goes first.  Yeah you're right...forgot about that (I did it in my code..just forgot about it when posting that... but that just further proves my point in this post. Quote Link to comment https://forums.phpfreaks.com/topic/239936-struggling-graduate/page/2/#findComment-1233531 Share on other sites More sharing options...
Alex Posted June 22, 2011 Share Posted June 22, 2011 HOWEVER... there are specs for abilities that cause stats to change, which does affect each round of the battle. Yeah, sorry, when I said "In which case a change in stats during the battle wouldn't matter." I meant with respect to determining who goes first. I wasn't ever arguing with that.  edit: Nevermind. Quote Link to comment https://forums.phpfreaks.com/topic/239936-struggling-graduate/page/2/#findComment-1233541 Share on other sites More sharing options...
.josh Posted June 22, 2011 Share Posted June 22, 2011 Ninja: "With each attack there is a 5% chance of doubling the attack strength." This very explicitly states that an altered stat should affect each fighting round.  I interpreted that as: every time a ninja attacks there's a 5% chance that it does twice as much damage as it would normally do, not that the attack stat of the ninja doubles permanently.  edit:  Looking over the code it seems that Daniel and ignace interpreted it that way (the way I did) as well.  I interpret that as for each round, 5% chance that the $attack stat doubles. This doesn't necessarily double the actual damage done, because damage done is $attack - $defense.  So IOW I interpret it as  ($attack * 2) - $defense  not  ($attack - $defense) * 2  I guess that interpretation is a matter of opinion though... but I too interpret that it is something to do each round, and shouldn't be a permanent stat increase. So my code in principle basically goes like this:  current stats $ninja->attack = 50; $warrior->defense = 50;  pre-battle: rand 1,100..if > 95 (5% chance) then $ninja->attack = $ninja->attack * 2; // evaluate true for demo  battle: $damage = $ninja->attack - $warrior->defense; // 100 - 50 $warrior->health = $warrior->health - $damage;  post-battle: $ninja->attack = $ninja->attack / 2;     Quote Link to comment https://forums.phpfreaks.com/topic/239936-struggling-graduate/page/2/#findComment-1233549 Share on other sites More sharing options...
Alex Posted June 22, 2011 Share Posted June 22, 2011 I edited my post, but you quoted me before that. Â I was actually talking about something else: I thought that you permanently increased the attack stat of the ninja, but upon closer inspection of your code I realized that you didn't, so I removed my comment about that. Â But what you posted on was another good point. The specifications are too ambiguous. Quote Link to comment https://forums.phpfreaks.com/topic/239936-struggling-graduate/page/2/#findComment-1233553 Share on other sites More sharing options...
.josh Posted June 22, 2011 Share Posted June 22, 2011 But what you posted on was another good point. The specifications are too ambiguous.  IMO, if it were me doing the interview, it would have earned the OP brownie points (and more time) if he had gone back with a list of questions to clarify details (and perhaps also point out flaws in the "game mechanics" itself, depending on the employer...the warriors are pretty unbalanced...). Quote Link to comment https://forums.phpfreaks.com/topic/239936-struggling-graduate/page/2/#findComment-1233555 Share on other sites More sharing options...
ebmigue Posted June 23, 2011 Share Posted June 23, 2011 The OP needs advice on how to overcome his "fresh graduate struggles as a web developer" in general, and not solve his specific problem of implementing a game. Â The brilliant suggested implementations/solutions of his exam interests me though. Â However, there ought to be a separate category for these sort of discussions, say, "PHP Games". Its purpose is to be a discussion of ideas of possible cool games, then implement it in PHP. While there is an existing category for PHP scripts, this will be different in the sense that it will devote itself to game programming in PHP. Â I don't know, just a suggestion. Quote Link to comment https://forums.phpfreaks.com/topic/239936-struggling-graduate/page/2/#findComment-1233647 Share on other sites More sharing options...
gizmola Posted June 23, 2011 Share Posted June 23, 2011 The OP needs advice on how to overcome his "fresh graduate struggles as a web developer" in general, and not solve his specific problem of implementing a game. Â The brilliant suggested implementations/solutions of his exam interests me though. Â However, there ought to be a separate category for these sort of discussions, say, "PHP Games". Its purpose is to be a discussion of ideas of possible cool games, then implement it in PHP. While there is an existing category for PHP scripts, this will be different in the sense that it will devote itself to game programming in PHP. Â I don't know, just a suggestion. Â Ok. Quote Link to comment https://forums.phpfreaks.com/topic/239936-struggling-graduate/page/2/#findComment-1233654 Share on other sites More sharing options...
ignace Posted June 23, 2011 Share Posted June 23, 2011 I really like how the OP actually posted a fun exercise, we all posted our solution in either OO or procedural, and now we are all discussing each others solution. I think we should do this more, allow the entire community to participate and defend their design/decisions. With the greater goal of everyone learning new things from each others code/comments. Quote Link to comment https://forums.phpfreaks.com/topic/239936-struggling-graduate/page/2/#findComment-1233698 Share on other sites More sharing options...
Alex Posted June 23, 2011 Share Posted June 23, 2011 I really like how the OP actually posted a fun exercise, we all posted our solution in either OO or procedural, and now we are all discussing each others solution. I think we should do this more, allow the entire community to participate and defend their design/decisions. With the greater goal of everyone learning new things from each others code/comments. Â I agree, I was thinking the same thing. I think it would be fun and great way to learn from each other and could ultimately lead to a nice library of examples. Quote Link to comment https://forums.phpfreaks.com/topic/239936-struggling-graduate/page/2/#findComment-1233708 Share on other sites More sharing options...
ebmigue Posted June 23, 2011 Share Posted June 23, 2011 I really like how the OP actually posted a fun exercise, we all posted our solution in either OO or procedural, and now we are all discussing each others solution. I think we should do this more, allow the entire community to participate and defend their design/decisions. With the greater goal of everyone learning new things from each others code/comments.  Thus, I would recommend a separate and new forum category. And it shall be devoted to discussions about Game Programming.  The fun really is in conceptualizing and implementing games, either new or old, complex or simple games. Also, Game Programming has a deep theoretical aspect, and it can enhance existing skills (as compared to developing emails or the next blog/cms application).   Quote Link to comment https://forums.phpfreaks.com/topic/239936-struggling-graduate/page/2/#findComment-1233723 Share on other sites More sharing options...
Alex Posted June 23, 2011 Share Posted June 23, 2011 I don't think the exercise was fun specifically because it involved a game. Quote Link to comment https://forums.phpfreaks.com/topic/239936-struggling-graduate/page/2/#findComment-1233725 Share on other sites More sharing options...
ebmigue Posted June 23, 2011 Share Posted June 23, 2011 I do think otherwise. Quote Link to comment https://forums.phpfreaks.com/topic/239936-struggling-graduate/page/2/#findComment-1233726 Share on other sites More sharing options...
Adam Posted June 23, 2011 Share Posted June 23, 2011 I think if there was a dedicated forum for this kind of thing then it would just end up inactive after a short while. It's been interesting and got people involved this time, but I think that's purely down to the fact that it's rare.. Like Christmas. Have that everyday and the novelty would soon ware out. Perhaps creating the odd thread here and there in Misc. would be better? Quote Link to comment https://forums.phpfreaks.com/topic/239936-struggling-graduate/page/2/#findComment-1233727 Share on other sites More sharing options...
ebmigue Posted June 23, 2011 Share Posted June 23, 2011 I think if there was a dedicated forum for this kind of thing then it would just end up inactive after a short while. It's been interesting and got people involved this time, but I think that's purely down to the fact that it's rare.. Like Christmas. Have that everyday and the novelty would soon ware out. Â I agree though. Quote Link to comment https://forums.phpfreaks.com/topic/239936-struggling-graduate/page/2/#findComment-1233731 Share on other sites More sharing options...
ignace Posted June 23, 2011 Share Posted June 23, 2011 I think if there was a dedicated forum for this kind of thing then it would just end up inactive after a short while. Â Although I would like to think/see it otherwise, I must agree. Quote Link to comment https://forums.phpfreaks.com/topic/239936-struggling-graduate/page/2/#findComment-1233760 Share on other sites More sharing options...
KevinM1 Posted June 23, 2011 Share Posted June 23, 2011 Regardless, to address ebmigue's other point, I don't think there's much we can do for the OP. He's obviously deficient in many areas, and nothing short of getting good resources (which we have at least one sticky topic for, if not more) and writing code will help him. Maybe he should go back to school for a couple years at a technical college, but since he just graduated, that's probably not a viable option.  With no disrespect intended to the OP, he's at beginning hobbyist level right now and is essentially asking us to make him into a competent entry level programmer. That's outside the scope of what we do, and not realistic at all anyway. We're more than willing to help him (or anyone) with specific questions about specific code, but we're not in the business of mentoring. Quote Link to comment https://forums.phpfreaks.com/topic/239936-struggling-graduate/page/2/#findComment-1233767 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.