Näiteid võimalikest projektidest

Siit lehelt leiad näiteid võimalikest tarkvaraprojektidest.

eKool

Realiseerige eKool, kasutades selleks OOP printsiipe. Kirjutage enda projektile ka testid, mis kontrollivad erinevaid olukordi.

Projektis tuleks realiseerida vähemalt järgnev:
  • koolis toimuvad ained,

  • õpilasel on nimi, klass ja keskmine hinne,

  • õpilane saab kooli registreeruda,

  • õpilane saab korraga olla vaid ühes koolis,

  • aine on seotud kooliga, sellel on nimi, õpetaja(d) ja õpetatav(ad) klass(id),

  • ühte ainet võib sooritada mitu klassi (näiteks matemaatika 1. - 12. klass),

  • ühte ainet võib õpetada mitu õpetajat,

  • üks õpetaja võib õpetada mitut ainet,

  • üks õpetaja võib õpetada mitmes koolis,

  • õpilane saab ainele registreeruda (seda ainult juhul kui ta on antud kooli registreerunud),

  • õpilane saab aine sooritada või läbi kukkuda,

  • kui õpilane sooritab aine, siis ta saab selle eest hinde,

  • hinded on 1, 2, 3, 4, 5,

  • kui õpilane saab aine eest hindeks 1 või 2, on ta aine läbi kukkunud,

  • õpilasel on ülevaade sooritatud (ja mitte sooritatud) ainetest,

  • koolil on ülevaade õpilasest, ainetest ja õpetajatest,

  • koolil on võimalik moodustada õpilaste pingerida keskmise hinde alusel.

Projektis tuleks kontrollida mõistlikkuse piires erinevaid piiranguid, näiteks:
  • õpilase klass peaks olema vahemikus 1-12,

  • õpilase keskmine hinne peaks olema vahemikus 1-5,

  • sisestatud hinne ei saa olla väljaspool määratud vahemikku,

  • õpilane ei ole korraga rohkem kui ühes koolis,

  • õpilast ei saa registreerida kursusele, kui seda tema klassile ei õpetata jne.

Programmi testimiseks võiks proovida näiteks sellist sündmuste ahelat:

luuakse uus kool
luuakse hulk õpetajaid
luuakse hulk õpilasi
õpilased lisatakse kooli
luuakse teine kool
kontrollitakse, et üks õpilane ei saa mitmes koolis olla
kooli luuakse erinevad ained
proovitakse luua vigaseid aineid
õpilane registreeritakse ainele
õpilane saab aine sooritatud
õpilane kukub aine läbi
õpilane näeb enda hinnete ajalugu
koolist saab vaadata õpilaste nimekirja
koolist saab vaadata õpetajate nimekirja
koolist saab vaadata ainete nimekirja
õpetaja näeb enda õpetatavaid aineid
kool väljastab õpilaste pingerea nende keskmise hinde põhjal

Raamatukogu

Realiseerige raamatukogu infosüsteem, kasutades selleks OOP printsiipe. Kirjutage enda projektile ka testid, mis kontrollivad erinevaid olukordi.

Tuleks realiseerida vähemalt järgnev:
  • raamatukogus on laenutatavad objektid,

  • realiseerida tuleks vähemalt kolme tüüpi objektid (näiteks raamat, ajakiri, ajaleht, DVD, tarkvara),

  • objektidel on populaarsus 0-10,

  • iga kord kui objekti laenutatakse, suureneb selle populaarsus,

  • raamatutel on laenutuse tähtaeg ning trahv ületatud päevade eest,

  • kui raamat tagastatakse peale tähtaega, siis arvutatakse välja trahvisumma (0.06€ iga ületatud päeva eest),

  • inimene saab registreeruda raamatukogu liikmeks,

  • üks inimene võib mitme raamatukogu liige olla,

  • inimene saab laenutada objekte,

  • inimesel on ülevaade enda laenutatud objektidest, raamatute laenutustähtaegadest ning trahvidest,

  • raamatukogul on ülevaade kõikidest laenutustest,

  • raamatukogul on ülevaade kõikidest trahvidest,

  • laenutada saab vaid neid objekte, mis on raamatukogus olemas,

  • füüsilised objektid (nätieks raamat, DVD) esinevad raamatukogus kindla kogusega (näiteks 3 Harry Potteri raamatut),

  • raamatukogu liige võib sama objekti laenutada ka mitu tükki (näiteks laenutab kõik 3 Harry Potteri eksemplari),

  • kui objekt ei ole saadaval (kõik on välja laenutatud), siis seda laenutada ei saa,

  • süsteem teeb vahet, kas objekti üldse ei ole või see on välja laenutatud,

  • tarkvara puhul laenutamise koguse piirangut ei ole,

  • raamatukogu liige ei saa tarkvara mitu korda laenutada,

  • raamatukogu liige saab objekte tagastada, tarkvara ei pea tagastama,

  • raamatukogu saab kuvada 10 kõige populaarsemat (kõrgeima popuaarsusega) objekti.

