Ülesande püstitus
Analüüs
Disain & realisats
Andmed
Programmi strukt.
Pileti ja loosimise numbrite loomine
  
Eriarvud
  
Sorteerimine
  
Tabamused
Sorteerimine lisa
 mull
 valik
 shell



 

Rakendus "Loto"

Ülesande püstitus


 

Koostada rakendus, mis võimal­dab imiteerida lotomängu sarnaselt näiteks Keno loto või Viking lotoga. Mängija sisestab või laseb arvutil genereerida teatud hulga juhuslikke üks­teisest erinevaid numbreid (näiteks 3 kuni 10). Loosimisel luuakse samuti teatud hulk juhuslikke arve (näiteks 10 kuni 20). Numbrid peavad olema mingis kindlas vahemikus (näiteks 1 … 64, 1 … 36 vm). Programm peab tegema kindlaks kokkulangevate numbrite arvu piletil ja loosimisel.
Kasutajaliides võiks sisaldada järgmisi elemente: loendite monitorid, kus kuvatakse pileti (Pilet), loosi (Loos) ja kokkulangevad numbrid (Pihtas). Muutujate liuguritega monitorid, mille abil saab mängija valida numbrite arvu piletil (np), numbrite arvu loosimisel (nl) ning maksimaalse võimaliku numbri piletil ja loosimisel (max). Samuti võiks olla muutuja monitor, mis näitab kokkulangevate numbrite arvu (tabas). Vastava tegevuse käivitamiseks võib teha käsunupud või kasutada selleks mingeid muid spraite.

Analüüs

Rakendus peab võimaldama luua kaks komplekti juhuslikke arve etteantavas vahemikus. Arvud salvestatakse vastavates loendites: üks sisaldab pileti numbreid, teine loosimise numbreid. Loosimise numbreid peab olema rohkem kui pileti numbreid. Kõik pileti numbrid peavad olema erinevad. Samuti ei tohi olla ühesuguseid numbreid loosimise loendis.
Selleks, et kasutajal oleks lihtsam võrrelda ja kontrollida pileti ja loosimise numbreid, peab programm kuvama need sorteerituna kasvavas järjestuses.
Programm peab leidma kokkulangevate numbrite arvu ja kuvama need numbrid eraldi loendis (kui on). Võib kehtestada ka mingid reeglid võidusumma määramiseks.
Seega peab rakenduse loomisel realiseerima järgmised ülesanded:

  • etteantud hulga üksteisest erinevate kindlas vahemikus olevate juhuarvude genereerimine ja salvestamine loendis,
  • loendite elementide järjestamine (sorteerimine),
  • kahes loendis olevate kokkulangevate väärtuste kindlakstegemine ja eraldamine omaette loendisse.

Numbrite genereerimine ja sorteerimine toimub pileti ja loosimise jaoks ühtemoodi, erinevus on ainult väärtuste hulgas. Hiljem näeme, et erinevate arvude loomise ja kokkulangevate numbrite kindlakstegemisega, kaasneb veel üks sageli programmides esinev tegevus – otsimine. Arvestades, et nimetatud tegevused esinevad algoritmides ja programmides tihti (eriti sorteerimine ja otsimine), on otstarbekas nende tegevuste täitmiseks luua suhteliselt universaalsed protseduurid. Kahjuks puuduvad Scratchi praeguses versioonis vahendid parameetrite ja argumentide kasutamiseks andmevahetusel skriptide vahel. Seepärast pole võimalik luua täiesti universaalseid protseduure (skripte), mida saab näiteks kopeerimise või importimise teel viia ühest programmist teise ilma spetsiaalsete meetmete rakendamiseta protseduuride sidumiseks. Kuid kasutades võimalust spraitide ekspordiks ja importimiseks (koos skriptidega), saab tekitada siiski võimaluse üldise iseloomuga skriptide lülitamiseks erinevatesse projektidesse.
Et praegu saaks kasutada erinevate arvude loomisel ja sorteerimisel pileti ja loosimise numbrite jaoks samu skripte (protseduure), võib võtta kasutusele abiloendi, milles tehakse nimetatud tegevused, ja tulemused, nö lõplikul kujul, kopeerida abiloendist pileti ja loosimise loenditesse.
Alternatiivse variandina võiks pileti ja loosimise numbrite loomiseks ja sorteerimiseks teha kaks sõltumatut skriptide gruppi: üks pileti jaoks, teine loosimise jaoks. Skriptid erinevate arvude genereerimiseks ja sorteerimiseks peab sellisel juhul dubleerima ja seadistama vastavalt kasutatavatele andmetele (loenditele).

