Files
flipper/desktop/examples/headless-tic-tac-toe/ticTacToeClient.js
Andrey Goncharov 0fcfdef465 Add TicTacToe client to headless tic-tac-toe
Summary: TicTacToe client implements basic operation to play Tic Tac Toe

Reviewed By: passy

Differential Revision: D36548545

fbshipit-source-id: cfca5dad4c42efc8272ee1ce7544914451059f14
2022-05-23 08:06:18 -07:00

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};