1. Sebelum memulai
Terobosan AlphaGo dan AlphaStar yang menakjubkan menunjukkan potensi penggunaan machine learning untuk membuat agen game level manusia super. Membangun game kecil yang didukung ML adalah latihan yang menyenangkan untuk mengasah keterampilan yang dibutuhkan dalam membuat agen game yang efektif.
Dalam codelab ini, Anda akan mempelajari cara membuat permainan papan menggunakan:
- Agen TensorFlow untuk melatih agen game dengan reinforcement learning
- TensorFlow Serving untuk menyalurkan model
- Flutter untuk membuat aplikasi game papan lintas platform
Prasyarat
- Pengetahuan dasar tentang pengembangan Flutter dengan Dart
- Pengetahuan dasar tentang machine learning dengan TensorFlow, seperti pelatihan versus deployment
- Pengetahuan dasar tentang Python, terminal, dan Docker
Yang akan Anda pelajari
- Cara melatih agen Karakter Non-Player (NPC) menggunakan Agen TensorFlow
- Cara menyalurkan model terlatih menggunakan TensorFlow Serving
- Cara membangun board game Flutter lintas platform
Yang Anda butuhkan
- Flutter SDK
- Penyiapan Android dan iOS untuk Flutter
- Penyiapan Desktop untuk Flutter
- Penyiapan Web untuk Flutter
- Penyiapan Visual Studio Code (VS Code) untuk Flutter dan Dart
- Docker
- Bash
- Python 3.7 dan yang lebih baru
2. Game Pesawat Strike
Game yang Anda buat dalam codelab ini disebut 'Plane Strike', yaitu game papan kecil untuk 2 pemain yang menyerupai game papan 'Battleship'. Aturannya sangat sederhana:
- Pemain manusia bermain melawan agen NPC yang dilatih dengan machine learning. Pemain manusia dapat memulai game dengan mengetuk sel mana pun di papan agen.
- Di awal game, masing-masing pemain dan agen memiliki 'pesawat' objek (8 sel hijau yang membentuk 'pesawat' seperti yang bisa Anda lihat pada papan pemain manusia di animasi di bawah) di papan mereka sendiri; ‘pesawat' ini ditempatkan secara acak dan hanya dapat dilihat oleh pemilik papan serta disembunyikan dari lawan.
- Pemain manusia dan agen bergiliran menyerang satu sel papan. Pemain manusia dapat mengetuk sel mana pun di papan agen, sedangkan agen akan otomatis membuat pilihan berdasarkan prediksi model machine learning. Sel yang dicoba berubah menjadi merah jika berupa 'pesawat' sel ('hit'); jika tidak, warnanya menjadi kuning ('miss').
- Siapa pun yang meraih 8 sel merah pertama kali memenangkan game; lalu game dimulai ulang dengan papan baru.
Berikut adalah contoh gameplay game:
3. Menyiapkan lingkungan pengembangan Flutter Anda
Untuk pengembangan Flutter, Anda memerlukan dua software untuk menyelesaikan codelab ini—Flutter SDK dan editor.
Anda dapat menjalankan codelab menggunakan salah satu perangkat berikut:
- Simulator iOS (perlu menginstal alat Xcode).
- Android Emulator (memerlukan penyiapan di Android Studio).
- Browser (Chrome diperlukan untuk proses debug).
- Aplikasi desktop Windows, Linux, atau macOS. Anda harus melakukan pengembangan di platform tempat Anda berencana men-deploy aplikasi. Jadi, jika ingin mengembangkan aplikasi desktop Windows, Anda harus mengembangkannya di Windows untuk mengakses rantai build yang sesuai. Ada persyaratan spesifik per sistem operasi yang dibahas secara mendetail di docs.flutter.dev/desktop.
4. Memulai persiapan
Untuk mendownload kode codelab ini:
- Buka repositori GitHub untuk codelab ini.
- Klik Code > Download zip guna mendownload semua kode untuk codelab ini.
- Ekstrak file zip yang didownload untuk mengekstrak folder root
codelabs-main
dengan semua resource yang Anda butuhkan.
Untuk codelab ini, Anda hanya memerlukan file dalam subdirektori tfagents-flutter/
di repositori, yang berisi beberapa folder:
- Folder
step0
hinggastep6
berisi kode awal yang Anda bangun untuk setiap langkah dalam codelab ini. - Folder
finished
berisi kode yang sudah selesai untuk aplikasi contoh yang telah selesai. - Setiap folder berisi subfolder
backbend
, yang mencakup kode backend, dan subfolderfrontend
, yang mencakup kode frontend Flutter
5. Mendownload dependensi untuk project
Backend
Buka terminal Anda dan masuk ke subfolder tfagents-flutter
. Jalankan perintah berikut:
pip install -r requirements.txt
Frontend
- Di VS Code, klik File > Buka folder, lalu pilih folder
step0
dari kode sumber yang Anda download sebelumnya. - Buka file
step0/frontend/lib/main.dart
. Jika Anda melihat dialog VS Code yang meminta Anda mendownload paket yang diperlukan untuk aplikasi awal, klik Get packages. - Jika Anda tidak melihat dialog ini, buka terminal lalu jalankan perintah
flutter pub get
di folderstep0/frontend
.
6. Langkah 0: Menjalankan aplikasi awal
- Buka file
step0/frontend/lib/main.dart
di VS Code, pastikan Android Emulator atau Simulator iOS disiapkan dengan benar dan muncul di status bar.
Misalnya, berikut adalah tampilan yang Anda lihat saat menggunakan Pixel 5 dengan Android Emulator:
Berikut adalah tampilan yang Anda lihat saat menggunakan iPhone 13 dengan Simulator iOS:
- Klik Start debugging.
Menjalankan dan menjelajahi aplikasi
Aplikasi akan diluncurkan di Android Emulator atau Simulator iOS. UI-nya cukup sederhana. Terdapat 2 papan permainan; pemain manusia dapat mengetuk sel mana pun di papan agen di bagian atas sebagai posisi teguran. Anda akan melatih agen cerdas untuk otomatis memprediksi di mana harus menyerang berdasarkan papan pemain manusia.
Di balik layar, aplikasi Flutter akan mengirimkan papan pemain saat ini ke backend, yang menjalankan model reinforcement learning dan menampilkan posisi sel yang diprediksi akan diserang berikutnya. Frontend akan menampilkan hasilnya di UI setelah menerima respons.
Jika Anda mengklik sel mana pun di board agen sekarang, tidak akan ada yang terjadi karena aplikasi belum dapat berkomunikasi dengan backend.
7. Langkah 1: Buat lingkungan Python Agen TensorFlow
Tujuan utama codelab ini adalah mendesain agen yang belajar melalui interaksi dengan lingkungan. Meskipun game Plane Strike relatif sederhana dan kamu bisa membuat aturan untuk agen NPC, kamu bisa menggunakan reinforcement learning untuk melatih agen agar kamu mempelajari skill dan bisa dengan mudah membangun agen untuk game lain di masa mendatang.
Dalam pengaturan Reinforcement Learning (RL) standar, agen menerima pengamatan pada setiap langkah waktu dan memilih tindakan. Tindakan tersebut diterapkan ke lingkungan dan lingkungan akan mengembalikan reward dan pengamatan baru. Agen melatih kebijakan untuk memilih tindakan guna memaksimalkan jumlah reward, yang juga dikenal sebagai laba. Dengan sering memainkan game, agen dapat mempelajari pola dan mengasah keterampilannya untuk menguasai game. Untuk merumuskan game Pesawat Strike sebagai masalah RL, anggap status papan sebagai pengamatan, posisi serang sebagai tindakan, dan sinyal hit/miss sebagai reward.
Untuk melatih agen NPC, Anda memanfaatkan Agen TensorFlow, yang merupakan library reinforcement learning yang andal, skalabel, dan mudah digunakan untuk TensorFlow.
TF Agents sangat cocok untuk pembelajaran penguatan karena dilengkapi dengan serangkaian codelab, contoh, dan dokumentasi yang lengkap untuk membantu Anda memulai. Anda dapat menggunakan Agen TF untuk menyelesaikan masalah RL yang realistis dan kompleks dengan skalabilitas dan mengembangkan algoritma RL baru dengan cepat. Anda dapat dengan mudah beralih antara berbagai agen dan algoritma untuk eksperimen. Aplikasi ini juga sudah teruji dengan baik dan mudah dikonfigurasi.
Ada banyak lingkungan game bawaan yang diimplementasikan di OpenAI Gym (mis., Atari), Mujuco, dan lain-lain, yang dapat dimanfaatkan oleh Agen TF dengan mudah. Namun, karena game Plane Strike adalah game kustom yang lengkap, Anda harus menerapkan lingkungan baru dari awal terlebih dahulu.
Untuk menerapkan lingkungan Python Agents TF, Anda perlu mengimplementasikan metode berikut:
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."""
Yang paling penting adalah fungsi _step()
, yang melakukan tindakan dan menampilkan objek time_step
baru. Untuk game Pesawat Strike, Anda memiliki papan permainan; ketika ada posisi penyerang baru, berdasarkan kondisi papan game, lingkungan akan mencari tahu:
- Seperti apa tampilan papan permainan berikutnya (jika sel berubah warna menjadi merah atau kuning, berdasarkan lokasi bidang yang tersembunyi?)
- Reward apa yang harus diterima pemain untuk posisi tersebut (mencapai reward atau melewatkan penalti?)
- Haruskah game dihentikan (apakah ada yang menang?)
- Tambahkan kode berikut ke fungsi
_step()
ke 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. Langkah 2: Latih agen game dengan Agen TensorFlow
Dengan lingkungan Agen TF, Anda dapat melatih agen game. Untuk codelab ini, Anda menggunakan agen REINFORCE. REINFORCE adalah algoritma gradien kebijakan di RL. Ide dasarnya adalah menyesuaikan parameter kebijakan neural network berdasarkan sinyal reward yang dikumpulkan selama gameplay, sehingga jaringan kebijakan dapat memaksimalkan laba dalam permainan mendatang.
- Pertama, Anda perlu membuat instance lingkungan pelatihan dan evaluasi. Tambahkan kode ini ke fungsi
train_agent()
di filestep2/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)
- Selanjutnya, Anda perlu membuat agen reinforcement learning yang akan dilatih. Dalam codelab ini, Anda menggunakan agen REINFORCE, yang merupakan agen berbasis kebijakan. Tambahkan kode ini tepat di bawah kode di atas:
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, )
- Terakhir, latih agen di loop pelatihan. Dalam loop, pertama-tama Anda mengumpulkan beberapa episode permainan game menjadi buffer, lalu melatih agen dengan data yang di-buffer. Tambahkan kode ini ke fungsi
train_agent()
di filestep2/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()
- Sekarang Anda dapat memulai pelatihan. Di terminal, buka folder
step2/backend
di komputer dan jalankan:
python training.py
Perlu waktu 8-12 jam untuk menyelesaikan pelatihan, bergantung pada konfigurasi hardware Anda (Anda tidak perlu menyelesaikan seluruh pelatihan sendiri karena model terlatih disediakan di step3
). Sementara itu, Anda dapat memantau progresnya dengan TensorBoard. Buka terminal baru, buka folder step2/backend
di komputer dan jalankan:
tensorboard --logdir tf_agents_log/
tf_agents_log
adalah folder yang berisi log pelatihan. Contoh latihan yang dijalankan terlihat seperti di bawah ini:
Anda dapat melihat bahwa durasi episode rata-rata berkurang dan pengembalian rata-rata meningkat, seiring kemajuan pelatihan. Secara intuitif, Anda dapat memahami bahwa jika agen lebih cerdas dan membuat prediksi yang lebih baik, durasi game akan menjadi lebih pendek dan agen akan mengumpulkan lebih banyak reward. Hal ini masuk akal karena agen ingin menyelesaikan game dalam langkah yang lebih sedikit untuk meminimalkan diskon reward yang besar pada langkah berikutnya.
Setelah pelatihan selesai, model yang dilatih akan diekspor ke folder policy_model
.
9. Langkah 3: Deploy model terlatih dengan TensorFlow Serving
Setelah melatih agen game, Anda dapat men-deploy-nya dengan TensorFlow Serving.
- Di terminal Anda, buka folder
step3/backend
di komputer dan mulai TensorFlow Serving dengan 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 akan otomatis mendownload image TensorFlow Serving terlebih dahulu, yang memerlukan waktu sebentar. Setelah itu, TensorFlow Serving akan dimulai. Log akan terlihat seperti cuplikan kode berikut:
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 ...
Anda dapat mengirim contoh permintaan ke endpoint untuk memastikan endpoint berfungsi seperti yang diharapkan:
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
Endpoint akan menampilkan prediksi posisi 45
, yaitu (5, 5) di tengah papan (untuk yang ingin tahu, Anda dapat mencoba mencari tahu mengapa bagian tengah papan adalah perkiraan yang bagus untuk posisi teguran pertama).
{ "predictions": [45] }
Selesai. Anda telah berhasil membuat backend untuk memprediksi posisi teguran berikutnya untuk agen NPC.
10. Langkah 4: Membuat aplikasi Flutter untuk Android dan iOS
Backend sudah siap. Anda dapat mulai mengirim permintaan ke aplikasi Flutter untuk mengambil prediksi posisi teguran dari aplikasi Flutter.
- Pertama, Anda perlu menentukan class yang menggabungkan input yang akan dikirim. Tambahkan kode ini ke 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; } }
Sekarang Anda dapat mengirim permintaan ke TensorFlow Serving untuk membuat prediksi.
- Tambahkan kode ini ke fungsi
predict()
di filestep4/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'); }
Setelah aplikasi menerima respons dari backend, Anda akan mengupdate UI game untuk mencerminkan progres game.
- Tambahkan kode ini ke fungsi
_gridItemTapped()
di filestep4/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(() {});
Menjalankan aplikasi
- Klik Start debugging, lalu tunggu aplikasi dimuat.
- Ketuk sel mana pun di papan agen untuk memulai game.
11. Langkah 5: Aktifkan aplikasi Flutter untuk platform desktop
Selain Android dan iOS, Flutter juga mendukung platform desktop termasuk Linux, Mac, dan Windows.
Linux
- Pastikan perangkat target disetel ke di status bar VSCode.
- Klik Start debugging, lalu tunggu aplikasi dimuat.
- Klik sel mana pun di papan agen untuk memulai game.
Mac
- Untuk Mac, Anda perlu menyiapkan hak yang sesuai karena aplikasi akan mengirim permintaan HTTP ke backend. Harap buka Hak dan App Sandbox untuk mengetahui detail selengkapnya.
Tambahkan kode ini ke step4/frontend/macOS/Runner/DebugProfile.entitlements
dan step4/frontend/macOS/Runner/Release.entitlements
masing-masing:
<key>com.apple.security.network.client</key>
<true/>
- Pastikan perangkat target disetel ke di status bar VSCode.
- Klik Start debugging, lalu tunggu aplikasi dimuat.
- Klik sel mana pun di papan agen untuk memulai game.
Windows
- Pastikan perangkat target disetel ke di status bar VSCode.
- Klik Start debugging, lalu tunggu aplikasi dimuat.
- Klik sel mana pun di papan agen untuk memulai game.
12. Langkah 6: Aktifkan aplikasi Flutter untuk platform web
Satu hal lagi yang dapat Anda lakukan adalah menambahkan dukungan web ke aplikasi Flutter. Secara default, platform web secara otomatis diaktifkan untuk aplikasi Flutter, sehingga Anda hanya perlu meluncurkannya.
- Pastikan perangkat target disetel ke di status bar VSCode.
- Klik Start debugging, lalu tunggu aplikasi dimuat di browser Chrome.
- Klik sel mana pun di papan agen untuk memulai game.
13. Selamat
Anda telah membangun aplikasi permainan papan dengan agen yang didukung ML untuk bermain melawan pemain manusia.