UNPKG

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