Czy istnieje oprogramowanie, które okresowo pozwala mi wykonywać ćwiczenia arytmetyczne?


9

Jestem świadomy mojej leniwej natury i od czasu do czasu muszę pchać się w kierunku podstawowej arytmetyki mentalnej. Dlatego szukam oprogramowania, które okresowo prosi mnie o wykonanie krótkiej mentalnej arytmetyki (plus, minus, mnożenie, dzielenie).

Kryteria:

  • Powinno to pozwolić mi dostosować czas interwału
  • Powinien być zintegrowany z Ubuntu Desktop, tj. Być ukryty w tle i pokazywać się (wyskakujący) tylko podczas ćwiczeń

2
Wątpię, aby takie oprogramowanie istniało, ale można je bardzo łatwo utworzyć za pomocą powłoki lub skryptu python. Jutro coś
ugotuję

Tak, bsdgames ma arytmetykę i takie, ale sam musisz zautomatyzować okresowe wyskakujące okienka.
mchid

Drogi @erg, uprzejmie przypominam o twoim eksperymencie kulinarnym. :)
orschiro

1
W związku z tym opublikowałem odpowiedź w toku, którą będę edytować w miarę upływu czasu. Proszę spojrzeć, daj mi znać, co myślisz, jaką funkcjonalność dodać lub usunąć. Jak dotąd jest to aplikacja konsolowa, ale ostatecznie zmieni się w małe wyskakujące okienko.
Sergiy Kolodyazhnyy

2
Okazuje się, że jest miłym pytaniem do pracy!
Jacob Vlijm

Odpowiedzi:


8

1. Prosta wersja

Poniższy skrypt wygeneruje losowe przypisania, + , - , × i ÷ . Możesz (i należy) ustawić maksymalną liczbę, której może używać skrypt, a także odstęp czasu między zadaniami.

Zadania

Zadania są prezentowane w oknie wprowadzania Zenity:

wprowadź opis zdjęcia tutaj

jeśli odpowiedź jest nieprawidłowa:

wprowadź opis zdjęcia tutaj

Jeśli odpowiedź jest prawidłowa:

wprowadź opis zdjęcia tutaj

Scenariusz

#!/usr/bin/env python3
from random import randint
import sys
import subprocess
import time

# maximum number & interval
max_n = int(sys.argv[1]); pause = int(sys.argv[2])

def fix_float(n):
    """
    if the assignment is a division, the script divides the random number by a
    number (integer) it can be divided by. it looks up those numbers, and picks
    one of them (at random). if the number is a prime number the assignment is
    changed into another type
    """
    try:
        divs = [i for i in range(2, n) if n%i == 0]
        pick = randint(1, len(divs))
        div_by = divs[pick-1]
        return [str(n)+" : "+str(div_by), int(n/div_by)]
    except (ValueError, IndexError):
        pass

def get_assignment():
    """
    get a random number within the user defined range, make the assignment and
    the textual presentation
    """
    n1 = randint(2, max_n); n2 = randint(2, max_n)
    assignments = [
        [str(n1)+" + "+str(n2), n1+n2],
        [str(n1)+" - "+str(n2), n1-n2],
        [str(n1)+" x "+str(n2), n1*n2],
        fix_float(n1),
        ]
    # pick an assignment (type) at random
    assignment = assignments[randint(0, 3)]
    # if the random number is a prime number and the assignment a division...
    assignment = assignment if assignment != None else assignments[1]
    # run the interface job
    try:
        answer = int(subprocess.check_output(["/bin/bash", "-c",
            'zenity --entry --title="Think hard:" --text='+'"'+assignment[0]+'"'
            ]).decode("utf-8"))
        if answer == assignment[1]:
            subprocess.Popen(["notify-send", "Coolcool"])
        else:
            subprocess.Popen([
                "notify-send", "Oooops, "+assignment[0]+\
                " = "+str(assignment[1])])
    except (subprocess.CalledProcessError, ValueError):
        pass

while True:
    time.sleep(pause)
    get_assignment()

