Hi, Grib,

I've tested your solution and it works.

I've also replaced ascii_lowercase with ascii_letters and removed the casefold() function. It makes the algorithm less robust for encryption, but CC is just a toy anyway.

Sorry, I misunderstood. Feel free to delete my reply.

If the question is not about theoretical omega values but actual runtime on a specific system, then maybe the

timeit 

module could help.

I saw someone getting an assignment to implement the Vigenere Cipher, so I decided, just for the frig of it, to implement the Caesar Cipher. The algorithm below, however, doesn't account for spaces and punctuation. How can I account for those without redoing the whole thing?

from random import choice
from string import ascii_lowercase

# for both encryption algorithms use negative offset to decrypt

def caesar_cipher(text, offset):
    '''encrypts text with offset provided by user'''
    text, key = text.casefold(), ascii_lowercase
    cipher = [key[(key.index(char) + offset) % 26] for char in text if char in key]
    return cipher

def caesar_cipher_rnd(text):
    '''generates and returns random offset'''
    offset = choice(-13, 13)
    text, key = text.casefold(), ascii_lowercase
    cipher = [key[(key.index(char) + offset) % 26] for char in text if char in key] 
    return cipher, offset

Until I figure out what's going on I'm going to stop distributing the executable.

Meanwhile, a helpful person rewrote the script, creating a bunch of classes that subclass all the widgets to their parent tk/ttk classes. I'm waiting for them to tell me how they want to be credited before sharing the script.

rproffitt commented: It could be the compiler or false positives at virustotal. For now I'll try later with a fiddle. +0

That sounds like a gigantic project that would require many people. To make it work you'd need excellent organizational, management and people skills. I'd say COO level skills.

It would also take years of full-time work.

I'm not trying to discourage you, but how about this: first try writing something simple and small first to get an idea of how quickly you can work, how much debugging you need to do, what tools you need and which tools work and don't work for you. Then you'll have a better idea of how much effort your bigger project will be.

I did a full system malware scan and it found nothing.

Then I did a full bootup malware scan (which occurs after a restart but before windows boots) and still found nothing.

I tried to use both Outlook and Gmail's malware scanner by mailing the executable back and forth between my Outlook and Gmail accounts, but both services block .exe files even if archived.

I downloaded the executable from the repository you downloaded it from and specifically scanned it for malware and didn't find any.

Any help here? I really don't want to be spreading malware, but can't see how I am doing so.

rprofitt, you have my sincerest apologies for all the hassle.

Kindly try again here (the downloadables are at the bottom):

https://bitbucket.org/onager/onager.ornery.clicker/downloads

rproffitt commented: That was much better. +9

Sorry if the dropbox link is busted. I've created a Bitbucket account and can link you to the repo:

https://onager@bitbucket.org/onager/onager.ornery.clicker.git

The repo shouldn't be passworded so you should be able to download anything in it.

Thank you for the review. I'm making a list of what needs changing and what features should be added/removed before the game is ready for release. There are other elements I've thought of that haven't been mentioned yet, such as being able to vary the number of buttons in the grid (potentially important for phones!) and colour-coding the various buttons.

Onager Ornery Clicker presents a grid of buttons. One says "Click Me!" and the rest say "Don't Click Me!" Clicking the right button scores a point, while clicking the wrong button costs a point. After each click the buttons reshuffle. There is a timer you can start and stop. You can see how fast you can score x points, or how many points you can score in x time.

I need both playtesters and code reviewers. Please comment on the look, playability and coding functionality/style. If you'd like to see features added or removed, please let me know.

Here's the Windows binary you can just double-click and run without installing:
https://www.dropbox.com/s/flxg729trhimnfq/ooc-0.9.exe?dl=0

And here is the script in case you don't have Windows but do have python 3:
https://www.dropbox.com/s/ec0k2vk1d9gzibz/clickgame3.py?dl=0

Thanks for all feedback.

