1. Zanim zaczniesz
Niesamowity przełom w przypadku AlphaGo i AlphaStar pokazał potencjał wykorzystania uczenia maszynowego do tworzenia agentów gier na poziomie przekraczającym możliwości człowieka. Stworzenie małej gry opartej na ML to świetne ćwiczenie, które pozwala zdobyć umiejętności potrzebne do tworzenia zaawansowanych agentów w grach.
Z tego ćwiczenia dowiesz się, jak utworzyć grę planszową przy użyciu:
- Agent TensorFlow do trenowania agenta gry za pomocą uczenia ze wzmocnieniem
- TensorFlow Serving do udostępniania modelu
- Flutter do tworzenia aplikacji z grą planszową na wielu platformach
Wymagania wstępne
- Podstawowa znajomość tworzenia aplikacji w Flutterze za pomocą języka Dart.
- Podstawowa wiedza o uczeniu maszynowym za pomocą TensorFlow, np. różnice między trenowaniem a wdrażaniem.
- Podstawowa znajomość Pythona, terminali i Dockera
Czego się nauczysz
- Jak wytrenować agenta postaci niezależnej (NPC) za pomocą agentów TensorFlow
- Jak udostępniać wytrenowany model za pomocą TensorFlow Serving
- Tworzenie gry planszowej na wielu platformach w Flutterze
Czego potrzebujesz
- Pakiet SDK Flutter
- Konfiguracja Android i iOS na potrzeby Fluttera
- Konfiguracja na komputerze w przypadku Fluttera
- Konfigurowanie internetu w przypadku Fluttera
- Konfigurowanie Visual Studio Code (VS Code) na potrzeby Flutter i Dart
- Docker
- Bash
- Python 3.7 lub nowszy
2. The Plane Strike Game
Gra, którą stworzysz w tym ćwiczeniu, to „Plane Strike” – mała gra planszowa dla 2 graczy przypominająca „Bitwę morską”. Zasady są bardzo proste:
- Gracz gra przeciwko agentowi NPC wytrenowanemu przez uczenie maszynowe. Gracz może rozpocząć grę, klikając dowolne pole na planszy agenta.
- Na początku gry gracz i agent mają na swoich planszach obiekt „samolot” (8 zielonych komórek tworzących „samolot”, jak widać na planszy gracza w animacji poniżej). „Samoloty” są rozmieszczone losowo i widoczne tylko dla właścicieli planszy, a ukryte dla przeciwników.
- Gracz i agent na zmianę atakują po jednym polu na planszy przeciwnika. Gracz może kliknąć dowolną komórkę na planszy agenta, a agent automatycznie dokona wyboru na podstawie prognozy modelu uczenia maszynowego. Próbowana komórka zmieni kolor na czerwony, jeśli jest komórką „samolotu” („trafienie”), w przeciwnym razie zmieni kolor na żółty („pudło”).
- Wygrywa gracz, który jako pierwszy zdobędzie 8 czerwonych komórek. Następnie gra jest wznawiana z nowymi planszami.
Oto przykładowa rozgrywka:

3. Konfigurowanie środowiska programistycznego Fluttera
Aby ukończyć to ćwiczenie, potrzebujesz 2 elementów oprogramowania: pakietu SDK Flutter i edytora.
Codelab możesz uruchomić na dowolnym z tych urządzeń:
- Symulator iOS (wymaga zainstalowania narzędzi Xcode).
- Android Emulator (wymaga konfiguracji w Android Studio).
- przeglądarka (do debugowania wymagana jest Chrome);
- Jako aplikacja komputerowa na Windows, Linux lub macOS. Musisz tworzyć aplikację na platformie, na której zamierzasz ją wdrożyć. Jeśli chcesz opracować aplikację na komputery z systemem Windows, musisz to zrobić na komputerze z tym systemem, aby mieć dostęp do odpowiedniego łańcucha kompilacji. Istnieją wymagania dotyczące poszczególnych systemów operacyjnych, które są szczegółowo opisane na stronie docs.flutter.dev/desktop.
4. Konfiguracja
Aby pobrać kod do tego ćwiczenia:
- Otwórz repozytorium GitHub tego ćwiczenia.
- Aby pobrać cały kod do tych ćwiczeń z programowania, kliknij Code > Download zip (Kod > Pobierz plik ZIP).