Projektis tuleks kontrollida mõistlikkuse piires erinevaid piiranguid, näiteks:
  • inimene ei saa registreeruda sellise raamatukogu liikmeks, mida ei eksisteeri,

  • inimene ei saa raamatukogust laenutada objekte, kui ta ei ole selle raamatukogu liikmeks registreeritud,

  • inimene ei saa tarkvara samaaegselt mitu korda laenutada,

  • inimene ei saa laenutada objekte, mida ei ole antud raamatukogus olemas või on välja laenutatud,

  • inimene ei saa tagastada objekte, mida ta ei ole laenutanud.

Programmi testimiseks võiks proovida näiteks sellist sündmuste ahelat:

luuakse uus raamatukogu
luuakse hulk inimesi
registreeritakse inimesed raamatukogu lugejaks
lisatakse objektid raamatukokku
inimene proovib laenutada raamatut, mida ei ole raamatukogus olemas
inimene proovib laenutada raamatut, mis on olemas
inimene proovib laenutada raamatut, mis on välja laenutatud
inimene proovib tagastada raamatut
inimene proovib laenutada sama raamatut mitu korda
inimene proovib tarkvara laenutada
inimene proovib sama tarkvara laenutada mitu korda
inimene proovib tarkvara tagastada
kuvatakse raamatukogu kõige populaarsemad objektid
luuakse veel üks raamatukogu
proovitakse üht inimest mitme raamatukogu lugejaks registreerida

Pokemon

Kirjutage programm, mis teeb API päringu pokeapi.co pihta, korraldab pokemonide vahelisi võitlusi ja kirjutab võitluste tulemused faili.

Link, kust kõik pokemonid kätte saab: https://pokeapi.co/api/v2/pokemon?offset=0&limit=100000

Selleks, et vähendada serveri koormust, tuleks veebipäringud puhverdada. See tähendab seda, et päritud veebilehe tulemus tuleks faili kirjutada. Kui selline fail on juba olemas, siis loetakse andmed (JSON) failist. Kui sellist faili pole, loetakse andmed veebist ja kirjutatakse faili.

Näide ühest Pokemonist:

{"name": "bulbasaur", "speed": 45, "attack": 49, "defense": 49, "special-attack": 65, "special-defense": 65, "hp": 45, "types": ["poison", "grass"], "abilities": ["chlorophyll", "overgrow"], "forms": ["bulbasaur"], "moves": ["razor-wind", "swords-dance", "cut", "bind", "vine-whip", "headbutt", "tackle", "body-slam", "take-down", "double-edge", "growl", "strength", "mega-drain", "leech-seed", "growth", "razor-leaf", "solar-beam", "poison-powder", "sleep-powder", "petal-dance", "string-shot", "toxic", "rage", "mimic", "double-team", "defense-curl", "light-screen", "reflect", "bide", "sludge", "skull-bash", "amnesia", "flash", "rest", "substitute", "snore", "curse", "protect", "sludge-bomb", "mud-slap", "giga-drain", "endure", "charm", "swagger", "fury-cutter", "attract", "sleep-talk", "return", "frustration", "safeguard", "sweet-scent", "synthesis", "hidden-power", "sunny-day", "rock-smash", "facade", "nature-power", "ingrain", "knock-off", "secret-power", "grass-whistle", "bullet-seed", "magical-leaf", "natural-gift", "worry-seed", "seed-bomb", "energy-ball", "leaf-storm", "power-whip", "captivate", "grass-knot", "venoshock", "round", "echoed-voice", "grass-pledge", "work-up", "grassy-terrain", "confide"], "height": 7, "weight": 69, "base_experience": 64}