Jak używać

  1. Skopiuj skrypt do pustego pliku i zapisz go jako mindpractice.py
  2. Uruchom go z maksymalną dozwoloną liczbą i odstępem czasu (w sekundach) między przypisaniami jako argumentami:

    python3 /path/to/mindpractice.py <max_number> <interval>

    na przykład

    python3 /path/to/mindpractice.py 1000 300

    wykonać obliczenia do postaci 1000z 5-minutową przerwą między zadaniami.

  3. Jeśli wszystko działa poprawnie, możesz dodać go do aplikacji startowych w zwykły sposób, lub można uruchomić program uruchamiający do przełączania, który mogę dodać później :)

Uwaga

  • Podziału może wymagać pewnego wyjaśnienia. Prawdopodobnie nie chciałbyś obliczać liczb zmiennoprzecinkowych. Dlatego jeśli przypisaniem jest podział, skrypt wyszukuje liczby, przez które można go podzielić, i wybiera jeden (losowo). Jeśli (główny) numer okaże się liczbą pierwszą, przypisanie zostanie zmienione na inny typ.

2. Więcej opcji

Po rozpoczęciu obliczeń przekonasz się, że podział na liczby (powiedzmy) 100 jest znacznie łatwiejszy niż pomnożenie liczb do 100.

Za pomocą skryptu poniżej możesz (i powinieneś) ustawić maksymalną liczbę liczb dla każdego rodzaju ćwiczenia (zobacz instrukcje poniżej skryptu).

Scenariusz

#!/usr/bin/env python3
from random import randint
import sys
import subprocess
import time

levels = sys.argv[1:]
pause = [int(arg.replace("p:", "")) for arg in levels if "p:" in arg][0]

def fix_float(n):
    """
    if the assignment is a division, the script divides the random number by a
    number (integer) it can be divided by. it looks up those numbers, and picks
    one of them (at random). if the number is a prime number the assignment is
    changed into another type
    """
    try:
        divs = [i for i in range(2, n) if n%i == 0]
        pick = randint(1, len(divs))
        div_by = divs[pick-1]
        return [str(n)+" : "+str(div_by), int(n/div_by)]
    except (ValueError, IndexError):
        pass

def get_assignment():
    """
    get a random number within the user defined range, make the assignment and
    the textual presentation
    """
    # pick an assignment (type) at random
    track = randint(0, 3)
    arg = ["a:", "s:", "m:", "d:"][track]
    max_n = [int(item.replace(arg, "")) for item in levels if arg in item][0]

    n1 = randint(2, max_n); n2 = randint(2, max_n)
    assignments = [
        [str(n1)+" + "+str(n2), n1+n2],
        [str(n1)+" - "+str(n2), n1-n2],
        [str(n1)+" x "+str(n2), n1*n2],
        fix_float(n1),
        ]
    assignment = assignments[track]     
    # if the random number is a prime number and the assignment a division...
    assignment = assignment if assignment != None else assignments[1]
    # run the interface job
    try:
        answer = int(subprocess.check_output(["/bin/bash", "-c",
            'zenity --entry --title="Think hard:" --text='+'"'+assignment[0]+'"'
            ]).decode("utf-8"))
        if answer == assignment[1]:
            subprocess.Popen(["notify-send", "Coolcool"])
        else:
            subprocess.Popen([
                "notify-send", "Oooops, "+assignment[0]+\
                " = "+str(assignment[1])])
    except (subprocess.CalledProcessError, ValueError):
        pass

while True:
    time.sleep(pause)
    get_assignment()

Jak używać

  • Skonfiguruj skrypt dokładnie tak, jak pierwszy, ale uruchom go z argumentami (w dowolnej kolejności, skrypt połączy odpowiednie argumenty z właściwym elementem):

    • p: pauza (przerwa między zadaniami, w sekundach))
    • s: odejmij (maksymalna liczba do obliczenia)
    • a: dodaj (maksymalna liczba)
    • m: pomnożyć (maksymalna liczba)
    • d: dziel (maksymalna liczba)

    Na przykład:

    python3 '/home/jacob/Desktop/num.py' a:10 d:100 s:10 m:10 p:300

    pokazywać ćwiczenie co pięć minut, liczby do 10, z wyjątkiem dzielenia do liczby 100.


