# Crosswords Environment Documentation

## Overview
Crosswords is a single-player puzzle game where the player fills in a crossword grid with words based on provided clues. The player’s objective is to correctly guess all the words using the hints given, ensuring that the letters align correctly in the grid. The environment supports a standard and a hardcore mode, influencing the difficulty of the words provided.

## Action Space
- **Format**: Actions are strings in the format [row col letter], where:
    - row and col are grid indices (starting from 0) indicating the cell position.
    - letter is the character the player wants to place in the specified cell.

- **Examples**:
    - To place the letter 'A' in row 4, column 7: [4 7 A]

- **Notes**: Players can provide multiple guesses at once in the format [row col letter]. Additional text may accompany the action, but it must contain the correct format for the action to be processed. Incorrectly formatted actions or wrong guesses will be marked as invalid.

## Observation Space

**Reset Observation:**
On reset, the observation provides the initial prompt and the state of the Crosswords grid. For example:

```plaintext
[GAME] You are Player 0. You are playing Crosswords (Basic).
Here is the current state of the Crosswords grid. Each row is numbered, and each column is also numbered.
The cells that need to be populated with letters are represented by '_', and those that do not need words are represented by '.'.

Current Crosswords Grid:
   C00 C01 C02 C03 C04 C05 C06 C07 C08 C09 C10 C11 C12 C13
R00  _   .   .   .   .   .   .   .   .   .   .   .   .   .  
R01  _   .   .   .   .   .   .   .   .   .   .   .   .   .  
R02  _   .   .   .   .   .   .   _   .   .   .   .   .   .  
R03  .   .   .   .   .   .   _   _   _   _   .   .   .   .  
R04  .   .   .   .   .   .   .   _   .   .   .   .   .   .  
R05  .   .   .   .   .   .   .   _   .   .   .   .   .   .  
R06  .   .   .   .   .   .   .   _   .   .   .   .   .   .  
R07  .   .   .   .   .   .   .   _   .   .   .   .   .   .  
R08  .   .   .   .   .   .   .   _   .   .   .   .   .   .  
R09  .   .   .   .   .   .   .   _   .   .   .   .   .   .  
R10  .   .   .   .   .   .   .   _   .   .   .   .   .   .  
R11  .   .   .   .   .   .   .   .   .   .   .   .   .   .  
R12  .   .   .   .   .   .   .   .   .   .   .   .   .   .  
R13  .   .   .   .   .   .   .   .   .   .   .   .   .   .  

Here are the clues for the words you need to find:
1. Fully aware of one's feelings and emotions. (9 letters): (2, 7, 'down')
2. The covering of a building, often sloped or flat. (4 letters): (3, 6, 'across')
3. To consider or regard. (3 letters): (0, 0, 'down')

You may provide your response in any manner. However, note that any wrong guesses will result in you losing. Hence, plan your approach and risk appetite. Only guesses in the format of [row column letter] will be fetched from your response.
As you play, the history of your choices will be appended below. Use the information to complete the game.

```

**Step Observation:**
After each step, the environment returns the action and the updated Crosswords grid as the observation. For example:

