default_max_attempts_per_step: 9
sections:
  - section_id: "section_1"
    title: "Tic Tac Toe"
    steps:
      - step_id: "step_0"
        title: "Introduction"
        content_blocks:
          - |
            Welcome to Tic Tac Toe! 🎮
            You will be playing against the AI. You are 'X' and the AI is 'O'.
            The board positions are numbered 0 to 8 as follows:

            <img src="/static/images/tic-tac-toe.png">

      - step_id: "step_1"
        title: "Your Move"
        question: "Enter a position number (0-8) to place your 'X'. Say restart or exit to quit."
        tokens_for_ai: |
          Using the metadata, determine if the game is over and 'restart'.
          If the user wants to restart or play again, categorize as 'restart'
          If ai_wins or user_wins or is_draw is true, categorize as 'restart'.
          If the user wants to exit, categorize as 'exit'.
          If the game_over is True categorize as 'restart'.
          Finally check:
          If the move is valid, categorize as 'valid_move'.
          If the move is invalid, categorize as 'invalid_move'.
        feedback_tokens_for_ai: |
          Always speak in first person. DO NOT START WITH "ai_move:".
          Player is always X, You the AI are always O.
          If there is an error in the metadata the move was likely invalid.
          On a new line, provide feedback on the user's move.
          Only announce a winner or tie if game_over is True.
          The player makes the first and last move.
          If the move is invalid, prompt the user to try again.
          If the move is invalid, give a list of valid moves.
          If the move is valid & no errors say your move on the last line (ai_move) for example: I move to 8 and draw a O".
        processing_script: |
          import random

          win_conditions = [
              [0, 1, 2], [3, 4, 5], [6, 7, 8],  # rows
              [0, 3, 6], [1, 4, 7], [2, 5, 8],  # columns
              [0, 4, 8], [2, 4, 6]              # diagonals
          ]

          def check_win(board, player, win_conditions):
              # Check for win and return the winning condition if there is one
              for condition in win_conditions:
                  win = True
                  for i in condition:
                      if board[i] != player:
                          win = False
                          break
                  if win:
                      return condition
              return None

          def plot_board(board, win_line=None):
              import io
              import base64
              import matplotlib
              matplotlib.use("Agg")
              import matplotlib.pyplot as plt

              fig, ax = plt.subplots(figsize=(3, 3))
              ax.set_xlim(0, 3)
              ax.set_ylim(0, 3)
              ax.set_xticks([])
              ax.set_yticks([])
              ax.grid(True)

              for i, mark in enumerate(board):
                  x = i % 3
                  y = 2 - i // 3
                  if mark != " ":
                      ax.text(x + 0.5, y + 0.5, mark, fontsize=24, ha='center', va='center')
                  else:
                      # Plot the cell number if the cell is empty
                      ax.text(x + 0.5, y + 0.5, str(i), fontsize=12, ha='center', va='center', color='gray')


              # Draw the winning line if there is one
              if win_line:
                  for i in range(len(win_line) - 1):
                      start = win_line[i]
                      end = win_line[i + 1]
                      x_start, y_start = start % 3 + 0.5, 2 - start // 3 + 0.5
                      x_end, y_end = end % 3 + 0.5, 2 - end // 3 + 0.5
                      ax.plot([x_start, x_end], [y_start, y_end], 'r-', linewidth=2)

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

          # Reconstruct the board from moves
          user_moves = metadata.get("user_moves", [])
          ai_moves = metadata.get("ai_moves", [])
          ai_move = None
          board = [" "] * 9
          for move in user_moves:
              board[int(move)] = "X"
          for move in ai_moves:
              board[int(move)] = "O"

          # Get the user's latest move
          try:
              user_move = int(metadata.get("user_move"))
          except (IndexError, ValueError) as e:
              # Remove the invalid move from user_moves
              user_move = -1

          # Check if the move is valid
          if 0 <= user_move < 9 and board[user_move] == " ":
              board[user_move] = "X"
              user_moves.append(user_move)
          
              user_win_line = check_win(board, "X", win_conditions)
          
              if not user_win_line:
                  # ai makes a move.
                  available_positions = []
                  for i in range(len(board)):
                      if board[i] == " ":
                          available_positions.append(i)
                  if available_positions:
                      ai_move = random.choice(available_positions)
                      board[ai_move] = "O"
                      ai_moves.append(ai_move)
          
              ai_win_line = check_win(board, "O", win_conditions)
              is_draw = True
              for x in board:
                  if x == " ":
                      is_draw = False
                      break
              game_over = any([user_win_line, ai_win_line, is_draw])
          
              win_line = user_win_line if user_win_line else ai_win_line

              script_result = {
                  "plot_image": plot_board(board, win_line),
                  "set_background": not game_over,
                  "ai_move": ai_move,
                  "user_move": user_move,
                  "metadata": { 
                      "user_moves": user_moves,
                      "ai_moves": ai_moves,
                      "board": board,
                      "game_over": game_over,
                      "ai_wins": ai_win_line is not None,
                      "user_wins": user_win_line is not None,
                      "is_draw": is_draw
                  }
              }
          else:
              script_result = {
                  "error": f"Invalid move: {metadata.get('user_move')}",
                  "metadata": {
                      "user_moves": user_moves,
                  },
              }

          # Debugging: Print the current board state
          print("Current board state:", board)

        buckets:
          - valid_move
          - invalid_move
          - restart
          - exit
        transitions:
          valid_move:
            run_processing_script: True
            ai_feedback:
              tokens_for_ai: |
                at first glance it seems like a valid user_move.
                DO NOT:
                 * DRAW THE GAME BOARD
                 * DESCRIBE THE GAME BOARD
            metadata_tmp_add:
              user_move: "the-users-response"
            next_section_and_step: "section_1:step_1"
          invalid_move:
            ai_feedback:
              tokens_for_ai: "That move is invalid. Please choose an empty position between 0 and 8."
            metadata_tmp_add:
              user_move: "the-users-response"
            next_section_and_step: "section_1:step_1"
          exit:
            next_section_and_step: "section_1:step_2"
          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: "Goodbye"
        content_blocks:
          - "Thank you for playing Tic Tac Toe! 🎉"
          - "Feel free to come back anytime for another game."