3. Dajmy się ponieść emocjom

Będąc w stanie zobaczyć statystyki

Poniższa wersja pokazuje statystyki po każdych 10 ćwiczeniach:

wprowadź opis zdjęcia tutaj

Dodatkowo (może być przydatny, gdy jest stosowany u dzieci), możesz zobaczyć, co poszło nie tak w ostatnich 100 błędnie odpowiedzianych ćwiczeniach. W ukrytym pliku zapisywane są zarówno przypisania, jak i ich (nieprawidłowe) odpowiedzi:

wprowadź opis zdjęcia tutaj

Ten plik dziennika znajduje się:

~/.calculog

Scenariusz

#!/usr/bin/env python3
from random import randint
import sys
import subprocess
import time
import os

log = os.environ["HOME"]+"/.calculog"

levels = sys.argv[1:]
pause = [int(arg.replace("p:", "")) for arg in levels if "p:" in arg][0]

def fix_float(n):
    """
    if the assignment is a division, the script divides the random number by a
    number (integer) it can be divided by. it looks up those numbers, and picks
    one of them (at random). if the number is a prime number the assignment is
    changed into another type
    """
    try:
        divs = [i for i in range(2, n) if n%i == 0]
        pick = randint(1, len(divs))
        div_by = divs[pick-1]
        return [str(n)+" : "+str(div_by), int(n/div_by)]
    except (ValueError, IndexError):
        pass

def get_assignment():
    """
    get a random number within the user defined range, make the assignment and
    the textual presentation
    """
    # pick an assignment (type) at random
    track = randint(0, 3)
    arg = ["a:", "s:", "m:", "d:"][track]
    max_n = [int(item.replace(arg, "")) for item in levels if arg in item][0]

    n1 = randint(2, max_n); n2 = randint(2, max_n)
    assignments = [
        [str(n1)+" + "+str(n2), n1+n2],
        [str(n1)+" - "+str(n2), n1-n2],
        [str(n1)+" x "+str(n2), n1*n2],
        fix_float(n1),
        ]
    assignment = assignments[track]     
    # if the random number is a prime number and the assignment a division...
    assignment = assignment if assignment != None else assignments[1]
    # run the interface job
    try:
        answer = int(subprocess.check_output(["/bin/bash", "-c",
            'zenity --entry --title="Think hard:" --text='+'"'+assignment[0]+'"'
            ]).decode("utf-8"))
        if answer == assignment[1]:
            subprocess.Popen(["notify-send", "Coolcool"])
            return "ok"
        else:
            subprocess.Popen([
                "notify-send", "Oooops, "+assignment[0]+\
                " = "+str(assignment[1])])
            open(log, "+a").write(assignment[0]+"\t\t"+str(answer)+"\n")
            try:
                history = open(log).read().splitlines()
                open(log, "wt").write(("\n").join(history[-100:])+"\n")     
            except FileNotFoundError:
                pass 
            return "mistake"
    except (subprocess.CalledProcessError, ValueError):
        return None

results = []
while True:
    time.sleep(pause)
    results.append(get_assignment())
    if len(results) >= 10:
        score = results.count("ok")
        subprocess.call([
            "zenity", "--info",
            '--title=Latest scores',
            '--text='+str(score)+' out of 10',
            '--width=160',
            ])
        results = []

Jak używać

Użycie jest bardzo podobne do opcji 2, ale plik dziennika będzie dostępny i wyniki po każdych 10 zadaniach.


4. Wersja ostateczna

