Creazione di un gioco da tavolo con gli agenti TensorFlow e Flutter

1. Prima di iniziare

L'incredibile rivoluzione di AlphaGo e AlphaStar ha dimostrato il potenziale dell'utilizzo del machine learning per creare agenti di gioco a livello di supereroi. Creare un piccolo gioco basato sul machine learning è un esercizio divertente per acquisire le abilità necessarie per creare potenti agenti del gioco.

In questo codelab, imparerai a costruire un gioco da tavolo utilizzando:

  • Agente TensorFlow per addestrare un agente di gioco con l'apprendimento per rinforzo
  • Pubblicazione di TensorFlow per la pubblicazione del modello
  • Flutter per creare un'app di gioco da tavolo multipiattaforma

Prerequisiti

  • Conoscenza di base dello sviluppo Flutter con Dart
  • Conoscenza di base del machine learning con TensorFlow, ad esempio addestramento e deployment
  • Conoscenza di base di Python, terminali e Docker

Obiettivi didattici

  • Addestramento di un agente NPC (Non-Player Character Character) utilizzando gli agenti TensorFlow
  • Come pubblicare il modello addestrato utilizzando TensorFlow Serving
  • Come creare un gioco da tavolo Flutter multipiattaforma

Che cosa ti serve

2. The Plane Strike Game

