1. לפני שמתחילים
פריצת הדרך המדהימה של AlphaGo ו-AlphaStar הוכיחה את הפוטנציאל של שימוש בלמידת מכונה לפיתוח סוכני משחקים ברמה על-אנושית. זה תרגיל כיפי לפתח משחק קטן שמבוסס על למידת מכונה, שבעזרתו אפשר לרכוש את המיומנויות שנדרשות ליצירת סוכני משחקים חזקים.
ב-Codelab הזה תלמדו איך לבנות משחק לוח באמצעות:
- נציג של TensorFlow כדי לאמן סוכן משחקים עם למידת חיזוק
- מילוי בקשות של TensorFlow לצורך הצגת המודל
- Flutter ליצירת אפליקציה של משחקי לוח בפלטפורמות שונות
דרישות מוקדמות
- ידע בסיסי על התפתחות Flutter עם Drt
- ידע בסיסי בלמידת מכונה עם TensorFlow, למשל אימון לעומת פריסה
- ידע בסיסי ב-Python, טרמינלים ו-Docker
מה תלמדו
- איך מאמנים סוכן של דמות שאינה נגן (NPC) באמצעות סוכני TensorFlow
- איך להציג את המודל שעבר אימון באמצעות הצגת מודעות של TensorFlow
- איך בונים משחק לוח של Flutter בפלטפורמות שונות
למה תזדקק?
- Flutter SDK
- הגדרת Android ו-iOS עבור Flutter
- הגדרה של Flutter במחשב
- הגדרת אינטרנט של Flutter
- הגדרה של Visual Studio Code (VS Code) ב-Flutter וב-Dart
- Docker
- באש
- Python 3.7 ואילך
2. המשחק The Plane Strike
המשחק שאתם בונים ב-Codelab הזה נקרא Plane Strike – משחק לוח קטן ל-2 שחקנים שדומה למשחק הלוח Battleship. הכללים פשוטים מאוד:
- השחקן האנושי משחק נגד סוכן NPC שעבר אימון על ידי למידת מכונה. השחקנים יכולים להתחיל את המשחק בהקשה על תא כלשהו בלוח של הנציג.
- בתחילת המשחק, לשחקן האנושי ולסוכן יש 'מטוס' אובייקט (8 תאים ירוקים שיוצרים 'מישור' כפי שאפשר לראות בלוח של השחקן באנימציה שלמטה) על הלוחות שלו; המטוסים האלה מוצבים באופן אקראי וגלויים רק לבעלי הלוח ומוסתרים ליריבים.
- השחקנים האנושיים והנציג תורו להכות בתא אחד בלוח המשחק אחד של השני. הנגן האנושי יכול להקיש על כל תא בלוח של הסוכן, והסוכן יבצע את הבחירה באופן אוטומטי על סמך החיזוי של מודל למידת המכונה. התא לניסיון הופך לאדום אם הוא 'מטוס' תא (‘hit'); אחרת הוא הופך לצהוב ('החמצה').
- מי שישיג 8 תאים אדומים קודם יזכה במשחק. לאחר מכן המשחק יופעל מחדש עם לוחות חדשים.
הנה גיימפליי לדוגמה:
3. הגדרת סביבת הפיתוח של Flutter
לפיתוח של Flutter, נדרשות שתי קטעי תוכנה כדי להשלים את ה-Codelab הזה – Flutter SDK ועורך.
אפשר להריץ את Codelab באמצעות כל אחד מהמכשירים הבאים:
- הסימולטור של iOS (צריך להתקין כלים של Xcode).
- האמולטור של Android (נדרשת הגדרה ב-Android Studio).
- דפדפן (Chrome נדרש לניפוי באגים).
- בתור אפליקציית Windows , Linux או macOS למחשב. צריך לפתח בפלטפורמה שבה אתם מתכננים לפרוס. לכן, כדי לפתח אפליקציה למחשב של Windows, צריך לפתח את האפליקציה ב-Windows כדי לגשת לשרשרת ה-build המתאימה. יש דרישות ספציפיות למערכת ההפעלה שמפורטות בהרחבה בכתובת docs.flutter.dev/desktop.
4. להגדרה
כדי להוריד את הקוד ל-Codelab הזה:
- עוברים אל מאגר ה-GitHub של ה-Codelab הזה.
- לוחצים על קוד > כדי להוריד את כל הקוד ל-Codelab הזה, צריך להוריד את ה-ZIP.
- מחלצים את קובץ ה-ZIP שהורדתם כדי לפתוח תיקיית בסיס מסוג
codelabs-main
עם כל המשאבים הנחוצים.
ב-Codelab הזה, צריך רק את הקבצים בספריית המשנה tfagents-flutter/
במאגר, שמכיל כמה תיקיות:
- התיקיות
step0
עדstep6
מכילות את קוד הסימן לתחילת פעולה שעליו יוצרים בכל שלב ב-Codelab הזה. - התיקייה
finished
מכילה את הקוד שהושלם עבור האפליקציה לדוגמה הסופית. - כל תיקייה מכילה תיקיית משנה
backbend
, שכוללת את הקוד לקצה העורפי ותיקיית משנהfrontend
, שכוללת את הקוד בקצה הקדמי של Flutter
5. הורדת יחסי התלות של הפרויקט
קצה עורפי
פותחים את הטרמינל ונכנסים לתיקיית המשנה tfagents-flutter
. מריצים את הפקודה הבאה:
pip install -r requirements.txt
קצה קדמי
- ב-VS Code, לוחצים על File > (קובץ >) פותחים את התיקייה ובוחרים את התיקייה
step0
מקוד המקור שהורדתם קודם. - פתיחת הקובץ
step0/frontend/lib/main.dart
. אם מופיעה תיבת דו-שיח של VS Code, עם בקשה להוריד את החבילות הנדרשות לאפליקציה למתחילים, לוחצים על קבלת חבילות. - אם תיבת הדו-שיח הזו לא מופיעה, פותחים את הטרמינל ואז מריצים את הפקודה
flutter pub get
בתיקייהstep0/frontend
.
6. שלב 0: מפעילים את האפליקציה לתחילת הפעולה
- פותחים את הקובץ
step0/frontend/lib/main.dart
ב-VS Code, מוודאים שהאמולטור של Android או הסימולטור של iOS מוגדרים כראוי ומופיעים בשורת הסטטוס.
לדוגמה, זה מה שרואים כשמשתמשים ב-Pixel 5 עם האמולטור Android:
כשמשתמשים ב-iPhone 13 עם הסימולטור של iOS, רואים את הפרטים הבאים:
- לוחצים על התחלת ניפוי באגים.
הפעלה וגילוי של האפליקציה
האפליקציה צריכה להיות מופעלת באמולטור Android או בסימולטור של iOS. ממשק המשתמש הוא די פשוט. יש 2 לוחות משחקים; שחקן אנושי יכול להקיש על כל תא בלוח של הנציג בחלק העליון כמיקום פסילה. תאמנו סוכן חכם לחזות באופן אוטומטי את המיקום שבו הוא יכות על סמך לוח השחקן.
מתחת למכסה הקדמי, אפליקציית Flutter תשלח את הלוח הנוכחי של השחקן בקצה העורפי, שבו יופעל מודל של למידת חיזוק ותחזיר את המיקום הצפוי של התא שבו יוצג השחקן הבא. הקצה הקדמי יציג את התוצאה בממשק המשתמש לאחר קבלת התגובה.
אם לוחצים עכשיו על תא כלשהו בלוח של הנציג, לא יקרה כלום כי האפליקציה עדיין לא יכולה לתקשר עם הקצה העורפי.
7. שלב 1: יצירת סביבת Python של סוכני TensorFlow
המטרה העיקרית של ה-Codelab הזה היא לתכנן סוכן שלומד באמצעות אינטראקציה עם סביבה. משחק Plane Strike פשוט יחסית ואפשר ליצור כללים עבור סוכן NPC, אבל משתמשים בלמידת חיזוק כדי לאמן סוכן כדי ללמוד את המיומנויות וליצור סוכנים בקלות למשחקים אחרים בעתיד.
בהגדרה הרגילה של למידת חיזוק (RL), הנציג מקבל תצפית בכל שלב ובוחר פעולה. הפעולה מיושמת בסביבה והסביבה מחזירה תגמול ותצפית חדשה. הנציג אימון מדיניות כדי לבחור פעולות למיקסום סכום הפרסים, שנקראות גם 'החזרה'. כשהוא משחק במשחק הרבה פעמים, הסוכן יכול ללמוד את הדפוסים ולחדד את הכישורים שלו כדי ללמוד היטב את המשחק. כדי לנסח את משחק Plane Strike בתור בעיית RL, צריך להתייחס למצב הלוח בתור תצפית, למקם את הפסילה בתור הפעולה, ואת אות ההיט/החמצה בתור פרס.
כדי לאמן את סוכן ה-NPC באמצעות סוכני TensorFlow, ספרייה מהימנה, ניתנת להתאמה וקלה לשימוש ב-TensorFlow.
הכלי TF Agents הוא כלי מעולה ללמידת חיזוק כי הוא מגיע עם ערכה מקיפה של Codelabs, דוגמאות ומסמכי תיעוד מקיפים, שיעזרו לכם להתחיל. אפשר להשתמש בסוכני TF כדי לפתור בעיות RL מציאותיות ומורכבות עם מדרגיות, ולפתח אלגוריתמים חדשים של RL במהירות. אפשר לעבור בקלות בין סוכנים ואלגוריתמים שונים לצורך ניסוי. הוא גם נבדק היטב וקל להגדרה.
יש הרבה סביבות משחק שמובנות מראש ומוטמעות ב-OpenAI Gym (למשל, משחקי Atari), Mujuco וכו', שסוכני TF יכולים למנף בקלות. אבל מכיוון שהמשחק Plane Strike הוא משחק מותאם אישית לגמרי, קודם צריך להטמיע סביבה חדשה מאפס.
כדי להטמיע סביבת Python ב-TF Agents, צריך להטמיע את השיטות הבאות:
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."""
הפונקציה החשובה ביותר היא הפונקציה _step()
, שמבצעת פעולה ומחזירה אובייקט time_step
חדש. במקרה של המשחק Plane Strike, יש לכם לוח משחק; כשמתקבלת מיקום התראה חדש, בהתאם לתנאי לוח המשחק, הסביבה קובעת:
- איך לוח המשחק צריך להיראות עכשיו (האם צריך לשנות את צבע התא לאדום או לצהוב, בהינתן המיקום המוסתר של המטוס?)
- איזה פרס צריך לקבל השחקן על המיקום הזה (פגיעה בפרס או בהחמצה של עונש?)
- האם המשחק הסתיים (האם מישהו ניצח?)
- מוסיפים את הקוד הבא לפונקציה
_step()
לקובץ_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. שלב 2: מאמנים את סוכן המשחק באמצעות סוכני TensorFlow
בסביבת TF Agents, אפשר לאמן את סוכן המשחק. בשביל ה-Codelab הזה צריך להשתמש בסוכן REINFORCE. REINFORCE הוא אלגוריתם הדרגתי של מדיניות ב-RL. הרעיון הבסיסי הוא להתאים את הפרמטרים של רשת הנוירונים למדיניות בהתאם לאותות הפרסים שנאספים במהלך המשחק, כדי שרשת המדיניות תוכל למקסם את ההחזר במהלכים עתידיים.
- קודם כל צריך ליצור את סביבות האימון וההערכה. מוסיפים את הקוד הבא לפונקציה
train_agent()
בקובץ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)
- בשלב הבא צריך ליצור סוכן ללמידה של חיזוק שאמור לעבור הדרכה. ב-Codelab הזה משתמשים בסוכן REINFORCE, שהוא סוכן מבוסס-מדיניות. מוסיפים את הקוד הבא ממש מתחת לקוד שלמעלה:
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, )
- לבסוף, מאמנים את הנציג בלולאת האימון. בלולאה, קודם כול צריך לאסוף כמה פרקים של מהלכים במשחק למאגר נתונים, ואז לאמן את הסוכן בעזרת הנתונים שבמאגר. מוסיפים את הקוד הבא לפונקציה
train_agent()
בקובץ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()
- עכשיו תוכלו להתחיל את ההדרכה. בטרמינל, נכנסים לתיקייה
step2/backend
במחשב ומריצים את הפקודה:
python training.py
תהליך האימון נמשך 8-12 שעות, בהתאם לתצורות החומרה (אין צורך להשלים את כל האימון לבד, כי מודל שעבר אימון מראש זמין ב-step3
). בינתיים, תוכלו לעקוב אחר ההתקדמות באמצעות TensorBoard. פותחים טרמינל חדש, נכנסים לתיקייה step2/backend
במחשב ומריצים את הפקודה:
tensorboard --logdir tf_agents_log/
tf_agents_log
היא התיקייה שמכילה את יומן האימון. הרצת אימון לדוגמה נראית כך:
אפשר לראות שאורך הפרק הממוצע יורד וההחזר הממוצע גדל ככל שהאימון מתקדם. באופן אינטואיטיבי, אתם יכולים להבין שאם הסוכן חכם יותר ויספק תחזיות טובות יותר, משך המשחק יהיה קצר יותר והסוכן יצבור יותר פרסים. זה הגיוני כי הסוכן רוצה לסיים את המשחק בפחות שלבים כדי לצמצם את הנחת הפרסים המשמעותית בשלבים הבאים.
אחרי שהאימון מסתיים, המודל שעבר אימון מיוצא לתיקייה policy_model
.
9. שלב 3: פריסת המודל שעבר אימון באמצעות מילוי בקשות של TensorFlow
עכשיו, אחרי שהדרכתם את סוכן המשחק, תוכלו לפרוס אותו באמצעות TensorFlow הצגה.
- בטרמינל, נכנסים לתיקייה
step3/backend
במחשב ומתחילים להציג את TensorFlow באמצעות 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 מוריד באופן אוטומטי את תמונת ההצגה של TensorFlow, תוך דקה. לאחר מכן, ההצגה של TensorFlow אמורה להתחיל. היומן אמור להיראות כמו קטע הקוד הבא:
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 ...
אתם יכולים לשלוח בקשה לדוגמה לנקודת הקצה (endpoint) כדי לוודא שהיא פועלת כצפוי:
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
נקודת הקצה תחזיר את המיקום הצפוי 45
, שהוא (5, 5) במרכז הלוח (לסקרנים, אפשר לנסות להבין למה מרכז הלוח יכול לנחש טוב את מיקום ההתראה הראשונה).
{ "predictions": [45] }
זהו! יצרתם בהצלחה קצה עורפי לחיזוי מיקום ההתראה הבאה עבור סוכן NPC.
10. שלב 4: יוצרים את האפליקציה Flutter ל-Android ול-iOS
הקצה העורפי מוכן. אפשר להתחיל לשלוח אליו בקשות כדי לאחזר חיזויים של מיקומי התראה מאפליקציית Flutter.
- קודם כל צריך להגדיר מחלקה שמרכזת את ערכי הקלט לשליחה. מוסיפים את הקוד הבא לקובץ
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; } }
עכשיו אפשר לשלוח את הבקשה ל-TensorFlow serving כדי לבצע חיזויים.
- מוסיפים את הקוד הבא לפונקציה
predict()
בקובץ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'); }
אחרי שהאפליקציה מקבלת את התשובה מהקצה העורפי, מעדכנים את ממשק המשתמש של המשחק כך שישקף את ההתקדמות במשחק.
- מוסיפים את הקוד הבא לפונקציה
_gridItemTapped()
בקובץ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(() {});
הפעלה
- לוחצים על התחלת ניפוי באגים ומחכים עד שהאפליקציה תיטען.
- מקישים על תא כלשהו בלוח של הנציג כדי להתחיל את המשחק.
11. שלב 5: מפעילים את האפליקציה Flutter לפלטפורמות של מחשבים
בנוסף ל-Android ול-iOS, אפליקציית Flutter תומכת גם בפלטפורמות למחשב, כולל Linux, Mac ו-Windows.
Linux
- צריך לוודא שמכשיר היעד מוגדר לערך בשורת הסטטוס של VSCode.
- לוחצים על התחלת ניפוי באגים ומחכים עד שהאפליקציה תיטען.
- לוחצים על תא כלשהו בלוח של הנציג כדי להתחיל את המשחק.
Mac
- ב-Mac צריך להגדיר את ההרשאות המתאימות כי האפליקציה תשלח בקשות HTTP לקצה העורפי. לפרטים נוספים, ניתן לעיין בהרשאות וארגז החול של האפליקציות.
מוסיפים את הקוד הזה אל step4/frontend/macOS/Runner/DebugProfile.entitlements
ואל step4/frontend/macOS/Runner/Release.entitlements
בהתאמה:
<key>com.apple.security.network.client</key>
<true/>
- צריך לוודא שמכשיר היעד מוגדר לערך בשורת הסטטוס של VSCode.
- לוחצים על התחלת ניפוי באגים ומחכים עד שהאפליקציה תיטען.
- לוחצים על תא כלשהו בלוח של הנציג כדי להתחיל את המשחק.
Windows
- צריך לוודא שמכשיר היעד מוגדר לערך בשורת הסטטוס של VSCode.
- לוחצים על התחלת ניפוי באגים ומחכים עד שהאפליקציה תיטען.
- לוחצים על תא כלשהו בלוח של הנציג כדי להתחיל את המשחק.
12. שלב 6: מפעילים את אפליקציית Flutter לפלטפורמת האינטרנט
דבר נוסף שניתן לעשות הוא להוסיף תמיכה באינטרנט לאפליקציית Flutter. כברירת מחדל, פלטפורמת האינטרנט מופעלת באופן אוטומטי עבור אפליקציות Flutter, כך שכל מה שצריך לעשות הוא להפעיל אותה.
- צריך לוודא שמכשיר היעד מוגדר בתור בשורת הסטטוס של VSCode.
- לוחצים על התחלת ניפוי באגים ומחכים עד שהאפליקציה תיטען בדפדפן Chrome.
- לוחצים על תא כלשהו בלוח של הנציג כדי להתחיל את המשחק.
13. מזל טוב
יצרת אפליקציה של משחק לוח בעזרת סוכן מבוסס-ML כדי לשחק נגד השחקן האנושי!