default_max_attempts_per_step: 9
sections:
  - section_id: "section_1"
    title: "Killer Squares"
    steps:
      - step_id: "step_0"
        title: "Introduction"
        content_blocks:
          - |
            Welcome to Killer Squares! 🎮
            In this game, both you and the AI will secretly choose a square.
            Then, you will attempt to "kill" a square. If you hit the AI's secret spot, you win!
            If the AI hits your secret spot, you lose. If nobody hits, the game continues.

            The board positions are numbered 0 to 8 as follows:

            ```
            0 | 1 | 2
            ---------
            3 | 4 | 5
            ---------
            6 | 7 | 8
            ``` 

      - step_id: "step_1"
        title: "Choose Your Secret Spot"
        question: "Choose a secret spot (0-8) for this round."
        tokens_for_ai: |
          If the user wants to exit, categorize as 'exit'.
          If the move is valid, categorize as 'valid_move'.
          If the move is invalid, categorize as 'invalid_move'.
        feedback_tokens_for_ai: |
          DO NOT TELL THE AI SECRET.
          If there is an error in the metadata the move was likely invalid.
          Always speak in first person. DO NOT START WITH "ai_move:".
          On a new line, provide feedback on the user's move.
          If the move is valid, proceed to the next step.
          If the move is invalid, prompt the user to try again.
        processing_script: |
          import random

          # Initialize or retrieve the game state
          user_secret = metadata.get("user_secret", None)
          ai_secret = random.randint(0, 8)

          # Get the user's secret spot
          try:
              user_secret = int(metadata.get("user_secret"))
          except (IndexError, ValueError) as e:
              user_secret = -1

          # Check if the move is valid
          if 0 <= user_secret < 9:
              script_result = {
                  "metadata": {
                      "user_secret": user_secret,
                      "ai_secret": ai_secret,
                  }
              }
          else:
              script_result = {
                  "error": f"Invalid secret spot: {metadata.get('user_secret')}",
                  "metadata": {}
              }

        buckets:
          - valid_move
          - invalid_move
          - restart
          - exit
        transitions:
          valid_move:
            run_processing_script: True
            ai_feedback:
              tokens_for_ai: "You've chosen your secret spot. Now, let's move to the killing round."
            metadata_add:
              user_secret: "the-users-response"
            next_section_and_step: "section_1:step_2"
          invalid_move:
            ai_feedback:
              tokens_for_ai: "That move is invalid. Please choose a position between 0 and 8."
            metadata_add:
              user_secret: "the-users-response"
            next_section_and_step: "section_1:step_1"
          exit:
            next_section_and_step: "section_1:step_3"
          restart:
            ai_feedback:
              tokens_for_ai: "Restarting the game. Let's start fresh!"
            metadata_clear: True
            next_section_and_step: "section_1:step_0"

      - step_id: "step_2"
        title: "Kill a Square"
        question: "Choose a square to kill (0-8)."
        tokens_for_ai: |
          If the user wants to restart or play again, categorize as 'restart'.
          If the user wants to exit, categorize as 'exit'.
          If the move is valid, categorize as 'valid_move'.
          If the move is invalid, categorize as 'invalid_move'.
        feedback_tokens_for_ai: |
          DO NOT reveal the AI's secret spot until game_over = True.
          ALWAYS speak in first person. DO NOT START WITH "ai_move:".
          If there is an error in the metadata, the move was likely invalid.
          On a new line, provide feedback on the user's move:
          - If the move is valid, check if the user's shot hit my (AI's) secret spot (ai_secret).
          - If the user's shot hits my secret spot, say: "You hit my secret spot!"
          - If the user's shot misses, say: "You missed my secret spot."
          If the move is invalid, prompt the user to try again.
          My move is the last item in the ai_shots list. For example, if ai_shots = [5, 3], my move is 3.
          Announce my move: "I shoot at position [my move]."
          If game_over = True, determine the winner:
          - If user_wins = True, say: "Congratulations! You hit my secret spot and won the round!"
          - If ai_wins = True, say: "I hit your secret spot and won the round!"
          If game_over = True, describe the carnage of the final strike.
          If game_over = True, suggest: "Would you like to restart and play again, or would you prefer to exit?"
        processing_script: |
          import random
          import matplotlib
          matplotlib.use("Agg")
          import matplotlib.pyplot as plt
          import io
          import base64

          # Retrieve the game state
          user_secret = metadata.get("user_secret")
          ai_secret = metadata.get("ai_secret")
          user_shots = metadata.get("user_shots", [])
          ai_shots = metadata.get("ai_shots", [])
          game_over = metadata.get("game_over", False)


          # Get the user's kill move
          try:
              user_kill = int(metadata.get("user_kill"))
          except (IndexError, ValueError) as e:
              user_kill = -1

          if game_over:
              script_result = {}
          elif 0 <= user_kill < 9:
              # the move is valid.
              user_shots.append(user_kill)
              if user_kill == ai_secret:
                  game_over = True
                  user_wins = True
                  ai_wins = False
                  draw = False
                  user_title = "You Win!"
                  ai_title = "AI's Moves"
              else:
                  # AI makes a move, avoiding its own secret spot
                  available_positions = []
                  for i in range(9):
                      if i not in ai_shots and i != ai_secret:
                          available_positions.append(i)
                  ai_kill = random.choice(available_positions) if available_positions else None
                  if ai_kill is not None:
                      ai_shots.append(ai_kill)
                      if ai_kill == user_secret:
                          game_over = True
                          user_wins = False
                          ai_wins = True
                          draw = False
                          user_title = "Your Moves"
                          ai_title = "AI Wins!"
                      else:
                          game_over = False
                          user_wins = False
                          ai_wins = False
                          draw = False
                          user_title = "Your Moves"
                          ai_title = "AI's Moves"
                  else:
                      game_over = True
                      user_wins = False
                      ai_wins = False
                      draw = True
                      user_title = "Your Moves"
                      ai_title = "It's a Draw!"

              # Plot the boards
              fig, axs = plt.subplots(1, 2, figsize=(6, 3))
              fig.suptitle("Killer Squares", fontsize=16)
              fig.tight_layout(h_pad=4)

              # User's board
              axs[0].set_xlim(0, 3)
              axs[0].set_ylim(0, 3)
              axs[0].set_xticks([])
              axs[0].set_yticks([])
              axs[0].grid(True)
              axs[0].set_title(user_title, fontsize=12)

              for i in range(9):
                  x = i % 3
                  y = 2 - i // 3
                  axs[0].text(x + 0.5, y + 0.5, str(i), fontsize=12, ha='center', va='center', color='gray')

              for user_kill in user_shots:
                  ux, uy = user_kill % 3, 2 - user_kill // 3
                  axs[0].text(ux + 0.5, uy + 0.5, 'X', fontsize=24, ha='center', va='center', color='red')

              # AI's board
              axs[1].set_xlim(0, 3)
              axs[1].set_ylim(0, 3)
              axs[1].set_xticks([])
              axs[1].set_yticks([])
              axs[1].grid(True)
              axs[1].set_title(ai_title, fontsize=12)

              for i in range(9):
                  x = i % 3
                  y = 2 - i // 3
                  axs[1].text(x + 0.5, y + 0.5, str(i), fontsize=12, ha='center', va='center', color='gray')

              for ai_kill in ai_shots:
                  axx, axy = ai_kill % 3, 2 - ai_kill // 3
                  axs[1].text(axx + 0.5, axy + 0.5, 'X', fontsize=24, ha='center', va='center', color='blue')

              buf = io.BytesIO()
              plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0.1)
              plt.close(fig)
              buf.seek(0)
              plot_image = base64.b64encode(buf.getvalue()).decode('utf-8')

              script_result = {
                  "plot_image": plot_image,
                  "metadata": {
                      "user_secret": user_secret,
                      "ai_secret": ai_secret,
                      "user_shots": user_shots,
                      "ai_shots": ai_shots,
                      "game_over": game_over,
                      "user_wins": user_wins,
                      "ai_wins": ai_wins,
                      "draw": draw,
                  }
              }
          else:
              script_result = {
                  "error": f"Invalid kill move: {metadata.get('user_kill')}",
                  "metadata": {}
              }

        buckets:
          - valid_move
          - invalid_move
          - exit
          - restart
        transitions:
          valid_move:
            run_processing_script: True
            ai_feedback:
              tokens_for_ai: |
                If somebody wins explain the move that triggered the kill shot.
                Only if game_over is True reveal the ai secret spot number otherwise never tell the player the secret!
            metadata_tmp_add:
              user_kill: "the-users-response"
            next_section_and_step: "section_1:step_2"
          invalid_move:
            ai_feedback:
              tokens_for_ai: "That move is invalid. Please choose a position between 0 and 8."
            metadata_tmp_add:
              user_kill: "the-users-response"
            next_section_and_step: "section_1:step_2"
          exit:
            next_section_and_step: "section_1:step_3"
          restart:
            ai_feedback:
              tokens_for_ai: "Restarting the game. Let's start fresh!"
            metadata_clear: True
            next_section_and_step: "section_1:step_0"

      - step_id: "step_3"
        title: "Goodbye"
        content_blocks:
          - "Thank you for playing Killer Squares! 🎉"
          - "Feel free to come back anytime for another game."
