# Immutable XwordState
**Status**: Implemented | 2023

`XwordState` is mutable, and we carefully maintain it for the lifetime of
a puzzle.  This has a few shortcomings:

* Implementing Undo/Redo is hard.  We'd like to keep a history of states.

* The tests have to implement the "compare old and new states" logic
  themselves, instead of just using a hypothetical `play_state_equal(a, b)`.

## Turning `XwordStateFocus` into `XwordStateAction`

Issue #11 is about renaming the `XwordStateFocus` enum to
`XwordStateAction`, since now it contains `PLAY_STATE_DELETE`.  I
propose that we bite the bullet and make `XwordStateAction` a complete
description of the actions that can be taken on a `XwordState`.

```c
  typedef enum {
    PLAY_STATE_ACTION_NONE,
    PLAY_STATE_ACTION_UP,
    PLAY_STATE_ACTION_DOWN,
    PLAY_STATE_ACTION_LEFT,
    PLAY_STATE_ACTION_RIGHT,
    PLAY_STATE_ACTION_FORWARD,
    PLAY_STATE_ACTION_BACK,
    PLAY_STATE_ACTION_FORWARD_CLUE,
    PLAY_STATE_ACTION_BACK_CLUE,
    PLAY_STATE_ACTION_BACKSPACE,
    PLAY_STATE_ACTION_DELETE,
    PLAY_STATE_ACTION_SWITCH,
    PLAY_STATE_ACTION_GUESS,       /* has data, see below */
    PLAY_STATE_ACTION_SELECT_CLUE, /* has data, see below */
  } XwordStateActionKind;

  typedef struct {
    XwordStateActionKind kind;

    union {
      char *guess;
      ClueId select_clue;
      /* etc. for other actions that take arguments */
    } u;
  } XwordStateAction;
```

Then we can have a single

```c
XwordState play_state_dispatch(const XwordState *state, XwordStateAction action);
```

which returns a new state, not the old one modified.  It takes the
whole action description and acts upon it; we can then remove
`play_state_clue_selected()` et al piecemeal.

Along with "immutable puzzles" below, this would make testing easier,
and would open the door for implementing Undo/Redo.

## Immutable puzzles

Right now `IpuzCrossword` owns its `IpuzGuesses`, but other than
setters and getters, the only place where it is used is in the
internal `ipuz_crossword_game_won_solution`.  I think we should remove
the guesses from the crossword, and instead have

```c
gboolean ipuz_crossword_game_won (IpuzCrossword *xword, IpuzGuesses *guesses);
```

(Or call it `is_solution` or whatever.)

## Undo/Redo

:::{important}
This section is obsolete. We ended up not undoing the
actions, but using a PuzzleStack instead.
:::

*With the above, we can make `XwordState` own the `IpuzGuesses`.  Then we can have
this undo stack easily:*

```
state 0 -> action -> state 1 -> action -> state 2 -> action -> state 3
 with                 with                 with                 with
guesses              guesses              guesses              guesses
```

*Whether we keep all the states, or just the ones that change the
guesses, is up to you.  Emacs does the same "collapse undo steps while
typing" thing.*

## Editability and libipuz paraphernalia

I don't know if you'll later want to fuse `guesses` into a `crossword`
to turn them into the crossword's built-in solution.

Maybe we need an `EditState` different from `XwordState`?  It seems
that the behavior should be different, since the editor will have
actions like `EDIT_ACTION_TURN_CELL_INTO_BLOCK` or
`EDIT_ACTION_TURN_CELL_INTO_NULL`, or whatever actions we have later
to add fancy markers to individual grid lines.

(I know, I know, I should get going on the new layout code...)

I think it's fine to have `IpuzCrossword` have a mutability API, but
it would be easier if the crossword editor app kept it immutable by
copying the old xword to a new one and then modifying cells in the new
one.  This way we can also have an undo stack for the editor.