Il gioco creato in questo codelab si chiama "Plane Strike", un piccolo gioco da tavolo a 2 giocatori che ricorda il gioco da tavolo "Battleship". Le regole sono molto semplici:

  • Il giocatore umano gioca contro un agente NPC addestrato dal machine learning. Il giocatore può iniziare il gioco toccando qualsiasi cella nel tabellone dell'agente.
  • All'inizio del gioco, il giocatore umano e l'agente hanno ciascuno un "aereo" (8 celle verdi che formano un "piano", come puoi vedere nel tabellone di un giocatore umano nell'animazione seguente) sulle relative schede; questi "aerei" vengono posizionati in modo casuale, sono visibili solo ai proprietari del tabellone di gioco e nascosti ai loro avversari.
  • Il giocatore umano e l'agente si alternano a colpire una cella del tabellone a vicenda. Il giocatore umano può toccare qualsiasi cella nella bacheca dell'agente, mentre l'agente farà automaticamente la scelta in base alla previsione di un modello di machine learning. La cella che hai tentato di eseguire diventa rossa se si tratta di un "piano" cella ("hit"), altrimenti diventa giallo ("miss").
  • Vince la partita chi raggiunge 8 globuli rossi per primo; il gioco viene riavviato con nuovi tabelloni.

Ecco un esempio di gameplay:

77cead530c5a4aff.gif

3. Configura l'ambiente di sviluppo di Flutter

Per lo sviluppo di Flutter, hai bisogno di due parti di software per completare questo codelab: l'SDK Flutter e un editor.

Puoi eseguire il codelab utilizzando uno di questi dispositivi:

  • Il simulatore iOS (richiede l'installazione degli strumenti Xcode).
  • L'emulatore Android (richiede la configurazione in Android Studio).
  • Un browser (per il debug è richiesto Chrome).
  • Come applicazione desktop Windows, Linux o macOS. Devi svilupparle sulla piattaforma in cui prevedi di eseguire il deployment. Quindi, se vuoi sviluppare un'app desktop per Windows, devi sviluppare su Windows per accedere alla catena di build appropriata. Alcuni requisiti specifici del sistema operativo sono descritti in dettaglio all'indirizzo docs.flutter.dev/desktop.

4. Configurazione

Per scaricare il codice per questo codelab:

  1. Vai al repository GitHub per questo codelab.
  2. Fai clic su Codice > Scarica il file ZIP per scaricare tutto il codice per questo codelab.

2cd45599f51fb8a2.png

  1. Decomprimi il file ZIP scaricato per aprire una cartella principale codelabs-main con tutte le risorse di cui hai bisogno.

Per questo codelab, ti servono solo i file nella sottodirectory tfagents-flutter/ del repository, che contiene più cartelle:

  • Le cartelle da step0 a step6 contengono il codice iniziale che creerai per ogni passaggio in questo codelab.
  • La cartella finished contiene il codice completato per l'app di esempio completata.
  • Ogni cartella contiene una sottocartella backbend, che include il codice backend, e una sottocartella frontend, che include il codice frontend Flutter

5. Scarica le dipendenze per il progetto

Backend

Apri il terminale e vai alla sottocartella tfagents-flutter. Esegui questo comando:

pip install -r requirements.txt

Frontend

  1. In VS Code, fai clic su File > Apri cartella, quindi seleziona la cartella step0 dal codice sorgente scaricato in precedenza.
  2. Apri il file step0/frontend/lib/main.dart. Se viene visualizzata una finestra di dialogo VS Code che ti chiede di scaricare i pacchetti richiesti per l'app iniziale, fai clic su Ottieni pacchetti.
  3. Se non vedi questa finestra di dialogo, apri il terminale ed esegui il comando flutter pub get nella cartella step0/frontend.

7ada07c300f166a6.png

6. Passaggio 0: esegui l'app iniziale

  1. Apri il file step0/frontend/lib/main.dart in VS Code, assicurati che l'emulatore Android o il simulatore iOS sia configurato correttamente e appaia nella barra di stato.

Ad esempio, ecco cosa vedi quando usi Pixel 5 con l'emulatore Android:

9767649231898791.png

Ecco cosa vedi quando usi iPhone 13 con il Simulatore di iOS:

95529e3a682268b2.png

  1. Fai clic su a19a0c68bc4046e6.png Avvia debug.

Esegui ed esplora l'app

L'app dovrebbe avviarsi sull'emulatore Android o sul simulatore iOS. L'interfaccia utente è piuttosto semplice. Ci sono due tabelloni di gioco; un giocatore può toccare qualsiasi cella del tabellone dell'agente in alto per colpire. Addestrerai un agente intelligente a prevedere automaticamente dove colpire in base al tabellone di un giocatore umano.

Dietro le quinte, l'app Flutter invierà la bacheca corrente del giocatore umano al backend, che esegue un modello di apprendimento per rinforzo e restituisce la posizione prevista della cella per colpire dopo. Il frontend mostrerà il risultato nella UI dopo aver ricevuto la risposta.

734ab3d48a1133e1.png 15cba2e741149c95.png

Se ora fai clic su una cella nella bacheca dell'agente, non succede nulla perché l'app non può ancora comunicare con il backend.

7. Passaggio 1: crea un ambiente Python per gli agenti TensorFlow

L'obiettivo principale di questo codelab è progettare un agente che impari interagendo con un ambiente. Il gioco Plane Strike è relativamente semplice ed è possibile creare regole per l'agente NPC, ma puoi usare l'apprendimento per rinforzo per formare un agente in modo da apprendere le abilità e poter creare facilmente agenti per altri giochi in futuro.

Nell'impostazione standard di apprendimento per rinforzo (RL), l'agente riceve un'osservazione in ogni passo temporale e sceglie un'azione. L'azione viene applicata all'ambiente e quest'ultimo restituisce un premio e una nuova osservazione. L'agente addestra una norma per scegliere le azioni che consentono di massimizzare la somma dei premi, nota anche come restituzione. Giocando molte volte, l'agente è in grado di apprendere gli schemi e di affinare le sue abilità per padroneggiare il gioco. Per formulare il gioco Plane Strike come un problema di RL, pensa allo stato del tabellone come a un'osservazione, alla posizione dello sciopero come all'azione e all'indicatore colpo/mancante come ricompensa.

bc5da07bc45062f4.png

Per addestrare l'agente NPC, puoi usare gli agenti TensorFlow, una libreria di apprendimento per rinforzo affidabile, scalabile e facile da usare per TensorFlow.

TF Agents è ottimo per il reinforcement learning, perché include un ampio set di codelab, esempi e una documentazione completa per aiutarti a iniziare. È possibile utilizzare agenti TF per risolvere problemi RL realistici e complessi con scalabilità e sviluppare rapidamente nuovi algoritmi RL. Puoi passare facilmente tra agenti e algoritmi diversi per la sperimentazione. Inoltre, è ben testato e facile da configurare.

In OpenAI Gym sono implementati molti ambienti di gioco predefiniti (ad es. Atari), Mujuco e così via, che gli agenti TF possono sfruttare facilmente. Tuttavia, poiché il gioco Plane Strike è un gioco completamente personalizzato, devi prima implementare un nuovo ambiente da zero.

Per implementare un ambiente Python con agenti TF, devi implementare i seguenti metodi:

class YourGameEnv(py_environment.PyEnvironment):

  def __init__(self):
    """Initialize environment."""


  def action_spec(self):
    """Return action_spec."""


  def observation_spec(self):
    """Return observation_spec."""


  def _reset(self):
    """Return initial_time_step."""


  def _step(self, action):
    """Apply action and return new time_step."""

La più importante è la funzione _step(), che esegue un'azione e restituisce un nuovo oggetto time_step. Nel caso del gioco Plane Strike, hai un tabellone; quando entra in gioco un nuovo avvertimento, in base alle condizioni del tabellone di gioco, l'ambiente scopre:

  • Come dovrebbe apparire successivamente il tabellone di gioco (la cella deve cambiare di colore in rosso o giallo, data la posizione nascosta del piano?)
  • Quale premio dovrebbe ricevere il giocatore per quella posizione (ricompensa con colpi o penalità per mancare?)
  • Il gioco deve terminare (qualcuno ha vinto?)
  • Aggiungi il seguente codice alla funzione _step() al file _planestrike_py_environment.py:
if self._hit_count == self._plane_size:
    self._episode_ended = True
    return self.reset()

if self._strike_count + 1 == self._max_steps:
    self.reset()
    return ts.termination(
        np.array(self._visible_board, dtype=np.float32), UNFINISHED_GAME_REWARD
    )

self._strike_count += 1
action_x = action // self._board_size
action_y = action % self._board_size
# Hit
if self._hidden_board[action_x][action_y] == HIDDEN_BOARD_CELL_OCCUPIED:
    # Non-repeat move
    if self._visible_board[action_x][action_y] == VISIBLE_BOARD_CELL_UNTRIED:
        self._hit_count += 1
        self._visible_board[action_x][action_y] = VISIBLE_BOARD_CELL_HIT
        # Successful strike
        if self._hit_count == self._plane_size:
            # Game finished
            self._episode_ended = True
            return ts.termination(
                np.array(self._visible_board, dtype=np.float32),
                FINISHED_GAME_REWARD,
            )
        else:
            self._episode_ended = False
            return ts.transition(
                np.array(self._visible_board, dtype=np.float32),
                HIT_REWARD,
                self._discount,
            )
    # Repeat strike
    else:
        self._episode_ended = False
        return ts.transition(
            np.array(self._visible_board, dtype=np.float32),
            REPEAT_STRIKE_REWARD,
            self._discount,
        )
# Miss
else:
    # Unsuccessful strike
    self._episode_ended = False
    self._visible_board[action_x][action_y] = VISIBLE_BOARD_CELL_MISS
    return ts.transition(
        np.array(self._visible_board, dtype=np.float32),
        MISS_REWARD,
        self._discount,

8. Passaggio 2: addestra l'agente di gioco con gli agenti TensorFlow

Con l'ambiente di TF Agents attivo, puoi addestrare l'agente del gioco. Per questo codelab, utilizzerai un agente REINFORCE. REINFORCE è un algoritmo a gradiente di criteri in RL. La sua idea di base è quella di regolare i parametri della rete neurale dei criteri in base agli indicatori di ricompensa raccolti durante il gameplay, in modo che la rete delle norme possa massimizzare il ritorno nelle riproduzioni future.

  • Innanzitutto, devi creare un'istanza per gli ambienti di addestramento e valutazione. Aggiungi questo codice alla funzione train_agent() nel file step2/backend/training.py:
train_py_env = planestrike_py_environment.PlaneStrikePyEnvironment(
    board_size=BOARD_SIZE, discount=DISCOUNT, max_steps=BOARD_SIZE**2
)
eval_py_env = planestrike_py_environment.PlaneStrikePyEnvironment(
    board_size=BOARD_SIZE, discount=DISCOUNT, max_steps=BOARD_SIZE**2
)

train_env = tf_py_environment.TFPyEnvironment(train_py_env)
eval_env = tf_py_environment.TFPyEnvironment(eval_py_env)
  • Poi devi creare un agente di apprendimento per rinforzo che verrà addestrato. In questo codelab, utilizzerai l'agente REINFORCE, un agente basato su criteri. Aggiungi questo codice proprio sotto il codice riportato sopra:
actor_net = tfa.networks.Sequential(
    [
        tfa.keras_layers.InnerReshape([BOARD_SIZE, BOARD_SIZE], [BOARD_SIZE**2]),
        tf.keras.layers.Dense(FC_LAYER_PARAMS, activation="relu"),
        tf.keras.layers.Dense(BOARD_SIZE**2),
        tf.keras.layers.Lambda(lambda t: tfp.distributions.Categorical(logits=t)),
    ],
    input_spec=train_py_env.observation_spec(),
)

optimizer = tf.keras.optimizers.Adam(learning_rate=LEARNING_RATE)

train_step_counter = tf.Variable(0)

tf_agent = reinforce_agent.ReinforceAgent(
    train_env.time_step_spec(),
    train_env.action_spec(),
    actor_network=actor_net,
    optimizer=optimizer,
    normalize_returns=True,
    train_step_counter=train_step_counter,
)
  • Infine, devi addestrare l'agente nel loop di addestramento. Nel loop, per prima cosa raccogli alcune puntate delle partite di gioco in un buffer, quindi addestri l'agente con i dati presenti nel buffer. Aggiungi questo codice alla funzione train_agent() nel file step2/backend/training.py:
# Collect a few episodes using collect_policy and save to the replay buffer.
collect_episode(
    train_py_env,
    collect_policy,
    COLLECT_EPISODES_PER_ITERATION,
    replay_buffer_observer,
)

# Use data from the buffer and update the agent's network.
iterator = iter(replay_buffer.as_dataset(sample_batch_size=1))
trajectories, _ = next(iterator)
tf_agent.train(experience=trajectories)
replay_buffer.clear()
  • Ora puoi iniziare la formazione. Nel terminale, apri la cartella step2/backend sul computer ed esegui:
python training.py

Per completare l'addestramento, sono necessarie 8-12 ore, a seconda delle configurazioni hardware (non è necessario completare l'intero addestramento in autonomia poiché in step3 viene fornito un modello preaddestrato). Nel frattempo, puoi monitorare l'avanzamento con TensorBoard. Apri un nuovo terminale, vai alla cartella step2/backend sul tuo computer ed esegui:

tensorboard --logdir tf_agents_log/

tf_agents_log è la cartella che contiene il log di addestramento. Di seguito è riportato un esempio di esecuzione dell'addestramento:

33e12e2b387c063a.png 8488632ccf43348a.png

Puoi notare che la durata media delle puntate diminuisce e il ritorno medio aumenta con il procedere dell'addestramento. Intuitivamente puoi capire che se l'agente è più intelligente e fa previsioni migliori, la durata del gioco si riduce e l'agente raccoglie più premi. Questo ha senso perché l'agente vuole finire il gioco in meno passaggi per ridurre al minimo gli sconti intensivi sui premi nei passaggi successivi.

Al termine dell'addestramento, il modello addestrato viene esportato nella cartella policy_model.

9. Passaggio 3: esegui il deployment del modello addestrato con la pubblicazione di TensorFlow

Ora che hai addestrato l'agente di gioco, puoi eseguirne il deployment con TensorFlow Serving.

  • Nel terminale, vai alla cartella step3/backend sul tuo computer e avvia TensorFlow Serving con Docker:
docker run -t --rm -p 8501:8501 -p 8500:8500 -v "$(pwd)/backend/policy_model:/models/policy_model" -e MODEL_NAME=policy_model tensorflow/serving

Docker scarica automaticamente prima l'immagine di TensorFlow Serving, che richiede un minuto. Successivamente, verrà avviata la pubblicazione di TensorFlow. Il log dovrebbe essere simile al seguente snippet di codice:

2022-05-30 02:38:54.147771: I tensorflow_serving/model_servers/server.cc:89] Building single TensorFlow model file config:  model_name: policy_model model_base_path: /models/policy_model
2022-05-30 02:38:54.148222: I tensorflow_serving/model_servers/server_core.cc:465] Adding/updating models.
2022-05-30 02:38:54.148273: I tensorflow_serving/model_servers/server_core.cc:591]  (Re-)adding model: policy_model
2022-05-30 02:38:54.262684: I tensorflow_serving/core/basic_manager.cc:740] Successfully reserved resources to load servable {name: policy_model version: 123}
2022-05-30 02:38:54.262768: I tensorflow_serving/core/loader_harness.cc:66] Approving load for servable version {name: policy_model version: 123}
2022-05-30 02:38:54.262787: I tensorflow_serving/core/loader_harness.cc:74] Loading servable version {name: policy_model version: 123}
2022-05-30 02:38:54.265010: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:38] Reading SavedModel from: /models/policy_model/123
2022-05-30 02:38:54.277811: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:90] Reading meta graph with tags { serve }
2022-05-30 02:38:54.278116: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:132] Reading SavedModel debug info (if present) from: /models/policy_model/123
2022-05-30 02:38:54.280229: I external/org_tensorflow/tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
2022-05-30 02:38:54.332352: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:206] Restoring SavedModel bundle.
2022-05-30 02:38:54.337000: I external/org_tensorflow/tensorflow/core/platform/profile_utils/cpu_utils.cc:114] CPU Frequency: 2193480000 Hz
2022-05-30 02:38:54.402803: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:190] Running initialization op on SavedModel bundle at path: /models/policy_model/123
2022-05-30 02:38:54.410707: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:277] SavedModel load for tags { serve }; Status: success: OK. Took 145695 microseconds.
2022-05-30 02:38:54.412726: I tensorflow_serving/servables/tensorflow/saved_model_warmup_util.cc:59] No warmup data file found at /models/policy_model/123/assets.extra/tf_serving_warmup_requests
2022-05-30 02:38:54.417277: I tensorflow_serving/core/loader_harness.cc:87] Successfully loaded servable version {name: policy_model version: 123}
2022-05-30 02:38:54.419846: I tensorflow_serving/model_servers/server_core.cc:486] Finished adding/updating models
2022-05-30 02:38:54.420066: I tensorflow_serving/model_servers/server.cc:367] Profiler service is enabled
2022-05-30 02:38:54.428339: I tensorflow_serving/model_servers/server.cc:393] Running gRPC ModelServer at 0.0.0.0:8500 ...
[warn] getaddrinfo: address family for nodename not supported
2022-05-30 02:38:54.431620: I tensorflow_serving/model_servers/server.cc:414] Exporting HTTP/REST API at:localhost:8501 ...
[evhttp_server.cc : 245] NET_LOG: Entering the event loop ...

