Giter Club home page Giter Club logo

word-search-generator's Introduction

  • 👋 Hi, I’m Josh!
  • 👀 I’m interested in design, programming, automation, and photography
  • 🌱 I’m currently learning Python, Javascript, and Adobe Extendscript
  • 💞️ I’m looking to collaborate on cool Python projects and extending Adobe applications
  • 📫 Reach me @joshbduncan errwhere ✌️

word-search-generator's People

Contributors

duck57 avatar joshbduncan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

word-search-generator's Issues

Solution without random fill characters

Hi, this really isn't an issue but more of a request for a feature. Would it be possible to show the puzzle after the solution characters without the random fill characters, so just the puzzle with the answers and the other spots with empty spaces?

add hide_filers to save?

Would it be possible to have the hide_filers be added to save()? So you could put in something like:

p.save(path="puzzle-solution.csv", format="csv", hide_fillers=True)

or is there a different way to get the solution exported as a csv file without the fillers?

Draw a rectangle around the words

Hi,
First of all thanks for this project. I was wondering if it'd be possible to improve it a little in how it generates the solution. I'd like to have the possibility to create a rectangle or other shapes around the word. Do you think you could add it?

For instance something like the following image
MetalsWordsearchSolved

Thanks

Ability to customize PDF export options

@joshbduncan
Thank you for creating this!!!
I have been looking for a tool for some time like this and I think I finally found it!

Would it be possible to add some options to the word-search cli tool to allow customizing the PDF, related to the PDF font size options?

I print puzzles for some elderly individuals who have vision problems/trouble seeing, and would like to be able to increase the size a bit.

Specifically, I would like to be able to change the following:

  1. The size of the font
  2. The kind font (i.e. something other than Courier)

I tried downloading the source code and modifying the file src/word_search_generator/export.py, but I could not get my changes to show up when I ran word-search .

Are there any instructions on how to create the word-search program. I was only able to get this with the pip install instructions.

Regards,
SardiSiV

Update CLI file output options

The plan is to separate out the export file type as a flag (defaulting to PDF). Currently the script infers the file export type from the file extension of the -o, --output path. The new flag would be -t, --type with the options PDF, CSV, JSON. If no -t type is specified, it would default to PDF as that is the most common.

* The CSV and JSON exports would not include the solution.

Outputting shortened words of a solution

Hi,

I currently have an use case where I'd like to generate a crossword puzzle but where shortened words of solutions which were added to the word list should also be outputted in the key value in the JSON, but sometimes aren't.

For example, let's say I have a wordlist of 5k words and create a 8x8 grid using this tool. One word in the list could be "icecream" and another one could be "cream" among these 5k words. There now seems to be a situation where "icecream" could be a solution (and is outputted) but "cream" isn't, while it was in my word list and it is a valid solution.

Using these arguments and shuffling a large (Turkish) dictionary and passing it to stdin:

word-search -l 2 -s 8 -f JSON -o ....

I'm seeing a solution which is "nemek" while I am expecting "ne" to also be in there, but isn't.

Thanks for the package though

TypeError: 'type' object is not subscriptable

After importing the wordsearch-package - without actually using it - I encounter:

>>> from typing import Optional, TypedDict
>>> class KeyInfo(TypedDict):
...     start: tuple[int,int]
...     direction: str
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in KeyInfo
TypeError: 'type' object is not subscriptable
>>> 

Unbake assumptions about secret words [priority, valid direction] from the Game class

There's probably a better title for this proposal, as it's broader than that. I'd also be happy to work on coding this, but I want to discuss it first—especially considering the big refactor since the last time I poked at this project.

The overall goal is to increase the Game object's flexibility by decoupling some word placement assumptions. Ideally, the WordSearch API will remain unchanged by these under-the-hood changes.

New attrs for the Word object

priority: int = 3

Instead of baking the algorithm of first placing the regular words before secret words into the Game object, assign each word a priority.

#pseudocode for Game object methods
def words_by_priority_dict(self) -> dict[int, list[Word]]:
    # there's almost certainly an easier way to do this with itertools
    # or at least a clever one-liner
    d = defaultdict(list)
    for w in self.words: 
        d[w.priority].append(w)
    return d

def list_words_by_priority(self) -> list[Word]:
    # see above comment, probably doesn't need 2 functions
    o = []
    for pri in self.words_by_priority_dict().values():
        o += sorted(pri, key=lambda w: len(w), reverse=True)
    return o

Priority 1 words go first, then priority 2, etc…

Within each priority, the default sort is longest to shortest.

