PageRenderTime 43ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/OOP-Principles/ExamTasksOOP/WarMachines/Program.cs

https://github.com/RosenTodorov/OOP-Principles--High-Quality-Programming-Code
C# | 757 lines | 620 code | 137 blank | 0 comment | 43 complexity | 75385e6b058825cfcdcc43ebf7fb676b MD5 | raw file
Possible License(s): CPL-1.0, GPL-3.0, Apache-2.0
  1. namespace WarMachines.Engine
  2. {
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using WarMachines.Interfaces;
  7. using WarMachines.Machines;
  8. using WarMachines.Pilot;
  9. using System.Text;
  10. public class Command : ICommand
  11. {
  12. private const char SplitCommandSymbol = ' ';
  13. private string name;
  14. private IList<string> parameters;
  15. private Command(string input)
  16. {
  17. this.TranslateInput(input);
  18. }
  19. public string Name
  20. {
  21. get
  22. {
  23. return this.name;
  24. }
  25. private set
  26. {
  27. if (string.IsNullOrEmpty(value))
  28. {
  29. throw new ArgumentNullException("Name cannot be null or empty.");
  30. }
  31. this.name = value;
  32. }
  33. }
  34. public IList<string> Parameters
  35. {
  36. get
  37. {
  38. return this.parameters;
  39. }
  40. private set
  41. {
  42. if (value == null)
  43. {
  44. throw new ArgumentNullException("List of strings cannot be null.");
  45. }
  46. this.parameters = value;
  47. }
  48. }
  49. public static Command Parse(string input)
  50. {
  51. return new Command(input);
  52. }
  53. private void TranslateInput(string input)
  54. {
  55. var indexOfFirstSeparator = input.IndexOf(SplitCommandSymbol);
  56. this.Name = input.Substring(0, indexOfFirstSeparator);
  57. this.Parameters = input.Substring(indexOfFirstSeparator + 1).Split(new[] { SplitCommandSymbol }, StringSplitOptions.RemoveEmptyEntries);
  58. }
  59. }
  60. public class MachineFactory : IMachineFactory
  61. {
  62. public IPilot HirePilot(string name)
  63. {
  64. return new Pilot(name);
  65. }
  66. public ITank ManufactureTank(string name, double attackPoints, double defensePoints)
  67. {
  68. return new Tank(name, attackPoints, defensePoints);
  69. }
  70. public IFighter ManufactureFighter(string name, double attackPoints, double defensePoints, bool stealthMode)
  71. {
  72. return new Fighter(name, attackPoints, defensePoints, stealthMode);
  73. }
  74. }
  75. public sealed class WarMachineEngine : IWarMachineEngine
  76. {
  77. private const string InvalidCommand = "Invalid command name: {0}";
  78. private const string PilotHired = "Pilot {0} hired";
  79. private const string PilotExists = "Pilot {0} is hired already";
  80. private const string TankManufactured = "Tank {0} manufactured - attack: {1}; defense: {2}";
  81. private const string FighterManufactured = "Fighter {0} manufactured - attack: {1}; defense: {2}; stealth: {3}";
  82. private const string MachineExists = "Machine {0} is manufactured already";
  83. private const string MachineHasPilotAlready = "Machine {0} is already occupied";
  84. private const string PilotNotFound = "Pilot {0} could not be found";
  85. private const string MachineNotFound = "Machine {0} could not be found";
  86. private const string MachineEngaged = "Pilot {0} engaged machine {1}";
  87. private const string InvalidMachineOperation = "Machine {0} does not support this operation";
  88. private const string FighterOperationSuccessful = "Fighter {0} toggled stealth mode";
  89. private const string TankOperationSuccessful = "Tank {0} toggled defense mode";
  90. private const string InvalidAttackTarget = "Tank {0} cannot attack stealth fighter {1}";
  91. private const string AttackSuccessful = "Machine {0} was attacked by machine {1} - current health: {2}";
  92. private static readonly WarMachineEngine SingleInstance = new WarMachineEngine();
  93. private IMachineFactory factory;
  94. private IDictionary<string, IPilot> pilots;
  95. private IDictionary<string, IMachine> machines;
  96. private WarMachineEngine()
  97. {
  98. this.factory = new MachineFactory();
  99. this.pilots = new Dictionary<string, IPilot>();
  100. this.machines = new Dictionary<string, IMachine>();
  101. }
  102. public static WarMachineEngine Instance
  103. {
  104. get
  105. {
  106. return SingleInstance;
  107. }
  108. }
  109. public void Start()
  110. {
  111. var commands = this.ReadCommands();
  112. var commandResult = this.ProcessCommands(commands);
  113. this.PrintReports(commandResult);
  114. }
  115. private IList<ICommand> ReadCommands()
  116. {
  117. var commands = new List<ICommand>();
  118. var currentLine = Console.ReadLine();
  119. while (!string.IsNullOrEmpty(currentLine))
  120. {
  121. var currentCommand = Command.Parse(currentLine);
  122. commands.Add(currentCommand);
  123. currentLine = Console.ReadLine();
  124. }
  125. return commands;
  126. }
  127. private IList<string> ProcessCommands(IList<ICommand> commands)
  128. {
  129. var reports = new List<string>();
  130. foreach (var command in commands)
  131. {
  132. string commandResult;
  133. switch (command.Name)
  134. {
  135. case "HirePilot":
  136. var pilotName = command.Parameters[0];
  137. commandResult = this.HirePilot(pilotName);
  138. reports.Add(commandResult);
  139. break;
  140. case "Report":
  141. var pilotReporting = command.Parameters[0];
  142. commandResult = this.PilotReport(pilotReporting);
  143. reports.Add(commandResult);
  144. break;
  145. case "ManufactureTank":
  146. var tankName = command.Parameters[0];
  147. var tankAttackPoints = double.Parse(command.Parameters[1]);
  148. var tankDefensePoints = double.Parse(command.Parameters[2]);
  149. commandResult = this.ManufactureTank(tankName, tankAttackPoints, tankDefensePoints);
  150. reports.Add(commandResult);
  151. break;
  152. case "DefenseMode":
  153. var defenseModeTankName = command.Parameters[0];
  154. commandResult = this.ToggleTankDefenseMode(defenseModeTankName);
  155. reports.Add(commandResult);
  156. break;
  157. case "ManufactureFighter":
  158. var fighterName = command.Parameters[0];
  159. var fighterAttackPoints = double.Parse(command.Parameters[1]);
  160. var fighterDefensePoints = double.Parse(command.Parameters[2]);
  161. var fighterStealthMode = command.Parameters[3] == "StealthON" ? true : false;
  162. commandResult = this.ManufactureFighter(fighterName, fighterAttackPoints, fighterDefensePoints, fighterStealthMode);
  163. reports.Add(commandResult);
  164. break;
  165. case "StealthMode":
  166. var stealthModeFighterName = command.Parameters[0];
  167. commandResult = this.ToggleFighterStealthMode(stealthModeFighterName);
  168. reports.Add(commandResult);
  169. break;
  170. case "Engage":
  171. var selectedPilotName = command.Parameters[0];
  172. var selectedMachineName = command.Parameters[1];
  173. commandResult = this.EngageMachine(selectedPilotName, selectedMachineName);
  174. reports.Add(commandResult);
  175. break;
  176. case "Attack":
  177. var attackingMachine = command.Parameters[0];
  178. var defendingMachine = command.Parameters[1];
  179. commandResult = this.AttackMachines(attackingMachine, defendingMachine);
  180. reports.Add(commandResult);
  181. break;
  182. default:
  183. reports.Add(string.Format(InvalidCommand, command.Name));
  184. break;
  185. }
  186. }
  187. return reports;
  188. }
  189. private void PrintReports(IList<string> reports)
  190. {
  191. var output = new StringBuilder();
  192. foreach (var report in reports)
  193. {
  194. output.AppendLine(report);
  195. }
  196. Console.Write(output.ToString());
  197. }
  198. private string HirePilot(string name)
  199. {
  200. if (this.pilots.ContainsKey(name))
  201. {
  202. return string.Format(PilotExists, name);
  203. }
  204. var pilot = this.factory.HirePilot(name);
  205. this.pilots.Add(name, pilot);
  206. return string.Format(PilotHired, name);
  207. }
  208. private string ManufactureTank(string name, double attackPoints, double defensePoints)
  209. {
  210. if (this.machines.ContainsKey(name))
  211. {
  212. return string.Format(MachineExists, name);
  213. }
  214. var tank = this.factory.ManufactureTank(name, attackPoints, defensePoints);
  215. this.machines.Add(name, tank);
  216. return string.Format(TankManufactured, name, attackPoints, defensePoints);
  217. }
  218. private string ManufactureFighter(string name, double attackPoints, double defensePoints, bool stealthMode)
  219. {
  220. if (this.machines.ContainsKey(name))
  221. {
  222. return string.Format(MachineExists, name);
  223. }
  224. var fighter = this.factory.ManufactureFighter(name, attackPoints, defensePoints, stealthMode);
  225. this.machines.Add(name, fighter);
  226. return string.Format(FighterManufactured, name, attackPoints, defensePoints, stealthMode == true ? "ON" : "OFF");
  227. }
  228. private string EngageMachine(string selectedPilotName, string selectedMachineName)
  229. {
  230. if (!this.pilots.ContainsKey(selectedPilotName))
  231. {
  232. return string.Format(PilotNotFound, selectedPilotName);
  233. }
  234. if (!this.machines.ContainsKey(selectedMachineName))
  235. {
  236. return string.Format(MachineNotFound, selectedMachineName);
  237. }
  238. if (this.machines[selectedMachineName].Pilot != null)
  239. {
  240. return string.Format(MachineHasPilotAlready, selectedMachineName);
  241. }
  242. var pilot = this.pilots[selectedPilotName];
  243. var machine = this.machines[selectedMachineName];
  244. pilot.AddMachine(machine);
  245. machine.Pilot = pilot;
  246. return string.Format(MachineEngaged, selectedPilotName, selectedMachineName);
  247. }
  248. private string AttackMachines(string attackingMachineName, string defendingMachineName)
  249. {
  250. if (!this.machines.ContainsKey(attackingMachineName))
  251. {
  252. return string.Format(MachineNotFound, attackingMachineName);
  253. }
  254. if (!this.machines.ContainsKey(defendingMachineName))
  255. {
  256. return string.Format(MachineNotFound, defendingMachineName);
  257. }
  258. var attackingMachine = this.machines[attackingMachineName];
  259. var defendingMachine = this.machines[defendingMachineName];
  260. if (attackingMachine is ITank && defendingMachine is IFighter && (defendingMachine as IFighter).StealthMode)
  261. {
  262. return string.Format(InvalidAttackTarget, attackingMachineName, defendingMachineName);
  263. }
  264. attackingMachine.Targets.Add(defendingMachineName);
  265. var attackPoints = attackingMachine.AttackPoints;
  266. var defensePoints = defendingMachine.DefensePoints;
  267. var damage = attackPoints - defensePoints;
  268. if (damage > 0)
  269. {
  270. var newHeathPoints = defendingMachine.HealthPoints - damage;
  271. if (newHeathPoints < 0)
  272. {
  273. newHeathPoints = 0;
  274. }
  275. defendingMachine.HealthPoints = newHeathPoints;
  276. }
  277. return string.Format(AttackSuccessful, defendingMachineName, attackingMachineName, defendingMachine.HealthPoints);
  278. }
  279. private string PilotReport(string pilotReporting)
  280. {
  281. if (!this.pilots.ContainsKey(pilotReporting))
  282. {
  283. return string.Format(PilotNotFound, pilotReporting);
  284. }
  285. return this.pilots[pilotReporting].Report();
  286. }
  287. private string ToggleFighterStealthMode(string stealthModeFighterName)
  288. {
  289. if (!this.machines.ContainsKey(stealthModeFighterName))
  290. {
  291. return string.Format(MachineNotFound, stealthModeFighterName);
  292. }
  293. if (this.machines[stealthModeFighterName] is ITank)
  294. {
  295. return string.Format(InvalidMachineOperation, stealthModeFighterName);
  296. }
  297. var machineAsFighter = this.machines[stealthModeFighterName] as IFighter;
  298. machineAsFighter.ToggleStealthMode();
  299. return string.Format(FighterOperationSuccessful, stealthModeFighterName);
  300. }
  301. private string ToggleTankDefenseMode(string defenseModeTankName)
  302. {
  303. if (!this.machines.ContainsKey(defenseModeTankName))
  304. {
  305. return string.Format(MachineNotFound, defenseModeTankName);
  306. }
  307. if (this.machines[defenseModeTankName] is IFighter)
  308. {
  309. return string.Format(InvalidMachineOperation, defenseModeTankName);
  310. }
  311. var machineAsFighter = this.machines[defenseModeTankName] as ITank;
  312. machineAsFighter.ToggleDefenseMode();
  313. return string.Format(TankOperationSuccessful, defenseModeTankName);
  314. }
  315. }
  316. }
  317. namespace WarMachines.Interfaces
  318. {
  319. using System.Collections.Generic;
  320. public interface ICommand
  321. {
  322. string Name { get; }
  323. IList<string> Parameters { get; }
  324. }
  325. public interface IFighter : IMachine
  326. {
  327. bool StealthMode { get; }
  328. void ToggleStealthMode();
  329. }
  330. public interface IMachine
  331. {
  332. string Name { get; set; }
  333. IPilot Pilot { get; set; }
  334. double HealthPoints { get; set; }
  335. double AttackPoints { get; }
  336. double DefensePoints { get; }
  337. IList<string> Targets { get; }
  338. void Attack(string target);
  339. string ToString();
  340. }
  341. public interface IMachineFactory
  342. {
  343. IPilot HirePilot(string name);
  344. ITank ManufactureTank(string name, double attackPoints, double defensePoints);
  345. IFighter ManufactureFighter(string name, double attackPoints, double defensePoints, bool stealthMode);
  346. }
  347. public interface IPilot
  348. {
  349. string Name { get; }
  350. void AddMachine(IMachine machine);
  351. string Report();
  352. }
  353. public interface ITank : IMachine
  354. {
  355. bool DefenseMode { get; }
  356. void ToggleDefenseMode();
  357. }
  358. public interface IWarMachineEngine
  359. {
  360. void Start();
  361. }
  362. }
  363. namespace WarMachines.Machines
  364. {
  365. using System;
  366. using System.Collections.Generic;
  367. using System.Linq;
  368. using System.Text;
  369. using WarMachines.Interfaces;
  370. using System.Threading.Tasks;
  371. public class Fighter : Machine, IFighter
  372. {
  373. private bool isStealthModeOn;
  374. public Fighter(string name, double attackPoints, double defensePoints, bool stealthMode)
  375. : base(name, attackPoints, defensePoints)
  376. {
  377. this.HealthPoints = 200;
  378. this.isStealthModeOn = stealthMode;
  379. }
  380. public bool StealthMode
  381. {
  382. get { return this.isStealthModeOn; }
  383. }
  384. public void ToggleStealthMode()
  385. {
  386. if (this.isStealthModeOn)
  387. {
  388. this.isStealthModeOn = false;
  389. }
  390. else
  391. {
  392. this.isStealthModeOn = true;
  393. }
  394. }
  395. }
  396. public abstract class Machine : IMachine
  397. {
  398. private string name;
  399. private IPilot pilot;
  400. private double healthPoints;
  401. private double attackPoints;
  402. private double defensePoints;
  403. private IList<string> targets;
  404. public Machine(string name, double attackPoints, double defensePoints)
  405. {
  406. this.Name = name;
  407. this.attackPoints = attackPoints;
  408. this.defensePoints = defensePoints;
  409. this.targets = new List<string>();
  410. }
  411. public string Name
  412. {
  413. get { return this.name; }
  414. set
  415. {
  416. if (string.IsNullOrEmpty(value))
  417. {
  418. throw new ArgumentException("The name of the machine can not be empty!");
  419. }
  420. this.name = value;
  421. }
  422. }
  423. public IPilot Pilot
  424. {
  425. get
  426. {
  427. return this.pilot;
  428. }
  429. set
  430. {
  431. if (value == null)
  432. {
  433. throw new ArgumentException("Machine must have a pilot to be engaged!");
  434. }
  435. this.pilot = value;
  436. }
  437. }
  438. public double HealthPoints
  439. {
  440. get
  441. {
  442. return this.healthPoints;
  443. }
  444. set
  445. {
  446. if (string.IsNullOrEmpty(value.ToString()))
  447. {
  448. throw new ArgumentException("Please provide appropriate value for health points");
  449. }
  450. this.healthPoints = value;
  451. }
  452. }
  453. public double AttackPoints
  454. {
  455. get { return this.attackPoints; }
  456. protected set
  457. {
  458. if (string.IsNullOrEmpty(value.ToString()))
  459. {
  460. throw new ArgumentException("Please provide appropriate value for attack points");
  461. }
  462. this.attackPoints = value;
  463. }
  464. }
  465. public double DefensePoints
  466. {
  467. get { return this.defensePoints; }
  468. protected set
  469. {
  470. if (string.IsNullOrEmpty(value.ToString()))
  471. {
  472. throw new ArgumentException("Please provide appropriate value for defense points");
  473. }
  474. this.defensePoints = value;
  475. }
  476. }
  477. public IList<string> Targets
  478. {
  479. get { return this.targets; }
  480. }
  481. public void Attack(string target)
  482. {
  483. this.targets.Add(target);
  484. }
  485. public override string ToString()
  486. {
  487. return base.ToString();
  488. }
  489. public string ListMachineTargets()
  490. {
  491. var targs = new StringBuilder();
  492. if (this.targets.Count > 0)
  493. {
  494. foreach (var targ in this.targets)
  495. {
  496. targs.AppendFormat("{0}, ", targ);
  497. }
  498. }
  499. else
  500. {
  501. targs.Append("None");
  502. }
  503. string result = targs.ToString().Trim();
  504. return result.TrimEnd(',');
  505. }
  506. }
  507. public class Tank : Machine, ITank
  508. {
  509. private bool defenseMode;
  510. public Tank(string name, double attackPoints, double defensePoints)
  511. : base(name, attackPoints, defensePoints)
  512. {
  513. this.HealthPoints = 100;
  514. this.defenseMode = true;
  515. this.AttackPoints -= 40;
  516. this.DefensePoints += 30;
  517. }
  518. public bool DefenseMode
  519. {
  520. get { return this.defenseMode; }
  521. }
  522. public void ToggleDefenseMode()
  523. {
  524. if (this.DefenseMode)
  525. {
  526. this.defenseMode = false;
  527. this.DefensePoints -= 30;
  528. this.AttackPoints += 40;
  529. }
  530. else
  531. {
  532. this.defenseMode = true;
  533. this.DefensePoints += 30;
  534. this.AttackPoints -= 40;
  535. }
  536. }
  537. }
  538. }
  539. namespace WarMachines.Pilot
  540. {
  541. using System;
  542. using System.Collections.Generic;
  543. using System.Linq;
  544. using System.Text;
  545. using System.Threading.Tasks;
  546. using WarMachines.Interfaces;
  547. using WarMachines.Machines;
  548. public class Pilot : IPilot
  549. {
  550. private string name;
  551. private IList<Machine> engagedMachines;
  552. public Pilot(string name)
  553. {
  554. this.name = name;
  555. this.engagedMachines = new List<Machine>();
  556. }
  557. public string Name
  558. {
  559. get { return this.name; }
  560. }
  561. public void AddMachine(IMachine machine)
  562. {
  563. this.engagedMachines.Add((Machine)machine);
  564. }
  565. public string Report()
  566. {
  567. return this.ToString();
  568. }
  569. public override string ToString()
  570. {
  571. var output = new StringBuilder();
  572. output.Append(this.Name);
  573. int machinesCount = this.engagedMachines.Count;
  574. if (machinesCount == 0)
  575. {
  576. output.AppendLine(" - no machines");
  577. }
  578. else if (machinesCount == 1)
  579. {
  580. output.AppendLine(" - 1 machine");
  581. }
  582. else
  583. {
  584. output.AppendLine(" - " + machinesCount + " machines");
  585. }
  586. if (machinesCount >= 1)
  587. {
  588. foreach (var mac in engagedMachines)
  589. {
  590. output.AppendLine("- " + mac.Name);
  591. output.AppendLine(" *Type: " + mac.GetType().Name);
  592. output.AppendLine(" *Health: " + mac.HealthPoints);
  593. output.AppendLine(" *Attack: " + mac.AttackPoints);
  594. output.AppendLine(" *Defense: " + mac.DefensePoints);
  595. output.AppendLine(" *Targets: " + mac.ListMachineTargets());
  596. if (mac is IFighter)
  597. {
  598. output.AppendLine(((IFighter)mac).StealthMode ? " *Stealth: ON" : " *Stealth: OFF");
  599. }
  600. if (mac is ITank)
  601. {
  602. output.AppendLine(((ITank)mac).DefenseMode ? " *Defense: ON" : " *Defense: OFF");
  603. }
  604. }
  605. }
  606. return output.ToString().Trim();
  607. }
  608. }
  609. }
  610. namespace WarMachines
  611. {
  612. using WarMachines.Engine;
  613. public class WarMachinesProgram
  614. {
  615. public static void Main()
  616. {
  617. WarMachineEngine.Instance.Start();
  618. }
  619. }
  620. }