- Rozpakuj pobrany plik ZIP, aby wyodrębnić folder główny
codelabs-mainze wszystkimi potrzebnymi zasobami.
W tym ćwiczeniu potrzebne są tylko pliki z podkatalogu tfagents-flutter/ w repozytorium, który zawiera kilka folderów:
- Foldery
step0–step6zawierają kod startowy, który będziesz rozwijać w kolejnych krokach tego ćwiczenia. - Folder
finishedzawiera gotowy kod ukończonej przykładowej aplikacji. - Każdy folder zawiera podfolder
backbendz kodem backendu i podfolderfrontendz kodem frontendu Fluttera.
5. Pobierz zależności projektu.
Backend
Otwórz terminal i przejdź do podfolderu tfagents-flutter. Wykonaj zapytanie:
pip install -r requirements.txt
Frontend
- W VS Code kliknij File > Open folder (Plik > Otwórz folder), a następnie wybierz folder
step0z pobranego wcześniej kodu źródłowego. - Otwórz plik
step0/frontend/lib/main.dart. Jeśli pojawi się okno VS Code z prośbą o pobranie wymaganych pakietów dla aplikacji startowej, kliknij Pobierz pakiety. - Jeśli nie widzisz tego okna, otwórz terminal, a następnie uruchom polecenie
flutter pub getw folderzestep0/frontend.

6. Krok 0. Uruchom aplikację startową
- Otwórz plik
step0/frontend/lib/main.dartw VS Code i upewnij się, że Android Emulator lub symulator iOS jest prawidłowo skonfigurowany i wyświetla się na pasku stanu.
Oto przykład tego, co zobaczysz, gdy użyjesz Pixela 5 z emulatorem Androida:

Oto co zobaczysz, gdy użyjesz iPhone'a 13 z symulatorem iOS:

- Kliknij
Rozpocznij debugowanie.
Uruchamianie aplikacji i jej poznawanie
Aplikacja powinna się uruchomić w Android Emulator lub iOS Simulator. Interfejs jest dość prosty. Są 2 plansze do gry. Gracz może kliknąć dowolne pole na planszy agenta u góry, aby zadać cios. Wytrenujesz inteligentnego agenta, który będzie automatycznie przewidywać, gdzie uderzyć, na podstawie planszy gracza.
Aplikacja Flutter wyśle aktualną planszę gracza do backendu, który uruchomi model uczenia przez wzmacnianie i zwróci przewidywaną pozycję komórki, w którą należy uderzyć w następnej kolejności. Po otrzymaniu odpowiedzi interfejs wyświetli wynik w interfejsie użytkownika.

Jeśli teraz klikniesz dowolną komórkę na tablicy agenta, nic się nie stanie, ponieważ aplikacja nie może jeszcze komunikować się z backendem.
7. Krok 1. Utwórz środowisko Pythona TensorFlow Agents
Głównym celem tych ćwiczeń jest zaprojektowanie agenta, który uczy się przez interakcję ze środowiskiem. Gra Plane Strike jest stosunkowo prosta i można w niej ręcznie tworzyć reguły dla agenta NPC. Jednak w tym samouczku użyjesz uczenia ze wzmocnieniem, aby wytrenować agenta. Dzięki temu zdobędziesz umiejętności, które pozwolą Ci w przyszłości łatwo tworzyć agentów do innych gier.
W standardowym ustawieniu uczenia przez wzmacnianie agent otrzymuje obserwację w każdym kroku czasowym i wybiera działanie. Działanie jest stosowane w środowisku, które zwraca nagrodę i nową obserwację. Agent trenuje strategię, aby wybierać działania, które maksymalizują sumę nagród, czyli zwrot. Dzięki wielokrotnemu graniu w tę grę agent może nauczyć się wzorców i doskonalić swoje umiejętności, aby ją opanować. Aby sformułować grę Plane Strike jako problem RL, potraktuj stan planszy jako obserwację, pozycję uderzenia jako działanie, a sygnał trafienia/chybienia jako nagrodę.

