index.ts 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. type PlayerOne = {
  2. kind: "playerOne";
  3. name: string;
  4. };
  5. type PlayerTwo = {
  6. kind: "playerTwo";
  7. name: string;
  8. };
  9. type Player = PlayerOne | PlayerTwo;
  10. type Point = "love" | "15" | "30";
  11. type Deuce = {
  12. kind: "deuce";
  13. };
  14. type PointsData = {
  15. kind: "points";
  16. playerOnePoint: Point;
  17. playerTwoPoint: Point;
  18. };
  19. type FortyData = {
  20. kind: "forty";
  21. player: Player;
  22. otherPlayerPoint: Point;
  23. };
  24. type Advantage = {
  25. kind: "advantage",
  26. player: Player
  27. };
  28. type Game = {
  29. kind: "game",
  30. player: Player
  31. };
  32. type Score = Deuce | PointsData | FortyData | Advantage | Game;
  33. function scoreWhenDeuce(_score: Deuce, player: Player): Advantage {
  34. return {
  35. kind: "advantage",
  36. player
  37. };
  38. }
  39. function scoreWhenAdvantage(score: Advantage, player: Player): Game | Deuce {
  40. return player.kind === score.player.kind ?
  41. {
  42. kind: "game",
  43. player: score.player
  44. } :
  45. {
  46. kind: "deuce"
  47. };
  48. }
  49. function incrementPoint(point: Point): "15" | "30" | undefined {
  50. switch (point) {
  51. case "love":
  52. return "15";
  53. case "15":
  54. return "30";
  55. case "30":
  56. return undefined;
  57. }
  58. }
  59. function scoreWhenForty(score: FortyData, player: Player): Game | Deuce | FortyData {
  60. if (score.player.kind === player.kind) {
  61. return {
  62. kind: "game",
  63. player: player
  64. };
  65. } else {
  66. const newPoints: Point | undefined = incrementPoint(score.otherPlayerPoint);
  67. return (newPoints === undefined) ?
  68. { kind: "deuce" } :
  69. {...score, otherPlayerPoint: newPoints};
  70. }
  71. }
  72. function updatePointsData(score: PointsData, newPoints: Point, player: Player): PointsData {
  73. switch (player.kind) {
  74. case "playerOne":
  75. return {...score, playerOnePoint: newPoints};
  76. case "playerTwo":
  77. return {...score, playerTwoPoint: newPoints};
  78. }
  79. }
  80. function createFortyData(score: PointsData, player: Player): FortyData {
  81. const otherPlayerPoint: Point = player.kind === "playerOne" ? score.playerTwoPoint : score.playerOnePoint;
  82. return {
  83. kind: "forty",
  84. player,
  85. otherPlayerPoint
  86. };
  87. }
  88. function scoreWhenPoints(score: PointsData, player: Player): PointsData | FortyData {
  89. const newPoints: Point | undefined = player.kind === "playerOne" ?
  90. incrementPoint(score.playerOnePoint) :
  91. incrementPoint(score.playerTwoPoint);
  92. return newPoints === undefined ?
  93. createFortyData(score, player) :
  94. updatePointsData(score, newPoints, player);
  95. }
  96. function score(score: Score, player: Player): Score {
  97. switch (score.kind) {
  98. case "points":
  99. return scoreWhenPoints(score, player);
  100. case "forty":
  101. return scoreWhenForty(score, player);
  102. case "deuce":
  103. return scoreWhenDeuce(score, player);
  104. case "advantage":
  105. return scoreWhenAdvantage(score, player);
  106. case "game":
  107. return score;
  108. }
  109. }