Puoi inviare una richiesta di esempio all'endpoint per assicurarti che funzioni come previsto:

curl -d '{"signature_name":"action","instances":[{"0/discount":0.0,"0/observation":[[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,     0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]],"0/reward":0.0,"0/step_type":0}]}'     -X POST http://localhost:8501/v1/models/policy_model:predict

L'endpoint restituirà una posizione prevista 45, ovvero (5, 5) al centro della classifica (per i curiosi, puoi provare a capire perché il centro del tabellone è una buona ipotesi per la posizione del primo avvertimento).

{
    "predictions": [45]
}

È tutto. Hai creato un backend per prevedere la posizione del prossimo avvertimento per l'agente NPC.

10. Passaggio 4: crea l'app Flutter per Android e iOS

Il backend è pronto. Puoi iniziare a inviare richieste per recuperare le previsioni della posizione degli avvertimenti dall'app Flutter.

  • Per prima cosa, devi definire una classe che aggrega gli input da inviare. Aggiungi questo codice al file step4/frontend/lib/game_agent.dart:
class Inputs {
  final List<double> _boardState;
  Inputs(this._boardState);

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = <String, dynamic>{};
    data['0/discount'] = [0.0];
    data['0/observation'] = [_boardState];
    data['0/reward'] = [0.0];
    data['0/step_type'] = [0];
    return data;
  }
}

