Summary: TicTacToe client implements basic operation to play Tic Tac Toe Reviewed By: passy Differential Revision: D36548545 fbshipit-source-id: cfca5dad4c42efc8272ee1ce7544914451059f14
177 lines
4.7 KiB
JavaScript
177 lines
4.7 KiB
JavaScript
/**
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @format
|
|
*/
|
|
|
|
const {FlipperServerClient} = require('./flipperClient');
|
|
const inquirer = require('inquirer');
|
|
const {player, ticTacToePluginId} = require('./consts');
|
|
|
|
// Built based on https://codeburst.io/building-a-node-js-interactive-cli-3cb80ed76c86
|
|
class TicTacToeClient {
|
|
flipperServerClient = new FlipperServerClient();
|
|
|
|
async init() {
|
|
console.log('Connecting to Flipper Server...');
|
|
await this.flipperServerClient.init();
|
|
console.log('Connected to Flipper Server');
|
|
}
|
|
|
|
printBoard(cells) {
|
|
console.log('| | 0 | 1 | 2 |');
|
|
console.log(`| a | ${cells[0]} | ${cells[1]} | ${cells[2]} |`);
|
|
console.log(`| b | ${cells[3]} | ${cells[4]} | ${cells[5]} |`);
|
|
console.log(`| c | ${cells[6]} | ${cells[7]} | ${cells[8]} |`);
|
|
}
|
|
|
|
async onStateUpdate(clientId, {winner, turn, cells}) {
|
|
try {
|
|
if (winner !== ' ') {
|
|
const {next} = await inquirer.prompt([
|
|
{
|
|
type: 'list',
|
|
name: 'next',
|
|
message: `Game finished! ${
|
|
winner === player
|
|
? 'You won!!! 🥳🎉🎇'
|
|
: 'Not this time, rookie. Try harder.'
|
|
}`,
|
|
choices: ['Try again', 'Exit game'],
|
|
default: 0,
|
|
},
|
|
]);
|
|
|
|
if (next === 'Exit game') {
|
|
process.exit(0);
|
|
return;
|
|
}
|
|
await this.reset(clientId);
|
|
return;
|
|
}
|
|
|
|
this.printBoard(cells);
|
|
|
|
if (turn === player) {
|
|
const {move} = await inquirer.prompt([
|
|
{
|
|
type: 'list',
|
|
name: 'move',
|
|
message: 'Your turn...',
|
|
choices: cells
|
|
.map((value, i) => {
|
|
// 97 - "a" in ASCII, 98 - "b", 99 - "c"
|
|
const code0 = 97 + Math.floor(i / 3);
|
|
const code1 = i % 3;
|
|
const encoded = `${String.fromCharCode(code0)}${code1}`;
|
|
|
|
return value === ' ' ? {name: encoded, value: i} : null;
|
|
})
|
|
.filter((val) => !!val),
|
|
default: 0,
|
|
},
|
|
]);
|
|
this.move(clientId, move);
|
|
return;
|
|
}
|
|
|
|
console.log('Waiting for the mobile player...');
|
|
} catch (e) {
|
|
console.error('TicTacToeClient.onStateUpdate -> error', e);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
async startGame(clientId) {
|
|
console.log('Starting game...');
|
|
const state = await this.flipperServerClient.exec(
|
|
'companion-plugin-subscribe',
|
|
[clientId, ticTacToePluginId, 'state'],
|
|
);
|
|
console.log('Game on!');
|
|
|
|
this.onStateUpdate(clientId, state);
|
|
|
|
this.flipperServerClient.on(
|
|
'companion-plugin-state-update',
|
|
async ({data}) => this.onStateUpdate(clientId, data),
|
|
);
|
|
}
|
|
|
|
async move(clientId, cell) {
|
|
console.log('Sending your move...');
|
|
await this.flipperServerClient.exec('companion-plugin-exec', [
|
|
clientId,
|
|
ticTacToePluginId,
|
|
'makeMove',
|
|
[player, cell],
|
|
]);
|
|
console.log('Sent your move');
|
|
}
|
|
|
|
async reset(clientId) {
|
|
console.log('Restarting...');
|
|
await this.flipperServerClient.exec('companion-plugin-exec', [
|
|
clientId,
|
|
ticTacToePluginId,
|
|
'reset',
|
|
]);
|
|
}
|
|
|
|
async startTicTacToePlugin(clientId) {
|
|
console.log('Querying available plugins...');
|
|
const availablePlugins = await this.flipperServerClient.exec(
|
|
'companion-plugin-list',
|
|
[clientId],
|
|
);
|
|
console.log('Available plugins:', JSON.stringify(availablePlugins));
|
|
|
|
if (
|
|
!availablePlugins.some(({pluginId}) => pluginId === ticTacToePluginId)
|
|
) {
|
|
throw new Error('Tic-Tac-Toe plugin is not supported by the app');
|
|
}
|
|
|
|
console.log('Starting Tic-Tac-Toe plugin...');
|
|
|
|
await this.flipperServerClient.exec('companion-plugin-start', [
|
|
clientId,
|
|
ticTacToePluginId,
|
|
]);
|
|
|
|
console.log('Started Tic-Tac-Toe plugin');
|
|
}
|
|
|
|
async selectClient() {
|
|
console.log('Querying connected clients...');
|
|
const clients = await this.flipperServerClient.exec('client-list', []);
|
|
console.log('Found clients: ', JSON.stringify(clients));
|
|
|
|
if (!clients.length) {
|
|
throw new Error(
|
|
'No clinets connected. Please, start your app and try again.',
|
|
);
|
|
}
|
|
|
|
const {clientId} = await inquirer.prompt([
|
|
{
|
|
type: 'list',
|
|
name: 'clientId',
|
|
message: 'Choose your client (application)',
|
|
choices: clients.map(({id, query}) => ({
|
|
name: `${query.app} (${query.os}) on ${query.device}`,
|
|
value: id,
|
|
})),
|
|
default: 0,
|
|
},
|
|
]);
|
|
|
|
return clientId;
|
|
}
|
|
}
|
|
|
|
module.exports = {TicTacToeClient};
|