Do trenowania agenta NPC używasz TensorFlow Agents, czyli niezawodnej, skalowalnej i łatwej w obsłudze biblioteki uczenia ze wzmocnieniem dla TensorFlow.
TF Agents to świetne narzędzie do uczenia ze wzmocnieniem, ponieważ zawiera obszerny zestaw ćwiczeń z programowania, przykłady i obszerną dokumentację, która pomoże Ci zacząć. Możesz używać TF Agents do rozwiązywania realistycznych i złożonych problemów RL z możliwością skalowania oraz szybkiego opracowywania nowych algorytmów RL. Możesz łatwo przełączać się między różnymi agentami i algorytmami, aby przeprowadzać eksperymenty. Jest też dobrze przetestowany i łatwy w konfiguracji.
W OpenAI Gym (np. w przypadku gier Atari), Mujuco itp. zaimplementowano wiele gotowych środowisk gier, które TF Agents może łatwo wykorzystać. Gra Plane Strike jest jednak w pełni niestandardowa, więc musisz najpierw od podstaw zaimplementować nowe środowisko.
Aby zaimplementować środowisko Pythona TF Agents, musisz zaimplementować te metody:
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."""
Najważniejsza z nich to funkcja _step(), która przyjmuje działanie i zwraca nowy obiekt time_step. W przypadku gry Plane Strike masz planszę. Gdy pojawi się nowa pozycja ataku, środowisko na podstawie stanu planszy określa:
- Jak powinna wyglądać plansza w następnej kolejności (czy komórka powinna zmienić kolor na czerwony czy żółty, biorąc pod uwagę ukryte położenie samolotu)?
- Jaką nagrodę powinien otrzymać gracz za tę pozycję (nagroda za trafienie czy kara za nietrafienie)?
- Czy gra powinna się zakończyć (czy ktoś wygrał)?
- Dodaj do funkcji
_step()w pliku_planestrike_py_environment.pyten kod:
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. Krok 2. Trenowanie agenta gry za pomocą agentów TensorFlow
Po skonfigurowaniu środowiska TF Agents możesz wytrenować agenta gry. W tym ćwiczeniu użyjesz agenta REINFORCE. REINFORCE to algorytm gradientu strategii w uczeniu przez wzmacnianie. Jego podstawowa idea polega na dostosowywaniu parametrów sieci neuronowej zasad na podstawie sygnałów nagrody zebranych podczas rozgrywki, tak aby sieć zasad mogła w przyszłości maksymalizować zyski.
- Najpierw musisz utworzyć instancje środowisk trenowania i oceny. Dodaj ten kod do funkcji
train_agent()w plikustep2/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)
- Następnie musisz utworzyć agenta uczenia ze wzmocnieniem, który będzie trenowany. W tym ćwiczeniu użyjesz agenta REINFORCE, który jest agentem opartym na zasadach. Dodaj ten kod bezpośrednio pod powyższym kodem:
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,
)
- Na koniec wytrenuj agenta w pętli trenowania. W pętli najpierw zbierasz kilka epizodów rozgrywki w buforze, a potem trenujesz agenta na podstawie danych z bufora. Dodaj ten kod do funkcji
train_agent()w plikustep2/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()
- Możesz teraz rozpocząć trenowanie. W terminalu otwórz folder
step2/backendna komputerze i uruchom:
python training.py
Trenowanie trwa 8–12 godzin w zależności od konfiguracji sprzętu (nie musisz samodzielnie przeprowadzać całego trenowania, ponieważ wstępnie wytrenowany model jest dostępny w step3). W międzyczasie możesz śledzić postępy za pomocą TensorBoard. Otwórz nowy terminal, przejdź do folderu step2/backend na komputerze i uruchom:
tensorboard --logdir tf_agents_log/
tf_agents_log to folder zawierający dziennik trenowania. Przykładowe trenowanie wygląda tak:
Widać, że w miarę postępów w trenowaniu średnia długość odcinka maleje, a średni zwrot rośnie. Intuicyjnie można zrozumieć, że jeśli agent jest inteligentniejszy i dokonuje lepszych prognoz, gra trwa krócej i agent zbiera więcej nagród. Ma to sens, ponieważ agent chce zakończyć grę w mniejszej liczbie kroków, aby zminimalizować duże rabaty na nagrody w późniejszych krokach.
Po zakończeniu trenowania wytrenowany model jest eksportowany do folderu policy_model.
9. Krok 3. Wdróż wytrenowany model za pomocą TensorFlow Serving
Po wytrenowaniu agenta gry możesz go wdrożyć za pomocą TensorFlow Serving.
- W terminalu przejdź do folderu
step3/backendna komputerze i uruchom TensorFlow Serving za pomocą Dockera:
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 najpierw automatycznie pobierze obraz TensorFlow Serving, co zajmie minutę. Następnie powinna się uruchomić usługa TensorFlow Serving. Dziennik powinien wyglądać jak ten fragment kodu:
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 ...
Możesz wysłać do punktu końcowego przykładowe żądanie, aby upewnić się, że działa on zgodnie z oczekiwaniami:
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
Punkt końcowy zwróci przewidywaną pozycję 45, czyli (5, 5) na środku planszy (jeśli Cię to ciekawi, możesz spróbować dowiedzieć się, dlaczego środek planszy jest dobrym miejscem na pierwszy atak).
{
"predictions": [45]
}
To wszystko. Udało Ci się utworzyć backend do przewidywania następnej pozycji uderzenia agenta NPC.
10. Krok 4. Utwórz aplikację Flutter na Androida i iOS
Backend jest gotowy. Możesz zacząć wysyłać do niego żądania, aby pobierać z aplikacji Flutter prognozy pozycji uderzenia.
- Najpierw musisz zdefiniować klasę, która będzie zawierać dane wejściowe do wysłania. Dodaj ten kod do pliku
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;
}
}
Teraz możesz wysłać żądanie do TensorFlow Serving, aby uzyskać prognozy.
- Dodaj ten kod do funkcji
predict()w plikustep4/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');
}
Gdy aplikacja otrzyma odpowiedź z backendu, zaktualizuj interfejs gry, aby odzwierciedlał postępy w grze.
- Dodaj ten kod do funkcji
_gridItemTapped()w plikustep4/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(() {});
Stosuj
- Kliknij
Rozpocznij debugowanie, a następnie poczekaj na wczytanie aplikacji. - Aby rozpocząć grę, kliknij dowolną komórkę na tablicy agenta.

11. Krok 5. Włącz aplikację Flutter na platformach komputerowych
Oprócz Androida i iOS Flutter obsługuje też platformy desktopowe, takie jak Linux, Mac i Windows.
Linux
- Upewnij się, że na pasku stanu VSCode wybrane urządzenie docelowe to
. - Kliknij
Rozpocznij debugowanie, a następnie poczekaj na wczytanie aplikacji. - Aby rozpocząć grę, kliknij dowolną komórkę na tablicy agenta.

Mac
- W przypadku komputerów Mac musisz skonfigurować odpowiednie uprawnienia, ponieważ aplikacja będzie wysyłać żądania HTTP do backendu. Więcej informacji znajdziesz w artykule Uprawnienia i piaskownica aplikacji.
Dodaj ten kod do plików step4/frontend/macOS/Runner/DebugProfile.entitlements i step4/frontend/macOS/Runner/Release.entitlements:
<key>com.apple.security.network.client</key>
<true/>
- Upewnij się, że na pasku stanu VSCode wybrane urządzenie docelowe to
. - Kliknij
Rozpocznij debugowanie, a następnie poczekaj na wczytanie aplikacji. - Aby rozpocząć grę, kliknij dowolną komórkę na tablicy agenta.

Windows
- Upewnij się, że na pasku stanu VSCode wybrane urządzenie docelowe to
. - Kliknij
Rozpocznij debugowanie, a następnie poczekaj na wczytanie aplikacji. - Aby rozpocząć grę, kliknij dowolną komórkę na tablicy agenta.

12. Krok 6. Włącz aplikację Flutter na platformie internetowej
Możesz też dodać obsługę internetu do aplikacji Flutter. Platforma internetowa jest domyślnie włączona w przypadku aplikacji Flutter, więc wystarczy ją uruchomić.
- Upewnij się, że na pasku stanu VSCode wybrane urządzenie docelowe to
. - Kliknij
Rozpocznij debugowanie, a następnie poczekaj, aż aplikacja wczyta się w przeglądarce Chrome. - Aby rozpocząć grę, kliknij dowolną komórkę na tablicy agenta.

13. Gratulacje
Utworzono aplikację do gry planszowej z agentem opartym na uczeniu maszynowym, który może grać przeciwko człowiekowi.