Poniższa wersja przypomina opcję 3 (w tym plik dziennika i raporty), ale ma kilka dodatkowych funkcji:

  • dodaje obliczanie pierwiastka kwadratowego

    wprowadź opis zdjęcia tutaj

  • dodaje używając zakresu liczb, zamiast po prostu ustawić maksimum

  • dodaje opcję uruchamiania tylko określonych typów obliczeń (np. tylko dzielenie i mnożenie).
  • pamięta argumenty, z którymi był uruchamiany ostatni raz, gdy był uruchamiany bez argumentów (tylko za pierwszym razem, argumenty muszą być ustawione). Jeśli przy pierwszym uruchomieniu nie ustawiono żadnych argumentów, skrypt wysyła komunikat:

    wprowadź opis zdjęcia tutaj

Scenariusz

#!/usr/bin/env python3
from random import randint
import sys
import subprocess
import time
import os

"""
Use this script to practice head count. Some explanation might be needed:
The script can be used for the following types of calculating:

Type          argument example      explanation
-------------------------------------------------------------------------------
add           a:30-100              to add in numbers from 30-100
subtract      s:10-100              to subtract in numbers from 10-100
multiply      m:10-20               to multiply in numbers from 10-20
divide        d:200-400             to divide in numbers from 200-400
square root   r:1-1000              to find square root in numbers from 1-1000

N.B.
-------------------------------------------------------------------------------
- The argument p: (pause in seconds; break between the assignments) *must* be
  set, for example: p:300 to launch an assignment every 5 minutes
- A calculation type will only run *if* the argument is set for the
  corresponding type. An example: python3 /path/to/script p:60 s:30-60
  will run a subtract- assignment every minute.

Miscellaneous information:
-------------------------------------------------------------------------------
- On first run, arguments *must* be set. After first run, when no arguments
  are used the last set arguments will run, until the script is run with a new
  set of arguments.
- A log file of the last 100 incorrectly answered questions is kept in
  ~/.calculog
- After 10 assignments, the score of the last 10 pops up.
"""

log = os.environ["HOME"]+"/.calculog"
prefs = os.environ["HOME"]+"/.calcuprefs"
levels = sys.argv[1:]

if levels:
    open(prefs, "wt").write(str(levels))
else:
    try:
        levels = eval(open(prefs).read())
    except FileNotFoundError:
        subprocess.call([
            "zenity", "--info",
            '--title=Missing arguments',
            '--text=On first run, the script needs to be run with arguments\n'
            ])

def fix_float(n):
    """
    if the assignment is a division, the script divides the random number by a
    number (integer) it can be divided by. it looks up those numbers, and picks
    one of them (at random). if the number is a prime number the assignment is
    changed into another type
    """
    try:
        divs = [i for i in range(2, n) if n%i == 0]
        pick = randint(1, len(divs))
        div_by = divs[pick-1]
        return [str(n)+" : "+str(div_by), int(n/div_by)]
    except (ValueError, IndexError):
        pass

def fix_sqr(f1, f2):
    """
    If the assignment is calculating a square root, this function finds the sets
    of numbers (integers) that make a couple, within the given range.
    """
    q = f1; r = q**(.5); sets = []
    while q < f2:
        r = q**(.5)
        if r == int(r):
            sets.append([int(r), int(q)])
        q = q+1
    if sets:
        pick = sets[randint(0, len(sets)-1)]
        return ["√"+str(pick[1]), pick[0]]