Ora puoi inviare la richiesta a TensorFlow Serving per eseguire previsioni.

  • Aggiungi questo codice alla funzione predict() nel file step4/frontend/lib/game_agent.dart:
var flattenedBoardState = boardState.expand((i) => i).toList();
final response = await http.post(
  Uri.parse('http://$server:8501/v1/models/policy_model:predict'),
  body: jsonEncode(<String, dynamic>{
    'signature_name': 'action',
    'instances': [Inputs(flattenedBoardState)]
  }),
);

if (response.statusCode == 200) {
  var output = List<int>.from(
      jsonDecode(response.body)['predictions'] as List<dynamic>);
  return output[0];
} else {
  throw Exception('Error response');
}

Quando l'app riceve la risposta dal backend, aggiorni l'UI del gioco in modo che rifletta i relativi progressi.

  • Aggiungi questo codice alla funzione _gridItemTapped() nel file step4/frontend/lib/main.dart:
int agentAction =
    await _policyGradientAgent.predict(_playerVisibleBoardState);
_agentActionX = agentAction ~/ _boardSize;
_agentActionY = agentAction % _boardSize;
if (_playerHiddenBoardState[_agentActionX][_agentActionY] ==
    hiddenBoardCellOccupied) {
  // Non-repeat move
  if (_playerVisibleBoardState[_agentActionX][_agentActionY] ==
      visibleBoardCellUntried) {
    _agentHitCount++;
  }
  _playerVisibleBoardState[_agentActionX][_agentActionY] =
      visibleBoardCellHit;
} else {
  _playerVisibleBoardState[_agentActionX][_agentActionY] =
      visibleBoardCellMiss;
}
setState(() {});

