# Crosswords Player codebase overview

These documents describes the way the two applications are written. It
doesn't go into a lot of detail in each section, but gives a rough
overview and hints to understand the codebase better.

This page covers the main game. In addition, it refers to code from
the [shared internals](overview-internals.md) section. There are five
major sections of code:

* Main application
* Puzzle sets
* Puzzle pickers
* Game board
* Downloaders and convertors

## Main application
The primary window in the game is the `PlayWindow`. This window uses an
`AdwOverlaySplitView` to provide a sidebar that lets the user select
puzzle sets. It contains the main `GtkStack` to swap between views and
manages the control flow between them. It also has game controls
included in the top level, which are forwarded to other parts of the
application.

It also has a preferences dialog (`PlayPreferencesDialog`) with the global
settings, as well as a help overlay.

The `PlayWindow` maintains its state in a `PlayState` struct. It has
four game phases that it can be in at any time that determines how it
appears:
* `GAME_PHASE_WELCOME`: Display the welcome screen with tips and icons
* `GAME_PHASE_PICKERS`: Display the puzzle picker for the current set
* `GAME_PHASE_ADD`: Display the "Add/Remove Puzzle Sources" screen
* `GAME_PHASE_XWORD`: Display the active game board

Each phase is represented by a widget. The pickers and game board are
described in more detail below.

**Related code:**
* **PlayWindow:** play-window ([.h](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/play-window.h),[.c](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/play-window.c))
* **PlayState:** play-window-private.h ([.h](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/play-window-private.h))
* **PlayPreferencesDialog:** play-preferences-dialog ([.h](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/play-preferences-dialog.h),[.c](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/play-preferences-dialog.c))
* **help overlay:** help-overlay ([.blp](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/help-overlay.blp))

## Puzzle sets
Puzzle sets represents collection of puzzles based around a
theme. They are shipped as a GResource with an internal config file
(`puzzle.config`), defining that collection. They also optionally have
puzzles contained within the resource.

These are represented by a `PuzzleSet` object which is used to control
and load aspects of the collection. All configuration settings are
loaded from puzzle.config and contained within the `PuzzleSetConfig`
object. It will also load all puzzles from disk — or resource — at
creation and store them in `PuzzleSetModel`. This implements the
GListModel interface, which can be used to follow changes to the model.

Puzzle sets are referred to by a globally unique **id** field defined
in the puzzle.config file. This identifier is used in many
places. It's used as a location on disk to store the puzzle set, it's
used as a path within the GResource, and it's used to refer to the
puzzle set through out the code.

The PuzzleSet also acts as a factory, creating both puzzle pickers and
the game board (see below). Currently, due to limitations in the
current code base, only one PuzzleSet can exist at a time. This will
have to be changed before we can present multiple PlayWindows at the
same time.

**Related code:**
* **PuzzleSet:** puzzle-set ([.h](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/puzzle-set.h),[.c](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/puzzle-set.c))
* **PuzzleSetConfig:** puzzle-set-config ([.h](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/puzzle-set-config.h),[.c](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/puzzle-set-config.c))
* **PuzzleSetModel:** puzzle-set-model ([.h](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/puzzle-set-model.h),[.c](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/puzzle-set-model.c))

## Puzzle pickers
The `PuzzlePicker` widget manages the user's interaction with the
PuzzleSet. It is deceptively complex code. It has to present the
puzzles in a way for the user to handle them, and controls the
downloader (see below). The picker's appearance is defined in
puzzle.config and is read from the PuzzleSetConfig object.

PuzzlePicker is a base widget with two variants so far: `PickerGrid`
and `PickerList`. The grid presents a grid view of puzzles with
snapshots as can be seen in the cats-and-dogs puzzle set. The list is
less puzzle-like and doesn't require solving prior puzzles before
advancing. This list uses a PuzzleSetModel as its base model.

**Related code:**
* **PuzzlePicker:** puzzle-picker ([.h](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/puzzle-picker.h),[.c](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/puzzle-picker.c))
* **PickerGrid:** picker-grid ([.h](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/picker-grid.h),[.c](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/picker-grid.c))
* **PickerList:** picker-grid ([.h](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/picker-grid.h),[.c](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/picker-list.c))

## Game board
The game board is a widget that displays the puzzle. Currently, the
only one supported is the `PlayXword` which lets you play
crosswords. In the future, other puzzle types (such as *acrostics* or
*word searches*) could be supported through their own widget type. It
is created and configured by PuzzleSets and put in the main stack.

The PlayXword contains only one widget — the custom
`PlayXwordColumn`. There's a somewhat complicated
(rationale)[play-xword-column.md] for this custom container, but the
end result is that changes to it take extra work to implement. The
main game widget within the PlayXword is a `PlayGrid`. It also has
custom widgets for displaying clues and rows-of-clues (`PlayClueRow`
and `PlayClueList`).

The PlayXword controls the `XwordState` and uses it to update other
widgets. It's entirely stateless. Setting a new `IpuzPuzzle` on the
PlayXword will result in a valid appearance, even if it's entirely
different. To implement undo/redo it has a `PuzzleStack` that manages
the IpuzPuzzle internally.

**Related code:**
* **PlayXword:** play-xword ([.h](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/play-xword.h),[.c](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/play-xword.c))
* **PlayXwordColumn:** play-xword-column ([.h](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/play-xword-column.h),[.c](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/play-xword-column.c))
* **PlayClueList:** play-clue-list ([.h](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/play-clue-list.h),[.c](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/play-clue-list.c))
* **PlayClueRow:** play-clue-row ([.h](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/play-clue-row.h),[.c](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/play-clue-row.c))

## Downloaders and convertors
The `PuzzleDownloader` is how puzzles are imported by the game. They
are initiated by the user pressing the download button in the puzzle
picker, or from the user passing a uri in on the command-line.

The downloader has a multi-stage process. First, it can optionally use
a command provided by the puzzle set to download a file from a
location, and store it in /tmp. This command is configured by the
PuzzleSetConfig, and is managed by the PuzzleDownloader object.

Once the downloader has copied the file to /tmp, it is optionally
passed through the `ipuz-convertor` utility to the game's
directory. This convertor knows how to handle .ipuz, .puz, .jpz, and
.xd files. It is written to be modular and should be able to be extended
to other formats relatively easily.

**Related code:**
* **PuzzleDownloader:** puzzle-downloader ([.h](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/puzzle-downloader.h),[.c](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/puzzle-downloader.c))
* **PuzzleDownloaderDialog:** puzzle-downloader-dialog ([.h](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/puzzle-downloader-dialog.h),[.c](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/puzzle-downloader-dialog.c))
* **ipuzconvertor:** ipuzconvertor ([.py](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/tools/ipuzconvtor.py),[.c](https://gitlab.gnome.org/jrb/crosswords/-/blob/master/src/puzzle-downloader-dialog.c))