def get_assignment():
    """
    get a random number within the user defined range, make the assignment and
    the textual presentation
    """ 
    args = ["a:", "s:", "m:", "d:", "r:"]
    indc = []
    for i, item in enumerate(args):
        if item in str(levels):
            indc.append(i)

    index = indc[randint(0, len(indc)-1)]
    name = args[index]

    minmax = [
        [int(n) for n in item.replace(name, "").split("-")] \
        for item in levels if name in item][0]

    assignment = None
    # if the random number is a prime number *and* the assignment a division 
    # or a square root...
    while assignment == None:
        n1 = randint(minmax[0], minmax[1]); n2 = randint(minmax[0], minmax[1])
        assignment = [
            [str(n1)+" + "+str(n2), n1+n2],
            [str(n1)+" - "+str(n2), n1-n2],
            [str(n1)+" x "+str(n2), n1*n2],
            fix_float(n1),
            fix_sqr(minmax[0], minmax[1]),
            ][index]
    # run the interface job
    try:
        answer = int(subprocess.check_output(["/bin/bash", "-c",
            'zenity --entry --title="Think hard:" --text='+'"'+assignment[0]+'"'
            ]).decode("utf-8"))
        if answer == assignment[1]:
            subprocess.Popen(["notify-send", "Coolcool"])
            return "ok"
        else:
            subprocess.Popen([
                "notify-send", "Oooops, "+assignment[0]+\
                " = "+str(assignment[1])])
            open(log, "+a").write(assignment[0]+"\t\t"+str(answer)+"\n")
            try:
                history = open(log).read().splitlines()
                open(log, "wt").write(("\n").join(history[-100:])+"\n")     
            except FileNotFoundError:
                pass 
            return "mistake"
    except (subprocess.CalledProcessError, ValueError):
        return None

if levels:
    pause = [int(arg.replace("p:", "")) for arg in levels if "p:" in arg][0]
    [levels.remove(item) for item in levels if "p:" in item]
    results = []
    while True:
        time.sleep(pause)
        results.append(get_assignment())
        if len(results) >= 10:
            score = results.count("ok")
            subprocess.call([
                "zenity", "--info",
                '--title=Latest scores',
                '--text='+str(score)+' out of 10',
                '--width=160',
                ])
            results = []

Jak używać

  • Skopiuj skrypt do pustego pliku i zapisz go (ponownie) jako mindpractice.py. Uruchom go z następującymi opcjami (jako przykłady)

    Musisz ustawić:

    p:300                to set the interval between assignments to 5 minutes

    Opcjonalne (dokonaj wyboru):

    a:30-100             to add in numbers from 30-100 (optional)
    s:10-100             to subtract in numbers from 10-100
    m:10-20              to multiply in numbers from 10-20
    d:200-400            to divide in numbers from 200-400
    r:1-1000             to find square root in numbers from 1-1000
  • Przykładowe polecenie:

    python3 '/path/to/mindpractice.py' p:300 d:10-100 s:10-30  r:300-600

    ustawić:

    p:300                to set the interval between assignments to 5 minutes
    d:10-100             to divide in numbers from 10-100
    s:10-30              to subtract in numbers from 10-30
    r:300-600            to calculate square roots from 300-600

    podczas dodawania i mnożenia nie są używane.

Następnym razem, jeśli skrypt zostanie uruchomiony z:

python3 '/path/to/mindpractice.py'

Zapamięta ostatnio użyte argumenty


Użyj wersji, która najlepiej odpowiada Twoim potrzebom ...



Ta wersja działa jak dotąd świetnie. Dziękuję bardzo!
orschiro

1
@orschiro dodał rozszerzoną wersję, aby zróżnicować poziom trudności.
Jacob Vlijm

plik dziennika to bardzo fajny pomysł! Obecnie staram się omijać niektóre trzycyfrowe multiplikacje i podziały. Nie są takie proste. :)
orschiro

tylko pomysł: Czasami jestem tak skoncentrowany na pracy, że ignoruję Think Hardokno, aby zakończyć pracę przed (np. zakończyć pisanie zdania). Potem zapominam o oknie. Czy to możliwe, że po 5 minutach Think Hardokno automatycznie odzyska ostrość?
orschiro

1
@orschiro absolutnie! Nadal przeżuwałem całkowicie wersję GUI (nie trzeba niczego ustawiać z wiersza poleceń, nawet pierwszego uruchomienia), ale nie jestem pewien, czy pozwolą nam dodać więcej metrów do odpowiedzi :)
Jacob Vlijm

3

Wprowadzenie:

Następująca aplikacja generuje losowe wyrażenia całkowite do oceny przez użytkownika. Zakres losowo generowanych wyrażeń zależy od ustawień użytkownika w głównym oknie podręcznym. Po kliknięciu Lets Beginprzycisku sesja rozpoczyna się na czas nieokreślony, dopóki użytkownik nie naciśnie przycisku Anuluj.