Disain ja realisatsioon

Andmed

Põhimuutujad

  • max – maksimaalne number piletil ja loosimisel, minimaalne väärtus on alati 1,
  • np– numbrite arv piletil,
  • nl – numbrite arv loosimisel,
  • tabas – kokkulangevate numbrite arv.

Lisaks neile on kasutusel mitmeid täiendavaid, peamiselt lokaalseid, muutujaid erinevates skriptides.

Loendid

  • Pilet (np) – pileti numbrite loend (massiiv),
  • Loos (nl) – loosi numbrite loend,
  • Pihtas (tabas) – kokkulangevate numbrite loend (võib olla ka tühi),
  • V(*) – abiloend pileti ja loosi numbrite loomisel ja sorteerimisel (vt allpool).

Programmi struktuur ja skriptid

On ette nähtud kolm suhteliselt sõltumatut skriptide gruppi: Tee pilet, Loosi ja Kontrolli. Iga grupp koosneb peaskriptist ja alamskriptidest. Täitmine algab pea-skriptist, mis teadete abil paneb tööle alamskriptid.

sk

Kuna pileti ja loosi numbrite loomine ja sorteerimine toimub analoogselt, on otstarbekas salvestada tegemise ajal pileti ja loosimise numbrid kordamööda abiloendisse ja kopeerida tulemused sealt loenditesse Pilet ja Loos.

Pileti ja loosimise numbrite loomine

Pileti ja loosimise numbrite loomine ja sorteerimine toimub täiesti sarnaselt. Erinevus on ainult elementide arvus np või nl ning loendis, kuhu salvestatakse tulemused. Mõlemal juhul kasutatakse abiloendit V, kust loodud elemendid kopeeritakse loendisse Pilet või Loos. Siin on näidatud ainult pileti numbrite töötlemine.

Pileti numbrite loomine ja sorteerimine. Andmed

np – numbrite arv piletil
Pilet – loend pileti numbritega (np väärtust)
V(np) – abiloend, kus toimub pileti numbrite loomine ja sorteerimine (np väärtust). Andmed kopeeritakse siit loendisse Pilet. Loendit V kasutatakse ka loosimise numbrite loomisel ja sorteerimisel.

Pileti numbrite loomine

eemalda Pileti elemendid
n = np
Tee_arvud
Sordi
k = 1
kordus n korda
 lisa Piletile V(k)
 k = k + 1
lõpp kordus

Loto_tee_pilet.gif

Erinevate arvude loomine – skriptid Tee arvud ja Otsi

Skript Tee arvud loob üksteisest erinevad juhuarvud ja salvestab need loendis V.

Tee arvud. Andmed

Loend V(*) - kasutatakse numbrite loomiseks pileti ja loosimise jaoks
Muutujad
n - elementide arv loendis, võrdub np või nl,
x – jooksev juhuarv,
nr – x-ga võrdse väärtuse järjenumber loendis V või 0, kui sellist väärtust ei ole.

Tee arvud. Algoritm
eemalda V elemendid
kordus n korda
 nr = 1
 kordus kuni nr = 0
    x = juhuarv(1...max)
    teavita Otsi
 lõpp kordus
 lisa V-le x
lõpp kordus

Loto_Tee_arvud.gif

 

Otsi. Andmed
V(*) – loend, kus toimub otsimine
k– elemendi number loendis
nr– otsitava (x) järjenumber loendis või 0, kui vastavat väärtust loendis ei ole
k – elemendi järjenumber

Otsi. Algoritm
k = 1
kordus V.pikkus korda
 kui x = V(k) siis
  nr = k
  tagasi
 lõpp kui
 k = k + 1
 lõpp kordus
 nr = 0

Loto_otsi.gif