For the existing behavior of the WordSearch object, regular words should receive priority=2 and secret words priority=4.

valid_dirs: DirectionSet | None = None

(If set to None, should the word be skipped during placement or treated as a wildcard? Personally, I'd lean toward skipped.)

An alternate implementation would be to pass a dict[int, DirectionSet] to the Game object where the valid directions for each priority are shared. However, I feel that it's best for subclasses of Game to assign priorities to the Words during ingestion rather than forcing all words of the same priority to share the same valid directions in the Game class.

Moving the valid_dirs attr to the Word also frees up the Generator class to drop the directions & secret_directions params from its generate function, as that data is now contained within each Word.

For the WordSearch, assign either directions or secret_directions during Word creation as appropriate.

Conflict with existing design in the above

The Game class takes its words and secret_words as strings instead of iterables of Word objects. Perhaps I'll think of a better location for the ingestion & creation of Word objects after I've gotten some sleep and thought more about Python's init order. The init of a Game updated to reflect this proposal would look something like __init__(words, size, *, ...). However, the init for its subclasses should remain largely as they currently are.

Duplicate word policy

Perhaps this is addressed in existing code, but Game could accept an optional parameter of a Callable for duplicate_policy. Perhaps it could be a Validator… would need to look at it with freshly-caffeinated neurons. These would be made on Word objects after they have been assigned valid directions and priorities.

Three policies spring to mind:

  1. Error. Raises an error when it encounters a duplicate word.
  2. Merge: (see below pseudocode)
  3. drop(first=True) keeps either the oldest or most recent duplicate.
# this modifies w1 so the init doesn't need more fields
def merge(w1: Word, w2: Word) -> None:
    w1.secret = w1.secret and w2.secret
    w1.valid_directions |= w2.valid_directions
    w1.priority = min(w1.priority, w2.priority)

Word len

This doesn't require any of the above to implement

def __len__(self) -> int:
    return len(self.text)

Thanks - this is great!

@joshbduncan , thanks for creating and sharing this software. This weekend I was assisting a young developer who wanted to improve his coding skills and said he loved word search puzzles. So I encouraged him to write a word search puzzle solver. But where to find a word search puzzle generator? Well, right here, of course! :)

This is a great tool you wrote. Today I wrote a quick solver for it here as a reference for the young developer. It uses as input the exact text output of your tool. So thank you for that!

Implement shape masks

I made a very basic proof of concept that's disconnected from the rest of the generator code this afternoon. I've put plenty of TODO items in the commit message. Some of the code I wrote seems quite duplicituous. Let's use this issue for higher-level design discussions and comments on the commit to discuss the implementation in its current code.

I was inspired to write this as well as #21 after stumbling across a different Python word search generator

I could implement this one, but if I don't get the time to finish it before Halloween, I may not be able to return until March [unlikely that it will be untouched for that entire time, but I expect to have much less availablilty to work on side projects over the winter].

Fix puzzle grid offset on min puzzle size

Nothing functional, just aesthetics, but on the smallest puzzle size of 5, the puzzle title is wider than the puzzle so the grid is off center.

As is now...

word-search cat bat rat -s 5
-----------
WORD SEARCH
-----------
D F E C Y
S C R A B
A U A T A
L S T L T
E H B I C

Find these words: BAT, CAT, RAT
* Words can go NE, S, SE, and E.

Answer Key: BAT S @ (5, 2), CAT S @ (4, 1), RAT S @ (3, 2)

Should be...

word-search cat bat rat -s 5
-----------
WORD SEARCH
-----------
 D F E C Y
 S C R A B
 A U A T A
 L S T L T
 E H B I C

Find these words: BAT, CAT, RAT
* Words can go NE, S, SE, and E.

Answer Key: BAT S @ (5, 2), CAT S @ (4, 1), RAT S @ (3, 2)

alter generate.retry to take the maximum number of tries as a parameter

I want to use Word Search as the basis for a crossword generator (perhaps in December, more likely in February or March). The algorithm I'd use is:

  1. Read in a tab-separated file of words and their hints
  2. Find initial puzzle attempt size as max(sqrt(sum(len(word) for word in words)), len(longest_word))
  3. Use the @retry(3) wrapper to try generating a puzzle with those dimensions 3 times.
  4. If not all words were fit within 3 tries, try again at the next
  5. Bunch of formatting and display logic to think through at a later date

Changes to the code

  1. Add the parameter to the @retry function
  2. Change the @retry decorator on try_to_fit_word to be @retry(max_fit_tries)

CLI with empty stdin causes error