With the help of a fellow on Reddit I've got an almost-completed version of the game. Here's the latest:

    from tkinter import Tk, Frame, Label, IntVar
    from tkinter.ttk import Button
    from functools import partial
    from random import randrange

    class Game:

        def __init__(self):
            self.window = Tk()
            self.window.title("Onager Ornery Clicker")
            self.createwidgets()

        def createframes(self):
            self.frame1 = Frame(self.window)
            self.frame2 = Frame(self.window)
            self.frame1.configure(bg='silver',
                                  relief='raised', border='15')
            self.frame2.configure(bg='silver',
                                  relief='raised', border='15')
            self.frame1.rowconfigure(6)
            self.frame1.columnconfigure(5)
            self.frame2.rowconfigure(15)
            self.frame2.columnconfigure(5)
            self.frame1.grid(row=0, column=0, rowspan=6,
                             columnspan=5)
            self.frame2.grid(row=6, column=0, rowspan=15,
                             columnspan=5)

        def createtitle(self):
            self.title = Label(self.frame1)
            self.title.configure(bg='silver', fg='SlateBlue4',
                                 font='serif 30', justify='center',
                                 padx='10', pady='10',
                                 text='Onager Ornery Clicker')
            self.title.grid(row=0, column=0, rowspan=1,
                            columnspan=5)

        def createinstr(self):
            textstring="""Correct click scores a point.
    Incorrect click costs you a point.
    How quickly can you score points?
    Click Start to begin.
    HAVE FUN!!!"""
            self.instr = Label(self.frame1)
            self.instr.configure(bg='Silver', fg='SlateBlue4',
                                 font='serif 12', justify='center',
                                 text=textstring, pady='10')
            self.instr.grid(row=1, column=0, rowspan=5,
                            columnspan=1)

        def createstart(self):
            self.start = Button(self.frame1)
            self.start['text'] = 'Start'
            self.start['command'] = partial(self.start_game)
            self.start.grid(row=1, column=2, rowspan=1,
                            columnspan=1)

        def createstop(self):
            self.stop = Button(self.frame1)
            self.stop['text'] = 'Stop.'
            self.stop['command'] = partial(self.stop_game)
            self.stop.grid(row=1, column=3, rowspan=1,
                           columnspan=1)

        def createscore(self):
            self.score_label = Label(self.frame1)
            self.score_label.configure(fg='black',
                                       font='serif 10')
            self.score_label['text'] = 'Score:'
            self.score_label.grid(row=3, column=2, rowspan=1,
                                  columnspan=1)
            self.score = Label(self.frame1)
            self.score.configure(bg='black', fg='white',
                                 font='serif 16')
            self.score.grid(row=5, column=2, rowspan=1,
                            columnspan=1)

        def createtime(self):
            self.time_label = Label(self.frame1)
            self.time_label.configure(fg='black',
                                      font='serif 10')
            self.time_label['text'] = 'Time:'
            self.time_label.grid(row=3, column=3, rowspan=1,
                                 columnspan=1)
            self.time = Label(self.frame1)
            self.time.configure(bg='black', fg='white',
                                font='seriv 16')
            self.time.grid(row=5, column=3, rowspan=1,
                            columnspan=1)

        def createbuttons(self):
            index = randrange(0,74)
            for item in range(75):
                self.button = Button(self.frame2)
                if item == index:
                    self.button['text'] = 'Click Me!'
                else:
                    self.button['text'] = "Don't Click Me!"
                self.button['command'] = partial(self.clicked, self.button)
                rn, cn = divmod(item, 5) ...

Here's a version of the game where the look issues seem to have been fixed. Let me know how it looks on your system:

from tkinter import Tk, Frame, Label, IntVar
from tkinter.ttk import Button
from functools import partial
from random import randrange

class Game:

    def __init__(self):
        self.window = Tk()
        self.window.title("Onager Ornery Clicker")
        self.score = IntVar()
        self.createwidgets()

    def createframes(self):
        self.frame1 = Frame(self.window)
        self.frame2 = Frame(self.window)
        self.frame1.configure(bg='silver',
                              relief='raised', border='15')
        self.frame2.configure(bg='silver',
                              relief='raised', border='15')
        self.frame1.rowconfigure(6)
        self.frame1.columnconfigure(5)
        self.frame2.rowconfigure(15)
        self.frame2.columnconfigure(5)
        self.frame1.grid(row=0, column=0, rowspan=6,
                         columnspan=5)
        self.frame2.grid(row=6, column=0, rowspan=15,
                         columnspan=5)

    def createtitle(self):
        self.title = Label(self.frame1)
        self.title.configure(bg='silver', fg='SlateBlue4',
                             font='serif 30', justify='center',
                             padx='10', pady='10',
                             text='Onager Ornery Clicker')
        self.title.grid(row=0, column=0, rowspan=1,
                        columnspan=5)

    def createinstr(self):
        textstring="""Correct click scores a point.
        Incorrect click costs you a point.
        How quickly can you score 30 points?
        Click Start to begin.
        HAVE FUN!!!"""
        self.instr = Label(self.frame1)
        self.instr.configure(bg='Silver', fg='SlateBlue4',
                             font='serif 12', justify='center',
                             text=textstring, pady='10')
        self.instr.grid(row=1, column=0, rowspan=5,
                        columnspan=1)

    def createstart(self):
        self.start = Button(self.frame1)
        self.start['text'] = 'Start'
        self.start['command'] = partial(self.play)
        self.start.grid(row=1, column=2, rowspan=1,
                        columnspan=1)

    def createscore(self):
        self.timer = Label(self.frame1)
        self.timer.configure(bg='black', fg='white',
                             font='serif 16',
                             textvariable=str(self.score))
        self.timer.grid(row=3, column=2, rowspan=1,
                        columnspan=1)

    def createbuttons(self):
        index = randrange(0,74)
        for item in range(75):
            self.button = Button(self.frame2)
            if item == index:
                self.button['text'] = 'click Me!'
            else:
                self.button['text'] = "Don't Click Me!"
            rn, cn = divmod(item, 5)
            self.button.grid(row=rn, column=cn, rowspan=1,
                            columnspan=1)

    def play(self):
        pass

    def createwidgets(self):
        self.createframes()
        self.createtitle()
        self.createinstr()
        self.createstart()
        self.createscore()
        self.createbuttons()

