Applications

For now, this site contains only one application built with Shiny. I may extend it in the future if I create more.

Bee a Spelling Genius

About

This is a interactive app made to, help/improve player’s of New York times Spelling Bee.

In the spelling bee, the player is given seven letters. One letter is marked in yellow.

The goal is to make as many words as possible from the seven letters. Every word should contain the yellow letter.

Scoring

  • A word of 4 letters earns one point.
  • Words longer than 4 letters earn additional points (the exact amount is to be determined).

The dictionary used is provided Here under an open license.

The Spelling Bee uses a list of curated words. The dictionary is more like a reference for how words are spelled. For example, “AAAA” might appear in the dictionary but is unlikely to be included in the Spelling Bee.

There may also be words that are offensive or outdated. While they are correctly spelled, they probably won’t appear in the Spelling Bee.

The application can take a little while to load. The data is downloaded from a GitHub repository, so if you have browser extensions that might prevent this, it’s a good idea to temporarily turn them off.

#| '!! shinylive warning !!': |
#|   shinylive does not work in self-contained HTML documents.
#|   Please set `embed-resources: false` in your metadata.
#| standalone: true
#| viewerHeight: 800


from shiny import *
# For plot
import matplotlib.pyplot as plt
# Get all words in the english diconary
import numpy as np
import requests
# URL of the text file on GitHub
url = "https://raw.githubusercontent.com/dwyl/english-words/refs/heads/master/words.txt"

# Fetch the file content
response = requests.get(url)

if response.status_code == 200:
    # Read the content of the file
    file_content = response.text
    # Split the content into a list of words
    words_list = file_content.splitlines()
    print(words_list)
else:
    print("Failed to retrieve the file:", response.status_code)

def check_word_canidat_early_stopping(
        word:str,
        yellow_chr:chr,
        chr_list:list):
    """
    This function returns True or False.
    To be a valid candidate for a True return, the input word 
    must contain the yellow character and cannot contain any characters 
    other than the yellow character and characters from the provided character list.
    Args:
        word (str): The word to be checked.
        yellow_chr (str): A character that all valid words must contain.
        chr_list (list): A list of characters that the word is allowed to contain.
    Returns:
        bool: True or False depending on whether the word fulfills the conditions.

    """
    lover_yellow =yellow_chr.lower()
    return_obj=False
    is_word_combination_of_chr_list=False
    is_yellow_chr_contained= False
    lower_chars = [char.lower() for char in chr_list]
    
    for letter in word:
        is_letter_contained= letter.lower() in lower_chars
        if (is_letter_contained==False):
            is_word_combination_of_chr_list=False
            break
        else:
            is_word_combination_of_chr_list=True
        if (is_yellow_chr_contained==False):
            is_yellow_chr_contained=(lover_yellow==letter.lower())
    
    if(is_word_combination_of_chr_list==True and is_yellow_chr_contained==True):
        return_obj =True
    return return_obj



def get_word_candidates(
        word_list:list,
        yellow_chr: chr,
        chr_list:list,
        min_word_length:int = 4):
    """
    This returns list containg alle candidat words, for the spelling bee game.

    All word contain the yellow letter, and consist of combination yello and letter from the letter list.
    All words is longer ore equal to min_word_length
    
    Args:
        word_list (list): a list with string containg words to serach though
        yellow_chr (chr): all word in return should contain this letter
        chr_list (list): a list of chr that can be conatin a word in return
    Returns:
        list: a list of strings. all word should be combination of yellow chr and letter from the list.
        
    """
    return_objet = []
    index_list=[] #this list contais the index of wich words is potensiel words in the index list.
    allowed_chartes= chr_list + [yellow_chr]
    # len word is not calculated but store in the type string so it fast to check if len of the word is les than min first
    for i in range(len(word_list)):
        word_for_examination=word_list[i]
        if(len(word_for_examination)>=min_word_length):
            if(check_word_canidat_early_stopping(word_for_examination,yellow_chr,allowed_chartes)==True):
                return_objet.append(word_for_examination)
                index_list.append(i)
    return(return_objet)


# Generat plots

def get_len_word_list(words_list:int):
    list_len=[]
    for word in words_list: list_len.append(len(word))
    return list_len