When the word-search command does not contain any arguments, it waits for keyboard input from the user (similar to cat) and won't run until it receives an end-of-file ( EOF ) signal produced by CTRL+D key combination. If nothing is actually input before the EOF signal an error occurs.

This also happens if an empty string is piped into word-search like echo "" | word-search.

$ echo "" | word-search
Traceback (most recent call last):
  File "/Users/jbd/.local/pipx/venvs/word-search-generator/lib/python3.10/site-packages/word_search_generator/utils.py", line 43, in cleanup_input
    raise ValueError("Use words longer than one-character and without punctuation."
ValueError: Use words longer than one-character and without punctuation.

Separate PDF constraints from hard-coded constraints

This issue may need a better title, as it's likely to lead to a more general discussion on the use case of a CLI > PDF generator vs. use as a backend step in another pipeline.

This one is a sister issue to #20, as it's inspired by the same blog post.

In that blog post, the implementation is shown to fit all 118 element names in a 32x32 grid as well as the names of the planets in a 7x7 grid. Thinking through some of our earlier discussions, perhaps the backend generator constraints can be decoupled from the CLI/PDF constraints. Mostly in config.py, some specific suggestions to discuss:

  • Change min_puzzle_size from 10 to len(longest_word).
  • Split max_puzzle_size into max_puzzle_size = 32 (or more) and max_PDF_puzzle_size = 25
  • Increase max_puzzle_words to some function related to the area of the puzzle. The current limits give 30 words divided into 625 cells, for a density of 0.048. The element names example gives about 118 words in 1024 cells, for a density of 0.115. At the element density, a 25x25 puzzle could support up to 72 words [though it may be unacceptably slow with the number of retries].

In general, have two sets of limits: one for sensible output in a CLI>PDF workflow and another for sensible performance/sanity reasons when this module is run "headless". I'm not sure whether the CLI argparse validation should be hard-coded to sane PDF specifications or if the PDF sanity-checking is done if the output is specified as PDF but it is more lenient with oversize puzzles when outputting to stdout or CSV.

If the validation is separated, perhaps add a check during PDF generation to warn (or error out) if it's greater than 25x25 due to overflowing the page.

find_a_fit does not care about secret directions

find_a_fit() in generate.py only cares about WordSearch.directions and never checks if the word is secret or limits itself to using WordSeach.secret_directions. I've typed a quick fix already.

The easiest fix (that I've already typed) is to change the type signature of find_a_fit from having word: str to word: Word and switch which set of valid directions to use depending if word.secret is True.

A more complex fix would be to leave word: str in the signature and add the list of valid directions as a param to find_a_fit. Switching the set of valid directions would be handled in fill_words and passed through try_to_fit_word. Doing it this way would allow API consumers to forcibly add a word in the direction of their choosing. However, the current generation flow does not provide an opportunity for an API client to inject words between word placement and filling the random letters.

Out-of-scope for this issue, but perhaps the WordSearch init could be modified to take a list of forced words to provide such a feature to API clients. Each forced_word would be tuple[str, set[Direction], bool]. The boolean in the tuple is whether or not the word is treated like a secret word (defaults to True).

Saving as CSV saves as a PDF with CSV extension

I am trying to export the word search as a csv file using

p.save(path="puzzle.csv")

but what it gives me is a pdf with the csv extension instead of a csv file. If I rename the file to puzzle.pdf it shows the pdf.

Max puzzle size is 25, not 30

Docs state max puzzle size is 30, but this isn't consistent with what's in config.py.

# puzzle settings
min_puzzle_size = 10
max_puzzle_size = 25
min_puzzle_words = 1
max_puzzle_words = 30
max_fit_tries = 100

At least it's an easy fix 😁
Nice little tool this 👍

change default path word search.exe

HI,

I am using python embedded. It is working great on pip install and using python commandline.

What i would like to ask is

The file word-search.exe is in \scripts folder

Running in commandline scripts\word-search -r 10 -s 15 -l 3 works as expected if pip was done in default directory

But if i were to change the python directory to a different or path and so on the word-search.exe stops working and error below is shown

E:\python-3.11.5-embed-amd64>scripts\word-search -r 10 -s 15 -l 3
Fatal error in launcher: Unable to create process using '"E:\python-3.11.5-embed-amd64\python.exe"  "E:\python-3.11.5-embed-amd64\scripts\word-search.exe" -r 10 -s 15 -l 3': The system cannot find the file specified.

Is there a way we can change path in configuration file etc for word-search.exe to work? So it remains portable? Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.