Ründamise kordajad (fighting multipliers)

Tabelis on ründamise kordajad. Iga rida tähistab ründaja tüüpi, veerud tähistavad kaitsja tüüpi. Tabelis pole veeru pealkirjad visuaalselt veeruga kohakuti. Aga esimene pealkiri (normal) käib esimese kordaja veeru kohta, teine pealkiri (fighting) teise kordaja veeru kohta jne.

                normal              fighting        flying          poison          ground          rock            bug             ghost           steel           fire            water           grass           electric        psychic         ice             dragon          dark            fairy
normal              1.0             1.0             1.0             1.0             1.0             0.5             1.0             0.0             0.5             1.0             1.0             1.0             1.0             1.0             1.0             1.0             1.0             1.0
fighting    2.0             1.0             0.5             0.5             1.0             2.0             0.5             0.0             2.0             1.0             1.0             1.0             1.0             0.5             2.0             1.0             2.0             0.5
flying              1.0             2.0             1.0             1.0             1.0             0.5             2.0             1.0             0.5             1.0             1.0             2.0             0.5             1.0             1.0             1.0             1.0             1.0
poison              1.0             1.0             1.0             0.5             0.5             0.5             1.0             0.5             0.0             1.0             1.0             2.0             1.0             1.0             1.0             1.0             1.0             2.0
ground              1.0             1.0             0.0             2.0             1.0             2.0             0.5             1.0             2.0             2.0             1.0             0.5             2.0             1.0             1.0             1.0             1.0             1.0
rock                1.0             0.5             2.0             1.0             0.5             1.0             2.0             1.0             0.5             2.0             1.0             1.0             1.0             1.0             2.0             1.0             1.0             1.0
bug         1.0             0.5             0.5             0.5             1.0             1.0             1.0             0.5             0.5             0.5             1.0             2.0             1.0             2.0             1.0             1.0             2.0             0.5
ghost               0.0             1.0             1.0             1.0             1.0             1.0             1.0             2.0             1.0             1.0             1.0             1.0             1.0             2.0             1.0             1.0             0.5             1.0
steel               1.0             1.0             1.0             1.0             1.0             2.0             1.0             1.0             0.5             0.5             0.5             1.0             0.5             1.0             2.0             1.0             1.0             2.0
fire                1.0             1.0             1.0             1.0             1.0             0.5             2.0             1.0             2.0             0.5             0.5             2.0             1.0             1.0             2.0             0.5             1.0             1.0
water               1.0             1.0             1.0             1.0             2.0             2.0             1.0             1.0             1.0             2.0             0.5             0.5             1.0             1.0             1.0             0.5             1.0             1.0
grass               1.0             1.0             0.5             0.5             2.0             2.0             0.5             1.0             0.5             0.5             2.0             0.5             1.0             1.0             1.0             0.5             1.0             1.0
electric    1.0             1.0             2.0             1.0             0.0             1.0             1.0             1.0             1.0             1.0             2.0             0.5             0.5             1.0             1.0             0.5             1.0             1.0
psychic             1.0             2.0             1.0             2.0             1.0             1.0             1.0             1.0             0.5             1.0             1.0             1.0             1.0             0.5             1.0             1.0             0.0             1.0
ice         1.0             1.0             2.0             1.0             2.0             1.0             1.0             1.0             0.5             0.5             0.5             2.0             1.0             1.0             0.5             2.0             1.0             1.0
dragon              1.0             1.0             1.0             1.0             1.0             1.0             1.0             1.0             0.5             1.0             1.0             1.0             1.0             1.0             1.0             2.0             1.0             0.0
dark                1.0             0.5             1.0             1.0             1.0             1.0             1.0             2.0             1.0             1.0             1.0             1.0             1.0             2.0             1.0             1.0             0.5             0.5
fairy               1.0             2.0             1.0             0.5             1.0             1.0             1.0             1.0             0.5             0.5             1.0             1.0             1.0             1.0             1.0             2.0             2.0             1.0

