index.html

  1. <html>
  2. <head>
  3. <meta charset="utf-8">
  4. <style>
  5. * {
  6. padding: 0;
  7. margin: 0;
  8. }
  9. button {
  10. display: inline-block
  11. }
  12. </style>
  13. </head>
  14. <body>
  15. <div id="output" style="height: 400px; width: 600px; background: #eee">
  16. </div>
  17. <button id="rock" style="height: 40px; width: 80px">石头</button>
  18. <button id="scissor" style="height: 40px; width: 80px">剪刀</button>
  19. <button id="paper" style="height: 40px; width: 80px"></button>
  20. </body>
  21. <script>
  22. const $button = {
  23. rock: document.getElementById('rock'),
  24. scissor: document.getElementById('scissor'),
  25. paper: document.getElementById('paper')
  26. }
  27. const $output = document.getElementById('output')
  28. Object.keys($button).forEach(key => {
  29. $button[key].addEventListener('click', function () {
  30. fetch(`http://${location.host}/game?action=${key}`)
  31. .then((res) => {
  32. return res.text()
  33. })
  34. .then((text) => {
  35. $output.innerHTML += text + '<br/>';
  36. })
  37. })
  38. })
  39. </script>
  40. </html>

index.js

  1. const fs = require('fs');
  2. const game = require('./game')
  3. const koa = require('koa');
  4. const mount = require('koa-mount')
  5. // 玩家胜利次数,如果超过3,则后续往该服务器的请求都返回500
  6. var playerWinCount = 0
  7. // 玩家的上一次游戏动作
  8. var lastPlayerAction = null;
  9. // 玩家连续出同一个动作的次数
  10. var sameCount = 0;
  11. const app = new koa();
  12. app.use(
  13. mount('/favicon.ico', function (ctx) {
  14. // koa比express做了更极致的response处理函数
  15. // 因为koa使用异步函数作为中间件的实现方式
  16. // 所以koa可以在等待所有中间件执行完毕之后再统一处理返回值,因此可以用赋值运算符
  17. ctx.status = 200;
  18. })
  19. )
  20. const gameKoa = new koa();
  21. app.use(
  22. mount('/game', gameKoa)
  23. )
  24. gameKoa.use(
  25. async function (ctx, next) {
  26. if (playerWinCount >= 3) {
  27. ctx.status = 500;
  28. ctx.body = '我不会再玩了!'
  29. return;
  30. }
  31. // 使用await 关键字等待后续中间件执行完成
  32. await next();
  33. // 就能获得一个准确的洋葱模型效果
  34. if (ctx.playerWon) {
  35. playerWinCount++;
  36. }
  37. }
  38. )
  39. gameKoa.use(
  40. async function (ctx, next) {
  41. const query = ctx.query;
  42. const playerAction = query.action;
  43. if (!playerAction) {
  44. ctx.status = 400;
  45. return;
  46. }
  47. if (sameCount == 9) {
  48. ctx.status = 500;
  49. ctx.body = '我不会再玩了!'
  50. }
  51. if (lastPlayerAction == playerAction) {
  52. sameCount++
  53. if (sameCount >= 3) {
  54. ctx.status = 400;
  55. ctx.body = '你作弊!我再也不玩了'
  56. sameCount = 9
  57. return;
  58. }
  59. } else {
  60. sameCount = 0;
  61. }
  62. lastPlayerAction = playerAction;
  63. ctx.playerAction = playerAction
  64. await next();
  65. }
  66. )
  67. gameKoa.use(
  68. async function (ctx, next) {
  69. const playerAction = ctx.playerAction;
  70. const result = game(playerAction);
  71. // 对于一定需要在请求主流程里完成的操作,一定要使用await进行等待
  72. // 否则koa就会在当前事件循环就把http response返回出去了
  73. await new Promise(resolve => {
  74. // 模拟500毫秒后才返回的现象。
  75. setTimeout(() => {
  76. ctx.status = 200;
  77. if (result == 0) {
  78. ctx.body = '平局'
  79. } else if (result == -1) {
  80. ctx.body = '你输了'
  81. } else {
  82. ctx.body = '你赢了'
  83. ctx.playerWon = true;
  84. }
  85. resolve();
  86. }, 500)
  87. })
  88. }
  89. )
  90. app.use(
  91. mount('/', function (ctx) {
  92. ctx.body = fs.readFileSync(__dirname + '/index.html', 'utf-8')
  93. })
  94. )
  95. app.listen(3000);

game.js

  1. module.exports = function (playerAction) {
  2. // 计算电脑出的东西
  3. var computerAction;
  4. var random = Math.random() * 3
  5. if (random < 1) {
  6. computerAction = 'rock'
  7. // console.log('电脑出了石头')
  8. } else if (random > 2) {
  9. computerAction = 'scissor'
  10. // console.log('电脑出了剪刀')
  11. } else {
  12. computerAction = 'paper'
  13. // console.log('电脑出了布')
  14. }
  15. if (computerAction == playerAction) {
  16. return 0;
  17. } else if (
  18. (computerAction == 'rock' && playerAction == 'scissor') ||
  19. (computerAction == 'scissor' && playerAction == 'paper') ||
  20. (computerAction == 'paper' && playerAction == 'rock')
  21. ) {
  22. return -1;
  23. } else {
  24. return 1;
  25. }
  26. }