Skip to content

Commit

Permalink
Improve crossword/crossword category viewing logic
Browse files Browse the repository at this point in the history
Reduced the possibility of errors when viewing/loading crossword categories and crosswords. Additionally, some methods were added to utils.py to help the program infer the contents of an info.json file for a crossword directory with an empty info.json file, as well as randomly generate an info.json file for bare crossword category directories. This will allow the user more easily to create their own crosswords (if they really want to).
  • Loading branch information
tomasvana10 committed Apr 28, 2024
1 parent c791a5a commit 2ed8c50
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 18 deletions.
4 changes: 1 addition & 3 deletions crossword_puzzle/errors.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
class CrosswordBaseError(Exception): ... # Useful in error handling to see if
# an error is related to crossword
# generation
class CrosswordBaseError(Exception): ...


class EmptyDefinitions(CrosswordBaseError):
Expand Down
49 changes: 36 additions & 13 deletions crossword_puzzle/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,15 @@
)
from crossword_puzzle.cword_gen import Crossword
from crossword_puzzle.cword_webapp.app import _create_app_process, terminate_app
from crossword_puzzle.errors import CrosswordBaseError
from crossword_puzzle.utils import (
_get_colour_palette_for_webapp,
_get_language_options,
_load_cword_info,
_update_config,
find_best_crossword,
load_definitions,
_make_cword_info_json,
_make_category_info_json
)


Expand Down Expand Up @@ -525,7 +526,7 @@ def terminate_cword_webapp(self) -> None:
terminate_app()

def _rollback_states(self) -> None:
# User might not have selected a crossword within their category, so
# User might not have selected a crossword within their category, so
# this if condition is requried.
if hasattr(self, "selected_category_object"):
self.selected_category_object.b_close_category.configure(
Expand Down Expand Up @@ -593,11 +594,8 @@ def load_selected_cword(self) -> None:
)
)
except Exception as ex:
if issubclass(type(ex), CrosswordBaseError):
print(f"{type(ex).__name__}: {ex}")
return AppHelper.show_messagebox(cword_gen_err=True)
else:
return print(f"{type(ex).__name__}: {ex}")
print(f"{type(ex).__name__}: {ex}")
return AppHelper.show_messagebox(cword_gen_err=True)

# Only modify states after error checking has been conducted
self.b_load_selected_cword.configure(state="disabled")
Expand Down Expand Up @@ -724,6 +722,13 @@ def _generate_crossword_category_blocks(self) -> None:
for category in [
f for f in scandir(Paths.BASE_CWORDS_PATH) if f.is_dir()
]:
# Make the ``info.json`` file if it doesn't exist already
if (
"info.json" not in listdir(category.path)
or path.getsize(path.join(category.path, "info.json")) <= 0
):
_make_category_info_json(path.join(category.path, "info.json"))

block = CrosswordCategoryBlock(
self.info_block_container, self, category.name, i
)
Expand Down Expand Up @@ -816,6 +821,8 @@ def __init__(
self.category = category
self.value = value

# Represents the currently selected crossword radiobutton selector
# within the crosswords of this category (once open)
self.selected_block = IntVar()
self.selected_block.set(-1)

Expand Down Expand Up @@ -867,10 +874,15 @@ def _place_content(self) -> None:
)

def _get_colour_tag_hex(self) -> str:
"""Get the hex colour of the bottom tag of this category, read from
its ``info.json`` file."""
with open(
path.join(Paths.BASE_CWORDS_PATH, self.category, "info.json")
) as file:
return load(file)["bottom_tag_colour"]
try:
return load(file)["bottom_tag_colour"]
except:
return "#abcdef"

def _sort_category_content(self, arr: list[str]) -> list[str]:
"""Sort the cword content of a category by the cword suffixes (-easy
Expand All @@ -880,10 +892,11 @@ def _sort_category_content(self, arr: list[str]) -> list[str]:
return sorted(
arr,
key=lambda i: CrosswordDifficulties.DIFFICULTIES.index(
i.split("-")[-1].capitalize()
i.name.split("-")[-1].capitalize()
),
)
except Exception:
except Exception: # Could not find the "-" in the crossword name, so
# don't sort this category
return arr

def _configure_cword_blocks_state(
Expand All @@ -898,6 +911,8 @@ def _configure_cword_blocks_state(
def _view_category(self) -> None:
"""View all crossword info blocks for a specific category."""
self.b_view_category.configure(state="disabled")
# Reset crossword canvas xview so it is at the beginning
self.master.info_block_container._parent_canvas.xview("moveto", 0.0)
for block in self.master.category_block_objects: # Remove all category
# blocks
block.pack_forget()
Expand All @@ -909,16 +924,24 @@ def _view_category(self) -> None:
self.cword_block_objects: list[CrosswordInfoBlock] = []
# Gather all crossword directories with an info.json file.
crosswords = [
f.name
f
for f in scandir(path.join(Paths.BASE_CWORDS_PATH, self.category))
if f.is_dir() and "info.json" in listdir(f.path)
if f.is_dir()
and "definitions.json" in listdir(f.path)
and path.getsize(path.join(f.path, "definitions.json")) > 0
]

i: int = 1
for cword in self._sort_category_content(crosswords):
# Make the ``info.json`` file if it doesn't exist already
info_path = path.join(cword.path, "info.json")
if not path.exists(info_path) or path.getsize(info_path) <= 0:
_make_cword_info_json(cword.path, cword.name, self.category)

block = CrosswordInfoBlock(
self.master.info_block_container,
self.master,
cword,
cword.name,
self.category,
self,
i,
Expand Down
50 changes: 48 additions & 2 deletions crossword_puzzle/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
from __future__ import annotations

from configparser import ConfigParser
from json import load
from json import load, dump
from os import path, scandir
from random import randint

from babel import Locale

from crossword_puzzle.constants import Colour, Paths
from crossword_puzzle.constants import Colour, Paths, CrosswordDifficulties


def _update_config(
Expand Down Expand Up @@ -154,5 +155,50 @@ def _load_attempts_db() -> dict[str, int]:
integral to the crossword optimisation process, as crossword generation
time scales logarithmically with word count.
"""

with open(Paths.ATTEMPTS_DB_PATH) as file:
return load(file)


def _make_cword_info_json(path_, cword_name, category) -> None:
"""Make an info.json file for a given crossword since it does not exist.
Makes it easier for the end-user to make their own crossword if they
really want to.
"""

with open(path.join(path_, "info.json"), "w") as info_obj, \
open(path.join(path_, "definitions.json"), "r") as def_obj:
total_definitions: int = len(load(def_obj))

# Infer the difficulty and crossword name if possible
try:
parsed_cword_name_components = path.basename(path_).split("-")
difficulty: int = CrosswordDifficulties.DIFFICULTIES.index(
parsed_cword_name_components[-1].title()
)
adjusted_cword_name = "-".join(parsed_cword_name_components[0:-1])
except Exception:
difficulty: int = 0
adjusted_cword_name = cword_name

return dump(
{
"total_definitions": total_definitions,
"difficulty": difficulty,
"symbol": "0x2717",
"name": adjusted_cword_name,
"translated_name": "",
"category": category,
},
info_obj,
indent=4,
)


def _make_category_info_json(path_) -> None:
"""Write a new info.json to a category since it does not exist in the a
category's directory.
"""
hex_ = "#%06X" % randint(0, 0xFFFFFF)
with open(path_, "w") as f:
return dump({"bottom_tag_colour": hex_}, f, indent=4)

0 comments on commit 2ed8c50

Please sign in to comment.