Ülaltoodud tabel tasuks programmis näiteks maatriksiks konverteerida.

Pokemonide võitlused

Kaks pokemoni saavad omavahel pidada duelli. See käib järgmiste reeglite järgi: pokemonid ründavad kordamööda - üks pokemon alustab oma käiguga siis, kui teine on oma käigu täielikult lõpetanud. Käigu võitja leidmine käib järgneva valemi järgi (eeldusel, et meil võitlevad pokemon1 ja pokemon2 ning pokemon1 käib esimesena):

totalAttack = pokemon1.getAttack(turnCounter) * pokemon1.getAttackMultiplier(pokemon2.getTypes()) - pokemon2.getDefense(turnCounter)

Esimene käik on number 1.

Käikude lugemine on oluline selleks, et iga kolmas rünnak on special attack (vt üleval näites "special-attack"), samuti iga teine kaitsmine on special defense (vt üleval näites "special-defense"). NB: igasugune defense väärtus (vahet pole siis, kas special või tavaline), peaks arvutusse jõudmisel olema jagatud kahega.

Kui kaitsval pokemonil on mitu tüüpi, siis tuleb vastavad kordajad korrutada. Kui ründajal on mitu tüüpi, siis tuleb valida selline tüüp, mis annab parima tulemuse.

Käigu lõpus tuleks totalAttack lahutada rünnatud pokemoni eludest. Pokemonid ei saa võitluse ajal elusid tagasi ning kui totalAttack peaks mingil põhjusel olema negatiivne, siis lihtsalt rünnatud pokemon viga ei saa.

Kui kahe pokemoni vaheline duell võtab rohkem kui 100 käiku, siis on tegemist viigiga ja seda peaks vastavalt kajastama. Kui aga ühe pokemoni elud otsa saavad, siis duell lõpeb ning võitja saab oma skoorile ühe punkti juurde. Seejärel taastatakse kõigi pokemonide elud.

Pokemonid saavad ka pidada maha suure võitluse, kus nad kõik omavahel võitlusesse lähevad. Sellisel juhul tulekski tekitada pokemonide pingerida ning see faili salvestada. Selle suure võitluse puhul võitleb iga pokemon iga teisega ainult ühe korra. Siin saab kasutada seda sama duelli funktsionaalsust, kuid enne tuleb välja selgitada, kumb pokemon lööb esimesena. Selleks on järgmine loogika: pokemon, kelle speed on kõrgen, käib esimesena. Kui mõlema pokemoni speed on sama, siis käib esimesena pokemon, kelle weight on väiksem. Kui pokemonid kaaluvad sama palju, siis käib madalama height'iga pokemon enne. Kui pokemonid on sama pikad, siis käib rohkemate ability'tega pokemon enne. Kui pokemonidel on sama hulk ability'sid, siis käib esimesena see, kellel on rohkem moves elemente. Kui moves elementide hulk on sama, siis käib kõrgema base_experience väärtusega pokemon enne. Kui ka see on sama, siis järelikult on tegemist sama pokemoniga ja võitlust ei toimu.

Kui kõik pokemonid on omavahel läbi võidelnud, siis kirjutage pokemonide edetabel faili, sama skooriga pokemonid on tähestikulises järjekorras.

All on toodud mõned tulemused erinevate sisenditega. Sisendi puhul esimene arv näitab offset väärtust, teine limit väärtust URL-is.

0, 4:

[venusaur 3, charmander 2, ivysaur 1, bulbasaur 0]

0, 10:

[charizard 7, venusaur 7, blastoise 6, charmeleon 5, ivysaur 5, bulbasaur 4, wartortle 4, charmander 3, squirtle 3, caterpie 0]

0, 100:

[slowbro 89, tentacruel 88, dodrio 87, kingler 86, nidoking 83, cloyster 82, nidoqueen 82, pidgeot 82, muk 80, blastoise 79, charizard 79, fearow 79, dewgong 77, hypno 77, venusaur 77, arcanine 75, golbat 75, magneton 75, victreebel 75, poliwrath 74, golduck 72, raichu 72, slowpoke 72, sandslash 71, gengar 70, golem 69, dugtrio 68, rapidash 67, arbok 66, ninetales 65, machamp 64, beedrill 63, vileplume 63, wigglytuff 63, farfetchd 58, graveler 58, venomoth 58, persian 57, haunter 56, raticate 56, weepinbell 56, poliwhirl 55, grimer 53, primeape 53, alakazam 52, doduo 52, ivysaur 52, krabby 52, pidgeotto 52, geodude 51, wartortle 51, machoke 50, ponyta 50, clefable 49, onix 49, charmeleon 48, gloom 48, parasect 47, nidorino 46, magnemite 45, nidorina 45, butterfree 44, sandshrew 43, bellsprout 40, growlithe 40, tentacool 40, drowzee 37, spearow 37, venonat 37, bulbasaur 34, zubat 34, psyduck 33, seel 33, oddish 31, gastly 30, paras 30, shellder 30, machop 29, charmander 28, pikachu 28, squirtle 28, mankey 27, ekans 26, poliwag 24, diglett 23, nidoran-m 23, clefairy 22, kadabra 22, nidoran-f 21, pidgey 21, voltorb 20, vulpix 18, jigglypuff 17, meowth 14, rattata 13, weedle 10, kakuna 7, caterpie 3, metapod 3, abra 0]

69, 100:

['mewtwo 93', 'gyarados 91', 'mew 89', 'kabutops 88', 'dragonite 86', 'snorlax 85', 'aerodactyl 82', 'lapras 80', 'zapdos 80', 'articuno 78', 'tauros 78', 'kangaskhan 77', 'starmie 77', 'kingler 76', 'magneton 76', 'tentacruel 76', 'slowbro 75', 'feraligatr 74', 'scyther 73', 'cloyster 70', 'exeggutor 69', 'moltres 69', 'omastar 69', 'dodrio 68', 'pinsir 68', 'electabuzz 67', 'muk 67', 'victreebel 67', 'crobat 66', 'dewgong 65', 'rhydon 64', 'golem 63', 'vaporeon 63', 'hypno 62', 'jolteon 62', 'seaking 62', 'dragonair 61', 'gengar 58', 'kabuto 57', 'meganium 56', 'flareon 55', 'hitmonlee 55', 'rapidash 54', 'slowpoke 54', 'weepinbell 54', 'hitmonchan 52', 'typhlosion 52', 'weezing 52', 'croconaw 51', 'graveler 51', 'rhyhorn 51', 'magmar 50', 'electrode 48', 'furret 47', 'seadra 47', 'ariados 45', 'noctowl 45', 'haunter 44', 'krabby 44', 'marowak 44', 'farfetchd 43', 'geodude 43', 'onix 43', 'bayleef 41', 'jynx 41', 'tangela 41', 'exeggcute 40', 'ponyta 39', 'mr-mime 37', 'omanyte 37', 'doduo 36', 'goldeen 36', 'grimer 35', 'totodile 35', 'magnemite 34', 'chikorita 31', 'cubone 30', 'dratini 30', 'quilava 30', 'lickitung 29', 'porygon 29', 'tentacool 29', 'shellder 26', 'ledian 25', 'seel 25', 'koffing 24', 'gastly 22', 'staryu 22', 'cyndaquil 19', 'drowzee 19', 'eevee 19', 'horsea 16', 'voltorb 13', 'spinarak 11', 'ditto 10', 'hoothoot 9', 'ledyba 9', 'chansey 5', 'sentret 2', 'magikarp 0']

666, 33:

[barbaracle 28, malamar 27, doublade 26, gogoat 26, tyrantrum 25, pangoro 24, aegislash-shield 23, slurpuff 23, pyroar 22, florges 21, aurorus 20, clawitzer 20, honedge 20, heliolisk 19, aromatisse 18, dragalge 18, furfrou 18, tyrunt 15, meowstic-male 14, litleo 13, skiddo 13, skrelp 13, spritzee 11, espurr 10, pancham 10, floette 9, inkay 9, amaura 8, swirlix 8, binacle 5, clauncher 5, helioptile 5, flabebe 2]

Investor