wprowadź opis zdjęcia tutaj

wprowadź opis zdjęcia tutaj

Kod źródłowy:

#!/usr/bin/env python

# Author: Serg Kolo
# Date: Jan 30,2016
# Purpose: A graphical utility for practicing
#          random arithmetic operations
# Written for: http://askubuntu.com/q/725287/295286

#    Copyright: Serg Kolo , 2016
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

import sys
import time
import random
from PyQt4 import QtGui


class mathApp(QtGui.QWidget):
   def __init__(self):
       super(mathApp,self).__init__()
       self.mainMenu()

   def mainMenu(self):
      self.setGeometry(300, 300, 400, 200)

      self.btn = QtGui.QPushButton("Let's begin",self)
      self.btn.move(20,150)
      self.btn.clicked.connect(self.askQuestions)

      self.lbl1 = QtGui.QLabel(self)
      self.lbl1.move(20,25)
      self.lbl1.setText("Numbers From")


      self.lbl2 = QtGui.QLabel(self)
      self.lbl2.move(20,55)
      self.lbl2.setText("Numbers To")

      self.lbl2 = QtGui.QLabel(self)
      self.lbl2.move(20,85)
      self.lbl2.setText("Repeat (seconds)")

      self.le1 = QtGui.QLineEdit(self)
      self.le1.move(150,20)

      self.le2 = QtGui.QLineEdit(self)
      self.le2.move(150,50)

      self.le3 = QtGui.QLineEdit(self)
      self.le3.move(150,80)

      self.lbl3 = QtGui.QLabel(self)
      self.lbl3.move(20,105)

      self.setWindowTitle('Random Integer Arithmetic')

      self.show()

   def askQuestions(self):
       rangeStart = int(self.le1.text())
       rangeEnd = int(self.le2.text())
       sleepTime = int(self.le3.text())
       done=False
       while not done:
          self.show()
          expression = self.generateOperation(rangeStart,rangeEnd)
          correctAnswer = eval(expression)

          prompt = QtGui.QInputDialog() 
          text,ok = prompt.getText(self,"Don't think too hard",expression) 
          if ok:
             if int(text) == correctAnswer:                
                self.showAnswer("CORRECT,YOU ROCK !")
             else :
                self.showAnswer("Nope");
          else:
              done=True

          if done==True:
              self.close()
          time.sleep(sleepTime)


   def generateOperation(self,start,end):
      a = random.randint(start,end)
      b = random.randint(start,end)
      oplist = ['+','-','/','*']
      op = oplist[random.randint(0,3)]
      expr = str(a) + op + str(b) + ''
      return expr

   def showAnswer(self,result):
       popup = QtGui.QMessageBox()
       popup.setText(result)
       popup.exec_()


def main():
   root = QtGui.QApplication(sys.argv)
   app = mathApp()
   sys.exit(root.exec_())

if __name__ == '__main__':
   main()

Drogi @Serg, chcę również osobiście podziękować za twoją rozszerzoną wersję GUI. Jedno pytanie, właśnie miałem ćwiczenie 15/14 = 1. Nie jestem pewien, jak przydatne jest takie ćwiczenie. Co myślisz?
orschiro

@orschiro to jest integer arithmetic. Oznacza to, że wynik jest tylko częścią, a nie resztą. Jeśli chcesz, mógłbym również spróbować zaimplementować decimalarytmetykę. Daj mi również znać, jakie inne opcje chciałbyś, abym zaimplementował i dodał. Obecnie próbuję ćwiczyć agile developmentmetodę, a komunikacja z klientem jest kluczowa w takiej metodzie. Proszę daj mi znać.
Sergiy Kolodyazhnyy

Dobrze to słyszeć! Chciałbym przekazać ci więcej informacji zwrotnych, np. Lepszą integrację z Ubuntu Desktop (uruchom skrypt bardziej w tle, tj. Zminimalizuj po wprowadzeniu przez użytkownika). Jak mogę najlepiej przekazać dodatkowe informacje?
orschiro
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.