```plaintext
[Player 0] Let's analyze the clues and the current grid to fill in the answers strategically.

1. Clue 1: Fully aware of one's feelings and emotions. (9 letters)  : (2, 7, 'down')
   - A potential answer could be "self-aware".

2. Clue 2: The covering of a building, often sloped or flat. (4 letters)  : (3, 6, 'across')
   - A potential answer could be "roof".

3. Clue 3: To consider or regard. (3 letters)  : (0, 0, 'down')
   - A potential answer could be "see".

Now, let's start filling in the grid based on the answers we've deduced.

Filling in the Grid:
1. For Clue 3 (0, 0, 'down'), I will fill in "see".
   - [0 0 s]
   - [1 0 e]
   - [2 0 e]

2. For Clue 2 (3, 6, 'across'), I will fill in "roof".
   - [3 6 r]
   - [3 7 o]
   - [3 8 o]
   - [3 9 f]

3. For Clue 1 (2, 7, 'down'), I will fill in "self-aware".
   - [2 7 s]
   - [3 7 e]
   - [4 7 l]
   - [5 7 f]
   - [6 7 -]
   - [7 7 a]
   - [8 7 w]
   - [9 7 a]
   - [10 7 r]
   - [11 7 e]

I will now enter these letters in the grid:

1. Filling "see":
   - [0 0 s]
   - [1 0 e]
   - [2 0 e]

2. Filling "roof":
   - [3 6 r]
   - [3 7 o]
   - [3 8 o]
   - [3 9 f]

3. Filling "self-aware":
   - [2 7 s]
   - [3 7 e]
   - [4 7 l]
   - [5 7 f]
   - [6 7 -] (this cell is already filled)
   - [7 7 a]
   - [8 7 w]
   - [9 7 a]
   - [10 7 r]
   - [11 7 e]

Now, let's execute the moves one by one:

- [0 0 s]
- [1 0 e]
- [2 0 e]
- [3 6 r]
- [3 7 o]
- [3 8 o]
- [3 9 f]
- [2 7 s]
- [3 7 e]
- [4 7 l]
- [5 7 f]
- [7 7 a]
- [8 7 w]
- [9 7 a]
- [10 7 r]
- [11 7 e]

Let's execute these moves.

Executing Moves:
1. [0 0 s]
2. [1 0 e]
3. [2 0 e]
4. [3 6 r]
5. [3 7 o]
6. [3 8 o]
7. [3 9 f]
8. [2 7 s]
9. [3 7 e]
10. [4 7 l]
11. [5 7 f]
12. [7 7 a]
13. [8 7 w]
14. [9 7 a]
15. [10 7 r]
16. [11 7 e]

Let's now finalize the moves by confirming the letters.

Moves:
1. [0 0 s]
2. [1 0 e]
3. [2 0 e]
4. [3 6 r]
5. [3 7 o]
6. [3 8 o]
7. [3 9 f]
8. [2 7 s]
9. [3 7 e]
10. [4 7 l]
11. [5 7 f]
12. [7 7 a]
13. [8 7 w]
14. [9 7 a]
15. [10 7 r]
16. [11 7 e]

This should complete the crossword grid successfully.

[GAME] Board state:    
   C00 C01 C02 C03 C04 C05 C06 C07 C08 C09 C10 C11 C12 C13
R00  _   .   .   .   .   .   .   .   .   .   .   .   .   .  
R01  _   .   .   .   .   .   .   .   .   .   .   .   .   .  
R02  _   .   .   .   .   .   .   _   .   .   .   .   .   .  
R03  .   .   .   .   .   .   _   _   _   F   .   .   .   .  
R04  .   .   .   .   .   .   .   _   .   .   .   .   .   .  
R05  .   .   .   .   .   .   .   _   .   .   .   .   .   .  
R06  .   .   .   .   .   .   .   _   .   .   .   .   .   .  
R07  .   .   .   .   .   .   .   _   .   .   .   .   .   .  
R08  .   .   .   .   .   .   .   _   .   .   .   .   .   .  
R09  .   .   .   .   .   .   .   _   .   .   .   .   .   .  
R10  .   .   .   .   .   .   .   _   .   .   .   .   .   .  
R11  .   .   .   .   .   .   .   .   .   .   .   .   .   .  
R12  .   .   .   .   .   .   .   .   .   .   .   .   .   .  
R13  .   .   .   .   .   .   .   .   .   .   .   .   .   .  

```

By default, the environment returns observations in the following format:
```python
{
  player_id: int : [
    (sender_id: int, message: str),
    (sender_id: int, message: str),
    ...
  ]
}
```

## Gameplay
- **Grid Size**: The grid size is variable and dynamically generated based on the longest word and the number of words included.
- **Turns**: The player fills empty cells ('_') with letters to match the words in the clues.
- **Word Placement**: Words are placed either horizontally ("across") or vertically ("down") based on the clues. Players must fill in the letters one by one, ensuring they match the word locations and directions.
- **Winning Condition**: The game is won when all cells with letters are filled correctly based on the crossword solution.
- **Restart Condition**: The player can restart if they choose or when all allowed turns are exhausted without solving the crossword.