Kõigepealt eemaldatakse loendist V kõik elemendid ning ükshaaval luuakse ja lisatakse loendisse uued elemendid. Iga uue elemendi korral võetakse kõigepealt muutuja nr väärtuseks 1 (nr<>0), luuakse juhuarv ja omistatakse see muutujale x. Skript Otsi kontrollib, kas x-ga võrdne väärtus on loendis V juba olemas või mitte. Seda näitab muutuja nrväärtus peale skripti töö lõppu. Loendi elemente võrreldakse järjest x-ga. Kui tingimus x=V(k) osutub tõeseks, omistatakse muutujale nr väärtus k ja skripti töö katkestatakse. Kui x-ga võrdset väärtust ei ole, jõutakse korduse lõpuni ja muutujale nr omistaks väärtus null. Esimesel juhul (nr<>0) genereeritakse uus juhuarv ja kontrollitakse uuesti. Seda tehakse seni, kuni muutuja nr väärtus saab nulliks (sellist väärtust ei ole). Seejärel lisatakse x loendi lõppu ja sama toimub järgmise elemendiga. Paneme tähele, et esimese elemendi korral kordust ei toimu, sest loend on veel tühi (pikkus on null) ning muutujale nr omistatakse kohe väärtus 0.

Paneme tähele, et esimese elemendi korral kordust ei toimu, sest loend on veel tühi (pikkus on null) ning muutujale nr omistatakse kohe väärtus 0.


Kui x-ga võrdne väärtus on loendis olemas, näitab muutuja nr väärtus skripti Otsi töö lõppemisel selle järjenumbrit loendis V. Antud juhul ei ole oluline järjenumber vaid ainult see, kas nr väärtus on 0 (võrdset väärtust ei ole) või mitte (väärtus on). Kuid otsitava järjenumbrit loendis saab kasutada otsimistel paralleelsetes loendites või ka tabeli veergudes. Näiteks tõlkimisel, leides eestikeelse sõna järje­numbri loendis eesti (näiteks hiir nr 3), saab võtta sama numbriga sõna loendist inglise (mouse). Taolist lihtsat põhimõtet kasutatakse otsimiseks loendites ja tabelites sageli.

Keel_Mas.bmp

Sorteerimine

Sorteerimine seisneb väärtuse järjestamises kasvavalt või kahanevalt. Enamasti sorteeritakse kasvavas järjestuses, kuid põhimõttelist vahet siin ei ole. Reeglina toimub sorteerimine samas loendis (massiivis). Sorteerimine leiab väga sageli kasutamist andmetöötluses. Selleks on loodud palju erinevaid meetodeid ja algoritme, mille täitmise ajas võivad olla väga suured erinevused. Siin kasutatakse ühte kõige lihtsamat algoritmi nn jadasorteerimist, mis on suurte loendite korral väga aeglane. Praegu ei ole andmehulgad eriti suured.

Jadasortimine. Andmed

V – loend, mille elemente sorteeritakse (n väärtust).
n – elementide arv loendis
i, j – indeksid
abi – abimuutuja, kasutatakse vahetamisel
Iga elementi, alates esime­sest kuni eelviimaseni, võrrel­dakse kõikide järgneva­tega. Kui mõni neist on jooksvast elemendist väiksem, vahe­tatakse selle väärtus jooksva ele­mendiga.

Jadasortimine. Algoritm

i = 1
kordus n-1 korda
    j = i + 1
    kordus n - i korda
       kui V(j) < V(i) siis
          abi = V(i)
          V(i) = V(j)
          V(j) = abi
       lõpp kui
       j = j + 1
    lõpp kordus
    i = i + 1
lõpp kordus

Loto_sort_jada.gif

Algoritmi täitmisel toimub ca n2 võrdlust, vahetuste arv sõltub andmete sorteerituse astmest. Taoliste algoritmide kohta öeldakse, et nende keerukus on n2. Elementide arvu kasvamisel n korda, suureneb aeg n2 korda. Näiteks, kui elementide arv suureneb 10 korda, suureneb täitmise aeg 100 korda!

Vaadake täitmise demot

 

Kokkulangevate numbrite kontrollimine

Võrreldakse väärtusi kahes loendis Pilet ja Loos. Leitakse kokkulangevate väärtuste arv ja salvestatakse see muutujas tabas. Kokkulangevad numbrid (kui on) salvestatakse loendis Pihtas.

Kontroll ja Otsi_1. Andmed

Pilet– pileti numbrid (np)
Loos– loosi numbrid (nl)
Pihtas – kokkulangevad numbrid (*)
np – numbreid piletil
nl – numbreid loosimisel
tabas – kokkulangevuste arv
x – abimuutuja, jooksev väärtus loendist Pilet.

Kontroll. Algoritm

eemalda Pihtas elemendid
tabas = 0
i = 1
kordus Pilet.pikkus korda
    x = Pilet(i)
    teavita Otsi_1
    kui nr <> 0 siis
       tabas = tabas + 1
       lisa Pihtas Pilet(i)
    lõpp kui
    i = i + 1