Teie sõber võitis juhuslikult lotoga 1000 eurot ja otsustas, et edaspidi ei hakka õnnemängule sedasi enam lootma. Nüüd olevat õige aeg natuke investeerida seda raha. Ta kuulnud, et börsil on võimalik valuutavahetustega õigel ajal tehinguid tehes raha juurde teenida ja ta otsustas, et temast saab nüüd börsihai. Paraku on probleem selles, et tal pole õrna aimugi, kuidas asjaga toime tulla. Tema algne mõte oli iga kord, kui kurss tõusule pöörab, valuutat osta, ja iga kord, kui kurss langusele pöörab, valuutat müüa. Hiilgav plaan, kas pole? Paraku võtab pank iga vahetustehingu pealt 1% endale teenustasudena ära. Küll aga ta avastas, et kui vahetada mõnel sobivamal hetkel, siis on tegelikult võimalik panga teenustasudest võitu saada.

Ta lisas teile kaks näidet oma mõtte illustreerimiseks. Ta läks Eesti Panga eurokursside ajaloo lehele: https://www.eestipank.ee/valuutakursside-ajalugu ja võttis EUR/USD vahetuskursi ette ja koostas teile tabelid.

Teie ülesanne on nüüd oma sõpra aidata. Te peate kirjutama Pythonis rakenduse, millele on võimalik ette anda .csv fail Eesti Panga eurokursside ajaloo lehelt mingi valuutaga. Teie programm peab sealt välja lugema, mis valuutaga on tegu, võtma kuupäevad ja kursid ning tekitama sõbra etteantud näite alusel sarnased graafikud Matplotlib abil. Ühtlasi peate välja mõtlema, milline võiks olla see parem algoritm, mis aitab sõbral ka natuke raha teenida.

Ülesande raames peate looma investor.py faili, mis tegeleb andmete lugemisega failist ning vahetusplaani koostamisega. Lisaks peate tegema ühe teise faili (ükskõik mis nimega), mis kasutab investor.py failis saadud tulemusi graafiku joonistamiseks. Graafikul peab olema:

  • Raha kogus algses valuutas.

  • Raha kogus teises valuutas (kurss võib olla ka näiteks 20, seega peab kasutama erinevaid telgi).

  • Tõusujoon, mis näitab kuidas algses valuutas teie raha väärtus tõuseb (või langeb).

Graafik peab arvestama kuupäevade alguse ja lõpuga (kõik välja näitama vastavalt andmetele). Mida üldisema lahenduse teete, seda parem.

def get_currency_rates_from_file(filename: str) -> tuple:
"""
Read and return the currency and exchange rate history from file.

See web page:
https://www.eestipank.ee/valuutakursside-ajalugu

Note that the return value is tuple, that consists of two things:
1) currency name given in the file.
2) exchange rate history for the given currency.
    Note that history is returned using dictionary where keys represent dates
    and values represent exchange rates for the dates.

:param filename: file name to read CSV data from
:return: Tuple that consists of currency name and dict with exchange rate history
"""
return ("USD", {
    "03.01.2017": 1.0099,
    "02.01.2017": 1.0101,
    "01.01.2017": 1.0234
})


def exchange_money(exchange_rates: dict) -> list:
    """
    Find best dates to exchange money for maximum profit.

    You are given a dictionary where keys represent dates and values represent exchange
    rates for the dates. The amount you initially have is 1000 and you always use the
    maximum amount during the exchange.
    Be aware that there is 1% of service fee for every exchange. You only need to return
    the dates where you take action. That means the first action is always to buy the
    second currency and the second action is to sell it back. Repeat the sequence as
    many times as you need for maximum profit. You should always end up having the
    initial currency. That means there should always be an even number of actions. You can
    also decide that the best decision is to not make any transactions at all, if
    for example the rate is always dropping. In that case just return an empty list.

    :param exchange_rates: dictionary of dates and exchange rates
    :return: list of dates
    """
    return [
        "01.01.2017",
        "03.01.2017"
    ]

Näidisgraafikud

Graafiku joonistamisel tuleks ise katsetada erinevaid lahendusi, allpool on toodud mõned näited. Alati võib ka teha mitu erinevat graafikut.

Soovitatav (ei ole kohustuslik) on kasutada matplotlib graafikute joonistamiseks.

../_images/graph1.png ../_images/graph2.png ../_images/graph3.png