## Key Rules
- **Valid Moves**:

    - The player must enter a valid row, column, and letter in the [row col letter] format.
    - The move must not overwrite a filled cell or place a letter that doesn’t match the crossword solution.

- **Invalid Moves**:

    - Entering a row, column, or letter outside the grid bounds.
    - Overwriting an already filled cell.
    - Placing a letter that doesn’t align with the correct solution will result in the move being marked as invalid.

## Rewards
| Outcome          | Reward for Player  |
|------------------|:------------------:|
| **Win**          |       `+1`         |
| **Lose**         |       `0`          |
| **Invalid Move** |       `-1`         |

## Parameters

- `hardcore` (`bool`):
    - **Description:** Determines how many clues the player has to begin with.
    - **Impact:**
        - **Easy:** Player is provided with 50 pre-filled positions. It has to only guess 31 values.
        - **Medium**: Player is provided with 40 pre-filled positions. It has to only guess 41 values.
        - **Hard**: Player is provided with 30 pre-filled positions. It has to only guess 51 values.

- `max_turns` (`int`):
    - **Description:** Determines how many turns the player has to make its decisions.
    - **Impact:** This affects the number of tries it can make to complete the game. 

- `num_words` (`int`):
    - **Description:** Determines how many words the player has to guess.
    - **Impact:** More words means the player has to factor in more overlapping words. 

## Variants

| Env-id                    | hardcore | max_turns | num_words |
|---------------------------|:--------:|:---------:|:---------:|
| `Crosswords-v0`           | `False`  |  `30`     |  `8`      |
| `Crosswords-v0-hardcore`  | `True`   |  `30`     |  `8`      |

## Example Usage
```python
import textarena as ta

## initializa the environment
env = ta.make("Crosswords-v0")

## Wrap the environment for easier observation handling
env = ta.wrappers.LLMObservationWrapper(env=env)

## Wrap the environment for pretty rendering
env = ta.wrappers.PrettyRenderWrapper(env=env)

## initalize agents
agent0  = ta.basic_agents.GPTAgent(model_name="gpt-4o-mini")

## reset the environment to start a new game
observations = env.reset(seed=490)

## Write the game loop
done = False
while not done:
    for player_id, agent in enumerate([agent0]):
        ## get the current observation for the player
        obs = observations[player_id]

        ## Get the agent to use the observation and make an action
        action = agent(obs) 

        ## use the action and execute in the environment
        observation, rewards, truncated, terminated, info = env.step(player_id, action)

        ## render the environment
        env.render()

        ## check if the game has ended
        done = truncated or terminated

## Finally, print the game results
for player_id, agent in enumerate([agent0]):
    print(f"{agent.agent_identifier}: {rewards[player_id]}")
print(f"Reason: {info['reason']}")
```

## Troubleshooting

**Unplaced Word Issue**

- **Issue**: A word cannot be placed on the grid, and a message such as "Could not place the word: <word>" is displayed.
- **Solution**: Reduce the num_words parameter to allow more space or adjust the grid size by increasing the multiplier in `_determine_initial_grid_siz`e.

**Invalid Action Format**

- **Issue**: Player actions are flagged as invalid due to improper formatting or out-of-bound coordinates.
- **Solution**: Ensure actions are submitted in the correct [row col letter] format. Double-check that row and col values are within grid boundaries and the target cell is empty.

**Missing Words and Clues File**

- **Issue**: The words_clues.jsonl file is not found at the specified path, causing initialization to fail.
- **Solution**: Confirm that the words_clues.jsonl file exists in textarena/envs/single_player/Crosswords/. Verify that the path is correct and that the file is formatted properly.


## Version History
- **v0**
  - Initial release 


### Contact
If you have questions or face issues with this specific environment, please reach out directly to bobby_cheng@i2r.a-star.edu.sg