lõpp kordus

Loto_Kontroll.gif

Skript Otsi_1 on analoogne skriptiga Otsi, ainult otsimine toimub siin loendis Loos. Iga numbrit loendis Pilet võrreldakse elementi­dega loendis Loos ja kui on tegemist võrdsete väärtustega, omistatakse muutu­jale nr järjenumber k.
Kui nr <> 0, suurendatakse skriptis Kontroll muutuja tabas väärtust ühe võrra ja x (vastav element loendist Pilet) lisatakse loendisse Pihtas.

Loto_Otsi_1.gif

 

Mõned täiendavad sorteerimisalgoritmid

Mullsortimine

Mullsortimine on üks vanemaid sorteerimise algoritme. Massiiv vaadatakse korduvalt läbi. Iga kord võrreldakse naabreid ning kui V(i) > V(i+1), vahetakse need. Väiksemad väärtused „tõusevad“ ülespoole, suuremad laskuvad. Läbivaatamine kestab seni, kuni ei toimu ühtegi vahetust.
Keerukus n2. Meetod on 2-3 korda aeglasem kui valiksortimine. Üldjuhul veidi aeglasem kui jadasortimine. Kiire, kui väärtused on peaaegu järjestatud


protseduur Sort_Mull(V, n)
 tun = 1
 m = n - 1
 kordus kuni tun = 0
    tun = 0
    kordus i = 1... m
       kui V(i) > V(i + 1) siis
       abi = V(i)
       V(i) = V(i + 1)
       V(i + 1) = abi
       tun = 1
    lõpp kui
    m = m - 1
 lõpp kordus

# Python
def sort_mull(V):
 n = len(V)
 m = n - 1
 tun = 1
 while (tun != 0):
      tun = 0
      for i in range (m):
           j = i + 1
           if (V[i] > V[j]):
                V[i], V[j] = V[j], V[i]
                tun = 1
                m = m - 1

Valiksortimine minimaalse elemendi valimisega

Muudetakse indeksi i väärtust vahemikus 1 kuni n - 1, iga i korral leitakse minimaalne element vektori osas i kuni n ja vahetatakse see elemendiga i.
Keerukus n2, 2-3 korda kiirem kui mullsortimine.


protseduur Sort_Min(V, n)
 kordus i = 1 kuni n - 1
    min = V(i)
    k = i
    kordus j = i + 1 kuni n
       kui V(j) < min siis
          min = V(j)
          k = j
       lõpp kui
    lõpp kordus
    V(k) = V(i)
    V(i) = min
 lõpp kordus

void sordi_min(int V[], int n) // C
{
 int min, k;
 for (int i = 1; i <= n-1; i++)
 {
 min = V[i]; k = i;
 for (int j = i+1; j <= n; j++)
 if (V[j] < min)
 {min = V[j]
 k = j; }
 V[k]= V[i];
 V[i] = min;
 }
}


 

Shelli meetod

Sarnane mullsortimisele, kuid kasutatakse muutuvat sammu: alguses suur, edaspidi järjest väheneb. Keerukus sõltub oluliselt sammu valikust. Üks paremaid sammu muutmise reegleid - ni = ni-1 / 1,3. Keerukus ca n*log2n. Oluliselt kiirem eelmistest, eriti kui n on suur:
n = 1000 - ca 10 korda, n = 100 000 - ca 500 korda, n = 1 000 000 - ca 5000 korda!


prots Sort_Shell(V, n)
 h = n
 tun = 1
 kordus kuni h=1 & tun=0
    h = täisosa(h/1,3)
    kui h < 1 siis h = 1
    tun = 0
    kordus i = 1... n - h
       kui V(i) > V(i + h) siis
          abi = V(i)
          V(i) = V(i + h)
          V(i + h) = abi
          tun = 1
       lõpp kui
    lõpp kordus
 lõpp kordus

Sub Sort_Shell(V, n) ’ VBA
 Dim h, i, j, tun, abi
 h = n: tun = 1
 Do Until h = 1 And tun = 0
    h = Int(h / 1.3)
    If h < 1 Then h = 1
    tun = 0
    For i = 1 To n - h
       j = i + h
       If V(i) > V(j) Then
          tun = 1: abi = V(i)
          V(i) = V(j): V(j) = abi
       End If
    Next i
 Loop
End Sub