1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//! ReAct agent for Pokemon TCG.
//!
//! This module provides a ReAct-style AI agent that uses an LLM to play Pokemon TCG.
//! It follows the pattern established in the ContinualLearningBench crafter implementation.
//!
//! ## Architecture
//!
//! The module consists of three main components:
//!
//! 1. **Renderer** (`render.rs`): Converts `GameView` to human-readable text for LLM consumption.
//! - Full game state rendering with `render_game_view()`
//! - Compact rendering for repeated observations with `render_game_view_compact()`
//!
//! 2. **Action Parser** (`action_parser.rs`): Parses LLM responses into `Action` enums.
//! - Supports JSON format: `{"action": "PlayBasic", "card_id": 123}`
//! - Supports natural language: "Play Basic Pokemon with id 123"
//! - Context-aware parsing based on pending prompts
//!
//! 3. **ReactAi** (`react_ai.rs`): The main AI controller implementing `AiController`.
//! - Pluggable LLM provider interface
//! - Fallback to random actions on LLM failure
//! - Action history tracking for analysis
//! - TODO list maintenance across turns
//!
//! ## Usage
//!
//! ### With a custom LLM provider:
//!
//! ```ignore
//! use tcg_ai::react::{ReactAi, ReactAiConfig, LlmProvider};
//! use std::sync::Arc;
//!
//! struct MyLlmProvider {
//! api_key: String,
//! }
//!
//! impl LlmProvider for MyLlmProvider {
//! fn generate(&self, system: &str, user: &str, config: &ReactAiConfig) -> Result<String, String> {
//! // Call your LLM API here
//! Ok(r#"{"action": "EndTurn"}"#.to_string())
//! }
//! }
//!
//! let provider = Arc::new(MyLlmProvider { api_key: "...".to_string() });
//! let ai = ReactAi::with_config(42, ReactAiConfig::default(), provider);
//! ```
//!
//! ### With a closure:
//!
//! ```ignore
//! use tcg_ai::react::ReactAi;
//!
//! let ai = ReactAi::with_llm_fn(42, |system, user, config| {
//! // Your LLM call here
//! Ok(r#"{"action": "EndTurn"}"#.to_string())
//! });
//! ```
//!
//! ### As a fallback-only random agent:
//!
//! ```ignore
//! use tcg_ai::react::ReactAi;
//!
//! // Without an LLM provider, it will always use random fallback
//! let ai = ReactAi::new(42);
//! ```
//!
//! ## Integration with Game Server
//!
//! The `ReactAi` implements `AiController`, so it can be used directly with the game server:
//!
//! ```ignore
//! use tcg_ai::react::ReactAi;
//! use tcg_ai::AiController;
//!
//! let mut ai: Box<dyn AiController + Send> = Box::new(ReactAi::new(42));
//!
//! // When the game has a prompt for this player:
//! let actions = ai.propose_prompt_response(&view, &prompt);
//!
//! // When the game is in Main/Attack phase:
//! let actions = ai.propose_free_actions(&view);
//! ```
//!
//! ## Playing Against AI v4
//!
//! To set up a game where the ReactAi plays against the deterministic AI v4:
//!
//! ```ignore
//! use tcg_ai::{RandomAiV4, AiController};
//! use tcg_ai::react::ReactAi;
//!
//! // Create both AI players
//! let mut react_ai = ReactAi::with_llm_fn(42, my_llm_fn);
//! let mut v4_ai = RandomAiV4::new(123);
//!
//! // In your game loop, dispatch to the appropriate AI based on player ID
//! ```
// Re-export main types
pub use ;
pub use ;
pub use ;
pub use ;