# Define the app UI
app_ui = ui.page_fluid(
    ui.input_selectize("yellow_chr", "Choose one yellow letter", 
                       ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"], 
                       multiple=False),
    ui.output_text_verbatim("yellow_chr_output"),
    ui.input_selectize("grey_chr", "Choose six grey letters", 
                       ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"], 
                       multiple=True),
    ui.output_text_verbatim("grey_chr_output"),
    ui.output_text_verbatim("len_data_txt"),
    ui.output_plot("plot"),
    ui.output_ui("output_content"),
    ui.input_switch("switch", "Show word results", False),  
    ui.output_text_verbatim("word_list_output")
)

# Define the app server logic
def server(input, output, session):
    @reactive.Calc
    def dataset():
        # This function returns a dataset when 6 grey letters are selected
        if len(input.grey_chr()) == 6:
            return get_word_candidates(words_list, input.yellow_chr(),list(input.grey_chr()))
        else:
            return []
    @reactive.Calc
    def len_data():
        len_data=get_len_word_list(dataset())
        return len_data
        
    @output
    @render.text
    def yellow_chr_output():
        return f"The chosen yellow letter is {input.yellow_chr()}"
    @output
    @render.text
    def grey_chr_output():
        if len(input.grey_chr()) != 6:
            return f"You need to choose 6 grey letters; currently, you have chosen {len(input.grey_chr())}."
        else:
            return "You have chosen 6 grey letters."
    @output
    @render.text
    def len_data_txt():
        ret_ob="The data has not bin computed"
        if(len(input.grey_chr())==6):
            ret_ob=f"There are {len(dataset())} possible words with 4 or more letters"
        return ret_ob
    @output
    @render.plot(alt="A histogram of dataset values")
    def plot():    
        fig, ax = plt.subplots()
        if len(input.grey_chr()) == 6:
            unique_values, counts = np.unique(len_data(), return_counts=True)
            ax.bar(unique_values, counts, color='skyblue', edgecolor='black')
            ax.set_title("Histogram of Word Candidates")
            ax.set_xlabel("Length of word")
            ax.set_ylabel("Count")
        else:
            ax.text(0.5, 0.5, "Please select 6 grey letters", horizontalalignment='center', verticalalignment='center')
        return fig
    @output
    @render.text
    def word_list_output():
        ret_ob=""
        if(input.switch()==True):
            ret_ob="\n".join(dataset())
        return ret_ob
        
    

app = App(app_ui, server)

Version with the code

Here is a version where the code can be seen

#| '!! shinylive warning !!': |
#|   shinylive does not work in self-contained HTML documents.
#|   Please set `embed-resources: false` in your metadata.
#| standalone: true
#| viewerHeight: 800
#| components: [editor, viewer]

from shiny import *
# For plot
import matplotlib.pyplot as plt
# Get all words in the english diconary
import numpy as np
import requests
# URL of the text file on GitHub
url = "https://raw.githubusercontent.com/dwyl/english-words/refs/heads/master/words.txt"

# Fetch the file content
response = requests.get(url)

if response.status_code == 200:
    # Read the content of the file
    file_content = response.text
    # Split the content into a list of words
    words_list = file_content.splitlines()
    print(words_list)
else:
    print("Failed to retrieve the file:", response.status_code)

def check_word_canidat_early_stopping(
        word:str,
        yellow_chr:chr,
        chr_list:list):
    """
    This function returns True or False.
    To be a valid candidate for a True return, the input word 
    must contain the yellow character and cannot contain any characters 
    other than the yellow character and characters from the provided character list.
    Args:
        word (str): The word to be checked.
        yellow_chr (str): A character that all valid words must contain.
        chr_list (list): A list of characters that the word is allowed to contain.
    Returns:
        bool: True or False depending on whether the word fulfills the conditions.

    """
    lover_yellow =yellow_chr.lower()
    return_obj=False
    is_word_combination_of_chr_list=False
    is_yellow_chr_contained= False
    lower_chars = [char.lower() for char in chr_list]
    
    for letter in word:
        is_letter_contained= letter.lower() in lower_chars
        if (is_letter_contained==False):
            is_word_combination_of_chr_list=False
            break
        else:
            is_word_combination_of_chr_list=True
        if (is_yellow_chr_contained==False):
            is_yellow_chr_contained=(lover_yellow==letter.lower())
    
    if(is_word_combination_of_chr_list==True and is_yellow_chr_contained==True):
        return_obj =True
    return return_obj