def main():
    onager = Game()
    onager.window.mainloop()

if __name__=='__main__':
    main()

Would you mind uploading that code so I can work further on it? (If I copy what's in your message I'll have to delete all the line numbers.)

Your help much appreciated. :)

BTW how does it look with standard tk widgets instead of ttk ones? Just replace:

from tkinter import Tk...
from tkinter.ttk import Frame...

with:

from tkinter import Tk, Frame ...

Putting everything on one line.

That's because it looks like there isn't a "normal" ttk theme in your version of python3-tk. To find out which themes are available do this in the python3 interpreter:

>>>from tkinter.ttk import Style
>>>s = Style()
>>>s.theme_use()

That will output available styles in console. Then you can replace "normal" with some other style available on your system (that's line 15).
Alternatively, just comment out line 15 and use your OS's default theme.

This script is to be a 5x5 grid of buttons, one saying "Click Me" and the rest "Don't Click Me." A correct click scores a point, an incorrect click costs a point. The buttons get shuffled after each click. The player has 60 seconds to maximize his score.

The script is incomplete because I'm having two problems:

  1. The individual ttk widget styles are refusing to apply (only the global widget styles are applying).
  2. There is an extraneous column at the right of frame2 that I can't get rid of despite monkeying with the row/column/span/configure setttings for a geological age.

Any help appreciated.

from tkinter import Tk
from tkinter.ttk import Frame, Label, Button, Style
from random import randrange
from functools import partial

class Game:

    def __init__(self):
        self.window = Tk()
        self.window.title("Onager Ornery Clicker")
        self.createwidgets()

    def create_styles(self):
        frame_style = Style()
        frame_style.theme_use('normal')
        frame_style.configure("TFrame",
                              background='blue',
                              foreground='gold',
                              borderwidth='10',
                              relief='raised')

        title_style = Style()
        title_style.configure("TLabel", font='serif 30')

        instr_style = Style()
        instr_style.configure("TLabel", font='serif 12')

    def create_frames(self):
        self.frame = Frame(self.window)
        self.frame.rowconfigure(4)
        self.frame.columnconfigure(5)
        self.frame.grid(row=0, column=0)
        self.frame2 = Frame(self.window)
        self.frame2.rowconfigure(5)
        self.frame2.columnconfigure(5)
        self.frame2.grid(row=4, column=0)

    def create_title(self):
        self.title = Label(self.window,
                           style="title_style.TLabel",
                           text='Onager Ornery Clicker')
        self.title.grid(row=0, column=0, columnspan=5)

    def create_instr(self):
        self.instr = """        Correct click scores a point.
        Wrong click costs a point.
        You have 60 seconds.
        Click Start to begin.
        HAVE FUN!"""
        self.instr = Label(self.window,
                           style="instr_style.TLabel",
                           text=self.instr)
        self.instr.grid(row=1, column=0, rowspan=3, columnspan=4)

    def create_start_button(self):
        self.start = Button(self.window, text='Start')
        self.start.grid(row=1, column=4)

    def create_timer(self):
        self.timer = Label(self.window, text='Time')
        self.timer.grid(row=2, column=4)

    def create_score(self):
        self.score = Label(self.window, text='Score')
        self.score.grid(row=3, column=4)

    def shuffle(self):
        for i, button in enumerate(self.buttons, ...

Thank you, all.

I wish I could figure out what the native clearscreen keystroke combination is. The rest work fine (control-c for copy, control-x for cut, control-v for paste, control-a for select all, etc).

in the executable I compiled through pyinstaller under ActivePython, there is an issue with copy accidentally cutting text, but that doesn't happen with the interpreted .pyw script. (I haven't yet done the cross-platform compile under Debian, but a test on Hello World worked great.)

What software do you recommend for drawing layouts to be implemented in a ttk application? I'm looking for something simple and clutter-free where there aren't 10 zillion options I don't want. All I really need is basic shapes corresponding to the shapes of ttk widgets and a way to place them in the desired location within the drawing window.

(I have only a standard tower with mouse and keyboard, and am not looking to purchase a drawing tablet, pen, or touchscreen display.)

Thanks for all responses.

Thanks for your comments.

The missing features are missing because I don't use them. I've implemented only the features I normally rely on, and the window size and font are what I happen to like. This script is only for personal use, not distribution.

Yes, i've tried Kate/Gedit/Pluma/Emacs etc and all of them are too busy. I wanted something very simple that would include minimal clutter, and I've pretty much got it here.

My question was really whether the OO layout of the script is done in the standard, acceptable way. I've made a few changes and this is how the OO is laid out now:

from tkinter import Tk, END, INSERT
from tkinter.scrolledtext import ScrolledText
from tkinter.filedialog import asksaveasfilename, askopenfilename

class Scratchpad:

    def __init__(self, Tk, ScrolledText):
        self.display = Tk()
        self.display.title("Onager Text Editor")
        self.display.bind('<F7>', self.save_file)
        self.display.bind('<F5>', self.open_file)
        self.create_editor(ScrolledText)

    def create_editor(self, ScrolledText):
        self.editing_window = ScrolledText(self.display)
        self.editing_window.configure(fg='gold', bg='blue', insertbackground='cyan',
            height='25', width='70', padx='12', pady='12',
            wrap='word', tabs='48', font='serif 12')
        self.editing_window.pack()

    def save_file(self, event=None):
        name = asksaveasfilename()
        outfile = open(name, 'w')
        contents = self.editing_window.get(0.0, END)
        outfile.write(contents)
        outfile.close()

    def open_file(self, event=None):
        name = askopenfilename()
        infile = open(name, 'r')
        contents = infile.read()
        self.editing_window.insert(INSERT, contents)
        infile.close()

def main():
    onager = Scratchpad(Tk, ScrolledText)
    onager.display.mainloop()

if __name__=='__main__':
    main()

I'm developing a dirt-simple text editor for personal use, customized the way I like it. My biggest difficulty is with grasping how OOP works. Could you kindly review the following code and suggest improvements (or at least link further information)? Much appreciated.

from tkinter import Tk, END, INSERT
from tkinter.scrolledtext import ScrolledText
from tkinter.filedialog import asksaveasfilename, askopenfilename

class Scratchpad:

    def __init__(self, Tk):
        self.display = Tk()
        self.display.title("Onager Text Editor--<F7> save, <F5> open and insert")
        self.display.bind('<F7>', self.save_file)
        self.display.bind('<F5>', self.open_file)
        self.display.bind('<Control-c>', self.copy)
        self.display.bind('<Control-p>', self.cut)
        self.display.bind('<Control-v>', self.paste)

    def create_editor(self, ScrolledText):
        self.editing_window = ScrolledText(self.display)
        self.editing_window.configure(fg='gold', bg='blue', insertbackground='cyan',
            height='25', width='70', padx='12', pady='12',
            wrap='word', tabs='48', font='serif 12')
        self.editing_window.pack()

    def save_file(self, event=None):
        name = asksaveasfilename()
        outfile = open(name, 'w')
        contents = self.editing_window.get(0.0, END)
        outfile.write(contents)
        outfile.close()

    def open_file(self, event=None):
        name = askopenfilename()
        infile = open(name, 'r')
        contents = infile.read()
        self.editing_window.insert(INSERT, contents)
        infile.close()

    def copy(self, event=None):
        self.display.clipboard_clear()
        text = self.editing_window.get("sel.first", "sel.last")
        self.display.clipboard_append(text)

    def cut(self, event):
        self.copy()
        self.editing_window.delete("sel.first", "sel.last")

    def paste(self, event):
        self.editing_window.insert(INSERT, self.display.clipboard_get())

def main():
    onager = Scratchpad(Tk)
    onager.create_editor(ScrolledText)
    onager.display.mainloop()

if __name__=='__main__':
    main()