ping 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. #!/usr/bin/env node
  2. /**
  3. * ping
  4. * https://github.com/chjj/blessed
  5. * Copyright (c) 2013, Christopher Jeffrey (MIT License)
  6. * Online (ping)pong in your terminal.
  7. */
  8. // Example Usage:
  9. // Server: $ ./example/ping 3000
  10. // Client: $ ./example/ping 127.0.0.1 3000
  11. // Demo: $ ./example/ping
  12. process.title = 'ping';
  13. if (/^(-h|--help|-\?)$/.test(process.argv[2])) {
  14. console.log('node-ping');
  15. console.log('Example Usage:');
  16. console.log('Server: $ node-ping 3000');
  17. console.log('Client: $ node-ping 127.0.0.1 3000');
  18. console.log('Demo: $ node-ping');
  19. return process.exit(0);
  20. }
  21. var blessed = require('blessed')
  22. , nssocket;
  23. try {
  24. nssocket = require('nssocket');
  25. } catch (e) {
  26. ;
  27. }
  28. var server
  29. , socket;
  30. /**
  31. * Screen Layout
  32. */
  33. var screen = blessed.screen();
  34. var table = blessed.box({
  35. left: 0,
  36. top: 0,
  37. width: screen.width,
  38. height: screen.height
  39. });
  40. var ball = blessed.box({
  41. width: 1,
  42. height: 1,
  43. bg: 'white',
  44. top: 0,
  45. left: 0
  46. });
  47. var lpaddle = blessed.box({
  48. width: 1,
  49. height: 3,
  50. bg: 'yellow',
  51. top: 0,
  52. left: 0
  53. });
  54. var rpaddle = blessed.box({
  55. width: 1,
  56. height: 3,
  57. bg: 'yellow',
  58. top: 0,
  59. right: 0
  60. });
  61. var score = blessed.box({
  62. top: 0,
  63. left: 4,
  64. height: 3,
  65. width: 'shrink',
  66. border: {
  67. type: 'line'
  68. },
  69. //align: 'center',
  70. style: {
  71. bold: true
  72. },
  73. tags: true
  74. });
  75. score.lwins = 0;
  76. score.rwins = 0;
  77. var net = blessed.box({
  78. width: 1,
  79. height: '100%',
  80. bg: 'yellow',
  81. top: 0,
  82. left: 'center'
  83. });
  84. var message = blessed.box({
  85. width: '50%',
  86. height: 3,
  87. border: {
  88. type: 'line'
  89. },
  90. top: 'center',
  91. left: 'center'
  92. });
  93. var text = blessed.box({
  94. top: 'center',
  95. left: 1,
  96. right: 1,
  97. height: 1,
  98. align: 'center',
  99. content: 'Waiting for players to connect...'
  100. });
  101. message.append(text);
  102. screen.append(table);
  103. table.append(score);
  104. table.append(lpaddle);
  105. table.append(rpaddle);
  106. table.append(net);
  107. table.append(ball);
  108. table.append(message);
  109. screen.on('resize', function() {
  110. table.width = screen.width;
  111. table.height = screen.height;
  112. [ball, lpaddle, rpaddle].forEach(function(el) {
  113. if (el.rbottom < 0) el.rtop = table.height - 1 - el.height;
  114. if (el.rright < 0) el.rleft = table.width - 1;
  115. });
  116. screen.render();
  117. sync();
  118. });
  119. /**
  120. * Options
  121. */
  122. ball.speed = 2;
  123. ball.unpredictable = true;
  124. lpaddle.speed = 2;
  125. rpaddle.speed = 2;
  126. /**
  127. * Game
  128. */
  129. function sync() {
  130. if (!socket) return;
  131. socket.send(['update'], {
  132. table: { width: table.width, height: table.height },
  133. lpaddle: { rleft: lpaddle.rleft, rtop: lpaddle.rtop, speed: lpaddle.speed },
  134. rpaddle: { rleft: rpaddle.rleft, rtop: rpaddle.rtop, speed: rpaddle.speed },
  135. score: { lwins: score.lwins, rwins: score.rwins }
  136. });
  137. }
  138. function reset() {
  139. text.setContent('Waiting for players to connect...');
  140. message.hide();
  141. ball.moving = true;
  142. ball.direction = 'right';
  143. ball.angle = 'down';
  144. ball.rtop = 1;
  145. ball.rleft = 1;
  146. if ((score.lwins + score.rwins) % 2 !== 0) {
  147. ball.direction = 'left';
  148. ball.rleft = table.width - 1;
  149. }
  150. lpaddle.rtop = 0;
  151. rpaddle.rtop = 0;
  152. score.setContent('{green-fg}Score:{/} ' + score.lwins + ' | ' + score.rwins);
  153. rpaddle.movable = true;
  154. screen.render();
  155. if (server && socket) {
  156. socket.send(['reset']);
  157. }
  158. }
  159. function rand(min, max) {
  160. return Math.floor(Math.random() * (max - min + 1)) + min;
  161. }
  162. function startGame() {
  163. reset();
  164. if (startGame._bound) return;
  165. startGame._bound = true;
  166. screen.on('keypress', function(ch, key) {
  167. if (!ball.moving) return;
  168. if (key.name === 'up' || key.name === 'k') {
  169. if (socket) socket.send(['up']);
  170. if (lpaddle.rtop > 0) lpaddle.rtop -= lpaddle.speed;
  171. if (!socket) if (rpaddle.rtop > 0) rpaddle.rtop -= rpaddle.speed;
  172. if (lpaddle.rtop < 0) lpaddle.rtop = 0;
  173. if (rpaddle.rtop < 0) rpaddle.rtop = 0;
  174. screen.render();
  175. } else if (key.name === 'down' || key.name === 'j') {
  176. if (socket) socket.send(['down']);
  177. if (lpaddle.rbottom > 0) lpaddle.rtop += lpaddle.speed;
  178. if (!socket) if (rpaddle.rbottom > 0) rpaddle.rtop += rpaddle.speed;
  179. if (lpaddle.rbottom < 0) lpaddle.rtop = table.height - lpaddle.height - 1;
  180. if (rpaddle.rbottom < 0) rpaddle.rtop = table.height - rpaddle.height - 1;
  181. screen.render();
  182. }
  183. });
  184. setInterval(function() {
  185. if (!ball.moving) return;
  186. if (ball.direction === 'right') {
  187. if (ball.rright > 1) {
  188. ball.rleft += ball.speed;
  189. } else {
  190. if (ball.rtop >= rpaddle.rtop && ball.rtop <= rpaddle.rtop + rpaddle.height) {
  191. ball.direction = 'left';
  192. ball.rleft -= ball.speed;
  193. ball.rleft -= rand(0, 3);
  194. if (ball.angle === 'down') ball.rtop += rand(0, 3);
  195. else if (ball.angle === 'up') ball.rtop -= rand(0, 3);
  196. } else {
  197. // Right loses
  198. score.lwins++;
  199. ball.rleft = table.width - 1;
  200. if (socket) socket.send(['lose']);
  201. ball.moving = false;
  202. text.setContent('Right player loses!');
  203. message.show();
  204. setTimeout(reset, 3000);
  205. screen.render();
  206. return;
  207. }
  208. }
  209. if (ball.rright < 1) ball.rleft = table.width - 2;
  210. } else if (ball.direction === 'left') {
  211. if (ball.rleft > 1) {
  212. ball.rleft -= ball.speed;
  213. } else {
  214. if (ball.rtop >= lpaddle.rtop && ball.rtop <= lpaddle.rtop + lpaddle.height) {
  215. ball.direction = 'right';
  216. ball.rleft += ball.speed;
  217. ball.rleft += rand(0, 3);
  218. if (ball.angle === 'down') ball.rtop += rand(0, 3);
  219. else if (ball.angle === 'up') ball.rtop -= rand(0, 3);
  220. } else {
  221. // Left loses
  222. score.rwins++;
  223. ball.rleft = 0;
  224. if (socket) socket.send(['win']);
  225. ball.moving = false;
  226. text.setContent('Left player loses!');
  227. message.show();
  228. setTimeout(reset, 3000);
  229. screen.render();
  230. return;
  231. }
  232. }
  233. if (ball.rleft < 1) ball.rleft = 1;
  234. }
  235. if (ball.angle === 'down') {
  236. if (ball.rbottom > 0) {
  237. ball.rtop++;
  238. if (ball.unpredictable) ball.rtop += rand(0, 3);
  239. } else {
  240. ball.angle = 'up';
  241. ball.rtop--;
  242. }
  243. } else if (ball.angle === 'up') {
  244. if (ball.rtop > 0) {
  245. ball.rtop--;
  246. if (ball.unpredictable) ball.rtop -= rand(0, 3);
  247. } else {
  248. ball.angle = 'down';
  249. ball.rtop++;
  250. }
  251. }
  252. if (ball.rtop < 0) ball.rtop = 0;
  253. if (ball.rbottom < 0) ball.rtop = table.height - 1;
  254. if (socket) socket.send(['ball'], { rleft: ball.rleft, rtop: ball.rtop });
  255. screen.render();
  256. }, 100);
  257. }
  258. function startServer() {
  259. server = nssocket.createServer({}, function(socket_) {
  260. socket = socket_;
  261. sync();
  262. socket.data(['up'], function() {
  263. if (!ball.moving) return;
  264. if (rpaddle.rtop > 0) rpaddle.rtop -= rpaddle.speed;
  265. screen.render();
  266. });
  267. socket.data(['down'], function() {
  268. if (!ball.moving) return;
  269. if (rpaddle.rtop < table.height - 1) rpaddle.rtop += rpaddle.speed;
  270. screen.render();
  271. });
  272. socket.on('error', function() {
  273. socket = null;
  274. reset();
  275. ball.moving = false;
  276. message.show();
  277. screen.render();
  278. });
  279. startGame();
  280. });
  281. server.listen(+process.argv[2]);
  282. }
  283. function startClient() {
  284. var socket = new nssocket.NsSocket({
  285. reconnect: true,
  286. maxRetries: Infinity,
  287. retryInterval: 5000
  288. });
  289. socket.connect(+process.argv[3], process.argv[2]);
  290. screen.on('keypress', function(ch, key) {
  291. if (!rpaddle.movable) return;
  292. if (key.name === 'up' || key.name === 'k') {
  293. socket.send(['up']);
  294. if (rpaddle.rtop > 0) rpaddle.rtop -= rpaddle.speed;
  295. if (rpaddle.rtop < 0) rpaddle.rtop = 0;
  296. screen.render();
  297. } else if (key.name === 'down' || key.name === 'j') {
  298. socket.send(['down']);
  299. if (rpaddle.rbottom > 0) rpaddle.rtop += rpaddle.speed;
  300. if (rpaddle.rbottom < 0) rpaddle.rtop = table.height - rpaddle.height - 1;
  301. screen.render();
  302. }
  303. });
  304. socket.data(['up'], function() {
  305. if (lpaddle.rtop > 0) lpaddle.rtop -= lpaddle.speed;
  306. screen.render();
  307. });
  308. socket.data(['down'], function() {
  309. if (lpaddle.rtop < table.height - 1) lpaddle.rtop += lpaddle.speed;
  310. screen.render();
  311. });
  312. socket.data(['ball'], function(data) {
  313. ball.rleft = data.rleft;
  314. ball.rtop = data.rtop;
  315. screen.render();
  316. });
  317. socket.data(['update'], function(data) {
  318. if (data.lpaddle) {
  319. lpaddle.rleft = data.lpaddle.rleft;
  320. lpaddle.rtop = data.lpaddle.rtop;
  321. lpaddle.speed = data.lpaddle.speed;
  322. }
  323. if (data.rpaddle) {
  324. rpaddle.rleft = data.rpaddle.rleft;
  325. rpaddle.rtop = data.rpaddle.rtop;
  326. rpaddle.speed = data.rpaddle.speed;
  327. }
  328. if (data.ball) {
  329. ball.moving = data.ball.moving;
  330. ball.rleft = data.ball.rleft;
  331. ball.rtop = data.ball.rtop;
  332. }
  333. if (data.table) {
  334. table.height = data.table.height;
  335. table.width = data.table.width;
  336. }
  337. if (data.score) {
  338. score.lwins = data.score.lwins;
  339. score.rwins = data.score.rwins;
  340. }
  341. screen.render();
  342. });
  343. socket.data(['win'], function() {
  344. rpaddle.movable = false;
  345. score.rwins++;
  346. text.setContent('Left player loses!');
  347. message.show();
  348. screen.render();
  349. });
  350. socket.data(['lose'], function() {
  351. rpaddle.movable = false;
  352. score.lwins++;
  353. text.setContent('Right player loses!');
  354. message.show();
  355. screen.render();
  356. });
  357. socket.data(['reset'], reset);
  358. reset();
  359. }
  360. /**
  361. * Main
  362. */
  363. function main() {
  364. screen.on('keypress', function(ch, key) {
  365. if (key.name === 'q' || key.name === 'escape') {
  366. return process.exit(0);
  367. }
  368. });
  369. screen.render();
  370. // Demo Mode / Single Player
  371. if (!nssocket || !process.argv[2]) return startGame();
  372. // Server Mode
  373. if (!process.argv[3]) return startServer();
  374. // Client Mode
  375. if (process.argv[2] && process.argv[3]) return startClient();
  376. }
  377. /**
  378. * Execute
  379. */
  380. main();