def get_word_candidates(
        word_list:list,
        yellow_chr: chr,
        chr_list:list,
        min_word_length:int = 4):
    """
    This returns list containg alle candidat words, for the spelling bee game.

    All word contain the yellow letter, and consist of combination yellow and letter from the letter list.
    All words is longer ore equal to min_word_length
    
    Args:
        word_list (list): a list with string containg words to serach though
        yellow_chr (chr): all word in return should contain this letter
        chr_list (list): a list of chr that can be conatin a word in return
    Returns:
        list: a list of strings. all word should be combination of yellow chr and letter from the list.
        
    """
    return_objet = []
    index_list=[] #this list contais the index of wich words is potensiel words in the index list.
    allowed_chartes= chr_list + [yellow_chr]
    # len word is not calculated but store in the type string so it fast to check if len of the word is les than min first
    for i in range(len(word_list)):
        word_for_examination=word_list[i]
        if(len(word_for_examination)>=min_word_length):
            if(check_word_canidat_early_stopping(word_for_examination,yellow_chr,allowed_chartes)==True):
                return_objet.append(word_for_examination)
                index_list.append(i)
    return(return_objet)


# Generat plots

def get_len_word_list(words_list:int):
    list_len=[]
    for word in words_list: list_len.append(len(word))
    return list_len




# Define the app UI
app_ui = ui.page_fluid(
    ui.input_selectize("yellow_chr", "Choose one yellow letter", 
                       ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"], 
                       multiple=False),
    ui.output_text_verbatim("yellow_chr_output"),
    ui.input_selectize("grey_chr", "Choose six grey letters", 
                       ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"], 
                       multiple=True),
    ui.output_text_verbatim("grey_chr_output"),
    ui.output_text_verbatim("len_data_txt"),
    ui.output_plot("plot"),
    ui.output_ui("output_content"),
    ui.input_switch("switch", "Show word results", False),  
    ui.output_text_verbatim("word_list_output")
)

# Define the app server logic
def server(input, output, session):
    @reactive.Calc
    def dataset():
        # This function returns a dataset when 6 grey letters are selected
        if len(input.grey_chr()) == 6:
            return get_word_candidates(words_list, input.yellow_chr(),list(input.grey_chr()))
        else:
            return []
    @reactive.Calc
    def len_data():
        len_data=get_len_word_list(dataset())
        return len_data
        
    @output
    @render.text
    def yellow_chr_output():
        return f"The chosen yellow letter is {input.yellow_chr()}"
    @output
    @render.text
    def grey_chr_output():
        if len(input.grey_chr()) != 6:
            return f"You need to choose 6 grey letters; currently, you have chosen {len(input.grey_chr())}."
        else:
            return "You have chosen 6 grey letters."
    @output
    @render.text
    def len_data_txt():
        ret_ob="The data has not bin computed"
        if(len(input.grey_chr())==6):
            ret_ob=f"There are {len(dataset())} possible words with 4 or more letters"
        return ret_ob
    @output
    @render.plot(alt="A histogram of dataset values")
    def plot():    
        fig, ax = plt.subplots()
        if len(input.grey_chr()) == 6:
            unique_values, counts = np.unique(len_data(), return_counts=True)
            ax.bar(unique_values, counts, color='skyblue', edgecolor='black')
            ax.set_title("Histogram of Word Candidates")
            ax.set_xlabel("Length of word")
            ax.set_ylabel("Count")
        else:
            ax.text(0.5, 0.5, "Please select 6 grey letters", horizontalalignment='center', verticalalignment='center')
        return fig
    @output
    @render.text
    def word_list_output():
        ret_ob=""
        if(input.switch()==True):
            ret_ob="\n".join(dataset())
        return ret_ob
        
    

app = App(app_ui, server)


Made with Shiny for Python (Shiny Live)

This application is created using Shiny for Python (Shiny Live). There is also an R version available.

What makes the Shiny Live version so appealing is that it allows embedding Python code into WebAssembly. This application runs Python directly from your personal computer, with the dictionary downloaded from a GitHub link.

The library support is somewhat limited.

For small projects that should be accessible to the public, I like Shiny Live because it doesn’t require hosting a server for the backend.

Estially the backend runs on you pc.

Their is som drawback, every aplication need the data to load in seperatly. Alle code and data is exeable for the user, documentasion is spars. It hard to debug, since it reaktiv programing.

But overall, being able to create applications without needing to host a server is pretty cool.