Eseguilo

  1. Fai clic su a19a0c68bc4046e6.png Avvia debug, quindi attendi il caricamento dell'app.
  2. Tocca una cella qualsiasi nella bacheca dell'agente per iniziare il gioco.

852942d0de299c1f.png 6ae3601470c8e33a.png

11. Passaggio 5: attiva l'app Flutter per le piattaforme desktop

Oltre ad Android e iOS, Flutter supporta anche piattaforme desktop come Linux, Mac e Windows.

Linux

  1. Assicurati che il dispositivo di destinazione sia impostato su 86cba523de82b4f9.png nella barra di stato di VSCode.
  2. Fai clic su a19a0c68bc4046e6.png Avvia debug, quindi attendi il caricamento dell'app.
  3. Fai clic su una cella nella bacheca dell'agente per iniziare il gioco.

48594c7c0a589733.png

Mac

  1. Per Mac, devi configurare i diritti appropriati poiché l'app invierà richieste HTTP al backend. Per maggiori dettagli, consulta Diritti e sandbox dell'app.

Aggiungi questo codice rispettivamente a step4/frontend/macOS/Runner/DebugProfile.entitlements e step4/frontend/macOS/Runner/Release.entitlements:

<key>com.apple.security.network.client</key>
<true/>
  1. Assicurati che il dispositivo di destinazione sia impostato su eb4b0b5563824138.png nella barra di stato di VSCode.
  2. Fai clic su a19a0c68bc4046e6.png Avvia debug, quindi attendi il caricamento dell'app.
  3. Fai clic su una cella nella bacheca dell'agente per iniziare il gioco.

55a5de3674194e89.png

Windows

  1. Assicurati che il dispositivo di destinazione sia impostato su 9587be1bb375bc0f.png nella barra di stato di VSCode.
  2. Fai clic su a19a0c68bc4046e6.png Avvia debug, quindi attendi il caricamento dell'app.
  3. Fai clic su una cella nella bacheca dell'agente per iniziare il gioco.

41d9f87d84c5e755.png

12. Passaggio 6: attiva l'app Flutter per la piattaforma web

Un'altra cosa che puoi fare è aggiungere il supporto web all'app Flutter. Per impostazione predefinita, la piattaforma web è abilitata automaticamente per le app Flutter, quindi non devi fare altro che avviarla.

  1. Assicurati che il dispositivo di destinazione sia impostato su 71db93efa928d15d.png nella barra di stato di VSCode.
  2. Fai clic su a19a0c68bc4046e6.png Avvia debug, quindi attendi il caricamento dell'app nel browser Chrome.
  3. Fai clic su una cella nella bacheca dell'agente per iniziare il gioco.

fae7490304e28dfe.png

13. Complimenti

Hai creato un'app per un gioco da tavolo con un agente basato sul machine learning per giocare contro il giocatore umano.

Scopri di più