|
| 1 | +"""Kata - 80's Kids #6: Rock 'Em, Sock 'Em Robots |
| 2 | +
|
| 3 | +completed at: 2025-01-25 20:34:00 |
| 4 | +by: Jakub Červinka |
| 5 | +
|
| 6 | +You and your friends have been battling it out with your Rock 'Em, Sock 'Em robots, but things have gotten a little boring. You've each decided to add some amazing new features to your robot and automate them to battle to the death. |
| 7 | +
|
| 8 | +Each robot will be represented by an object. You will be given two robot objects, and an object of battle tactics and how much damage they produce. Each robot will have a name, hit points, speed, and then a list of battle tactics they are to perform in order. Whichever robot has the best speed, will attack first with one battle tactic. |
| 9 | +
|
| 10 | +Your job is to decide who wins. |
| 11 | +
|
| 12 | +Example: |
| 13 | +```javascript |
| 14 | + robot1 = { |
| 15 | + "name": "Rocky", |
| 16 | + "health": 100, |
| 17 | + "speed": 20, |
| 18 | + "tactics": ["punch", "punch", "laser", "missile"] |
| 19 | + } |
| 20 | + robot2 = { |
| 21 | + "name": "Missile Bob", |
| 22 | + "health": 100, |
| 23 | + "speed": 21, |
| 24 | + "tactics": ["missile", "missile", "missile", "missile"] |
| 25 | + } |
| 26 | + tactics = { |
| 27 | + "punch": 20, |
| 28 | + "laser": 30, |
| 29 | + "missile": 35 |
| 30 | + } |
| 31 | + |
| 32 | + fight(robot1, robot2, tactics) -> "Missile Bob has won the fight." |
| 33 | +``` |
| 34 | +```coffeescript |
| 35 | +robot1 = |
| 36 | + name: "Rocky" |
| 37 | + health: 100 |
| 38 | + speed: 20 |
| 39 | + tactics: [ |
| 40 | + "punch", "punch", "laser", "missile" |
| 41 | + ] |
| 42 | +robot2 = |
| 43 | + name: "Missile Bob" |
| 44 | + health: 100 |
| 45 | + speed: 21 |
| 46 | + tactics: [ |
| 47 | + "missile", "missile", "missile", "missile" |
| 48 | + ] |
| 49 | +tactics = |
| 50 | + punch: 20 |
| 51 | + laser: 30 |
| 52 | + missile: 35 |
| 53 | + |
| 54 | +fight(robot1, robot2, tactics) # "Missile Bob has won the fight." |
| 55 | +``` |
| 56 | +```ruby |
| 57 | +robot1 = { |
| 58 | + "name" => "Rocky", |
| 59 | + "health" => 100, |
| 60 | + "speed" => 20, |
| 61 | + "tactics" => ["punch", "punch", "laser", "missile"] |
| 62 | + } |
| 63 | + robot2 = { |
| 64 | + "name" => "Missile Bob", |
| 65 | + "health" => 100, |
| 66 | + "speed" => 21, |
| 67 | + "tactics" => ["missile", "missile", "missile", "missile"] |
| 68 | + } |
| 69 | + tactics = { |
| 70 | + "punch" => 20, |
| 71 | + "laser" => 30, |
| 72 | + "missile" => 35 |
| 73 | + } |
| 74 | + |
| 75 | + fight(robot1, robot2, tactics) # "Missile Bob has won the fight." |
| 76 | +``` |
| 77 | +```java |
| 78 | + robot1.getName() => "Rocky" |
| 79 | + robot1.getHealth() => 100 |
| 80 | + robot1.getSpeed() => 20 |
| 81 | + robot1.getTactics() => ["punch", "punch", "laser", "missile"] |
| 82 | + |
| 83 | + robot2.getName() => "Missile Bob" |
| 84 | + robot2.getHealth() => 100 |
| 85 | + robot2.getSpeed() => 21 |
| 86 | + robot2.getTactics() => ["missile", "missile", "missile", "missile"] |
| 87 | + |
| 88 | + tactics = { |
| 89 | + "punch" => 20, |
| 90 | + "laser" => 30, |
| 91 | + "missile" => 35 |
| 92 | + } |
| 93 | + |
| 94 | + fight(Robot robot1, Robot robot2, Map<String, Integer> tactics) -> "Missile Bob has won the fight." |
| 95 | +``` |
| 96 | +```python |
| 97 | + robot_1 = { |
| 98 | + "name": "Rocky", |
| 99 | + "health": 100, |
| 100 | + "speed": 20, |
| 101 | + "tactics": ["punch", "punch", "laser", "missile"] |
| 102 | + } |
| 103 | + robot_2 = { |
| 104 | + "name": "Missile Bob", |
| 105 | + "health": 100, |
| 106 | + "speed": 21, |
| 107 | + "tactics": ["missile", "missile", "missile", "missile"] |
| 108 | + } |
| 109 | + tactics = { |
| 110 | + "punch": 20, |
| 111 | + "laser": 30, |
| 112 | + "missile": 35 |
| 113 | + } |
| 114 | + |
| 115 | + fight(robot_1, robot_2, tactics) -> "Missile Bob has won the fight." |
| 116 | +``` |
| 117 | +
|
| 118 | +robot2 uses the first tactic, "missile" because he has the most speed. This reduces robot1's health by 35. Now robot1 uses a punch, and so on. |
| 119 | +
|
| 120 | +**Rules** |
| 121 | +
|
| 122 | +- A robot with the most speed attacks first. If they are tied, the first robot passed in attacks first. |
| 123 | +- Robots alternate turns attacking. Tactics are used in order. |
| 124 | +- A fight is over when a robot has 0 or less health or both robots have run out of tactics. |
| 125 | +- A robot who has no tactics left does no more damage, but the other robot may use the rest of his tactics. |
| 126 | +- If both robots run out of tactics, whoever has the most health wins. If one robot has 0 health, the other wins. Return the message "{Name} has won the fight." |
| 127 | +- If both robots run out of tactics and are tied for health, the fight is a draw. Return "The fight was a draw." |
| 128 | +
|
| 129 | +**To Java warriors** |
| 130 | +
|
| 131 | +`Robot` class is immutable. |
| 132 | +
|
| 133 | +<div style="width: 320px; text-align: center; color: white; border: white 1px solid;"> |
| 134 | +Check out my other 80's Kids Katas: |
| 135 | +</div> |
| 136 | +<div> |
| 137 | +<a style='text-decoration:none' href='http://www.codewars.com/kata/80-s-kids-number-1-how-many-licks-does-it-take'><span style='color:#00C5CD'>80's Kids #1:</span> How Many Licks Does It Take</a><br /> |
| 138 | +
|
| 139 | +<a style='text-decoration:none' href='http://www.codewars.com/kata/80-s-kids-number-2-help-alf-find-his-spaceship'><span style='color:#00C5CD'>80's Kids #2:</span> Help Alf Find His Spaceship</a><br /> |
| 140 | +
|
| 141 | +<a style='text-decoration:none' href='http://www.codewars.com/kata/80-s-kids-number-3-punky-brewsters-socks'><span style='color:#00C5CD'>80's Kids #3:</span> Punky Brewster's Socks</a><br /> |
| 142 | +
|
| 143 | +<a style='text-decoration:none' href='http://www.codewars.com/kata/80-s-kids-number-4-legends-of-the-hidden-temple'><span style='color:#00C5CD'>80's Kids #4:</span> Legends of the Hidden Temple</a><br /> |
| 144 | +
|
| 145 | +<a style='text-decoration:none' href='http://www.codewars.com/kata/80-s-kids-number-5-you-cant-do-that-on-television'><span style='color:#00C5CD'>80's Kids #5:</span> You Can't Do That on Television</a><br /> |
| 146 | +
|
| 147 | +<a style='text-decoration:none' href='http://www.codewars.com/kata/80-s-kids-number-6-rock-em-sock-em-robots'><span style='color:#00C5CD'>80's Kids #6:</span> Rock 'Em, Sock 'Em Robots</a><br /> |
| 148 | +
|
| 149 | +<a style='text-decoration:none' href='http://www.codewars.com/kata/80-s-kids-number-7-shes-a-small-wonder'><span style='color:#00C5CD'>80's Kids #7:</span> She's a Small Wonder</a><br /> |
| 150 | +
|
| 151 | +<a style='text-decoration:none' href='http://www.codewars.com/kata/80-s-kids-number-8-the-secret-world-of-alex-mack'><span style='color:#00C5CD'>80's Kids #8:</span> The Secret World of Alex Mack</a><br /> |
| 152 | +
|
| 153 | +<a style='text-decoration:none' href='http://www.codewars.com/kata/80-s-kids-number-9-down-in-fraggle-rock'><span style='color:#00C5CD'>80's Kids #9:</span> Down in Fraggle Rock </a><br /> |
| 154 | +
|
| 155 | +<a style='text-decoration:none' href='http://www.codewars.com/kata/80-s-kids-number-10-captain-planet'><span style='color:#00C5CD'>80's Kids #10:</span> Captain Planet </a><br /> |
| 156 | +
|
| 157 | +
|
| 158 | +</div> |
| 159 | +
|
| 160 | +""" |
| 161 | + |
| 162 | +from collections import deque |
| 163 | +from itertools import cycle |
| 164 | +from itertools import pairwise |
| 165 | +from dataclasses import dataclass |
| 166 | + |
| 167 | + |
| 168 | +class OutOfMoves(Exception): |
| 169 | + """Robot has no moves left.""" |
| 170 | + |
| 171 | + |
| 172 | +@dataclass |
| 173 | +class Robot: |
| 174 | + name: str |
| 175 | + health: int |
| 176 | + speed: int |
| 177 | + tactics: deque[str] |
| 178 | + |
| 179 | + @classmethod |
| 180 | + def from_dict(cls, dct): |
| 181 | + return cls( |
| 182 | + dct["name"], |
| 183 | + dct["health"], |
| 184 | + dct["speed"], |
| 185 | + deque(dct["tactics"]) |
| 186 | + ) |
| 187 | + |
| 188 | + def attack(self, other, tactics): |
| 189 | + power = tactics[self.tactics.popleft()] |
| 190 | + other.health -= power |
| 191 | + |
| 192 | + @property |
| 193 | + def dead(self): |
| 194 | + return self.health <= 0 |
| 195 | + |
| 196 | + @property |
| 197 | + def win_msg(self): |
| 198 | + return f'{self.name} has won the fight.' |
| 199 | + |
| 200 | + |
| 201 | +def fight(robot_1, robot_2, tactics): |
| 202 | + |
| 203 | + robot_1 = Robot.from_dict(robot_1) |
| 204 | + robot_2 = Robot.from_dict(robot_2) |
| 205 | + |
| 206 | + robots = pairwise(cycle(sorted([robot_1, robot_2], key=lambda r: r.speed, reverse=True))) |
| 207 | + |
| 208 | + for r1, r2 in robots: |
| 209 | + if not (r1.tactics or r2.tactics): |
| 210 | + break |
| 211 | + |
| 212 | + if r1.tactics: |
| 213 | + r1.attack(r2, tactics) |
| 214 | + if r2.dead: |
| 215 | + return r1.win_msg |
| 216 | + |
| 217 | + if r1.health == r2.health: |
| 218 | + return 'The fight was a draw.' |
| 219 | + |
| 220 | + return [r1.win_msg, r2.win_msg][r1.health < r2.health] |
| 221 | + |
0 commit comments