JavaFX valuutakalkulaator
Valuutakalkulaator on JavaFX kasutades kirjutatud graafiline programm, mis oskab teisendada EUR valuutat teisteks valuutadeks.
- programm loeb teiste valuutade nimed (nt USD) ja vahetuskursid tekstifailist
exchange-rates.txt
- kasutajaliideses on kaks tekstivälja - üks EUR summa jaoks ja teine võõrvaluuta summa jaoks. EUR tekstivälja summa sisestamisel peab automaatselt kohe teise tekstivälja konverteeritud summa ilmuma (property listener).
- võõrvaluuta summa tekstivälja ei tohi kasutaja saada muuta
- kasutajaliideses on drop-down menüü, kust saab võõrvaluuta valida. valiku muutmisel uuendatakse ka summa.
- kasutajaliideses on nupp, mis mõlemad tekstiväljad tühjendab
- kasutajaliides sisaldab programmi "logo". logo on mingi
javafx.scene.canvas.Canvas
abil koostatud pilt, mis sisaldab vähemalt kolme erinevat kujundit ja kahte eri värvi. - kasutajaliidese elemendid on paigutatud kasutades sobilikke layout klasse (BorderPane, HBox, VBox, GridPane jms; ära kasuta setLayoutXY ega hardcoded koordinaate)
Vihje: võta aluseks javafx praksist eelseadistatud tühi projekt
Telekanalid
Põhja-Korea juhid tahavad oma 60-tollistest 3D telekatest uudiseid vaadata. Riigis levib ametlikult ainult maailma parim kanal "Põhja-Korea rahvuslikud uudised". Lisaks levitavad mässulised piraat-telejaama "Põhja-Korea maailmauudised", mis edastab kohalikku kanalit ja lisaks ka Fox News uudiseid. Riigipea saab Fox Newsi ka otse oma satelliidi-vastuvõtjast vaadata.
- Loo interface BroadcastListener, kus on meetod
void listen(String)
. - Loo class Broadcaster, kus on meetodid
void subscribe(BroadcastListener)
javoid broadcast(String)
. Broadcaster jätab meelde kõik BroadcastListenerid, mis tallesubscribe
meetodiga ette antakse.broadcast
meetodi kutsumisel tuleb kõigile listeneridele ette antud string edasi anda (listen meetodit kutsuda). - Loo Broadcaster alamklass TVStation. Loo konstruktor, mis võtab parameetriks listi uudistest. Lisa meetod
void sendNews()
, mis broadcastib (ülemklassi meetodi abil) uudiste listist suvalise uudise. - Loo Broadcaster alamklass PirateStation, mis lisaks implementib BroadcastListener. PirateStation võtab teiste jaamade saateid vastu (listen) ja broadcastib need kohe kõigile oma kuulajatele edasi.
- Loo klass TV, mis implementib BroadcastListener. TV konstruktoriga peab määrama omaniku nime. Kõik kohale jõudvad uudised prindi koos TV omaniku nimega System.out-i.
Loo testklass, mis funktsionaalsust testib.
- Loo TVStation objektid "Põhja-Korea rahvuslikud uudised" ja "Fox News" jaoks. Mõlemal on oma erinev uudiste list. Loo PirateStation, mis võtab vastu ja edastab mõlema eelneva uudiseid.
- Loo TV Kim Jong-un jaoks, mis kuulab Fox News ja rahvuslikke uudiseid (otse, mitte läbi piraatkanali).
- Loo TV Kim Yong-nam jaoks, mis kuulab ainult rahvuslikke uudiseid.
- Loo TV Pak Pong-ju jaoks, mis kuulab piraatkanalit (selle kaudu mõlemaid teisi kanaleid).
- Käivita mõlema uudistekanali
sendNews()
ja veendu, et õiged isikud õiged uudiseid kuulevad.
Subscribe/broadcast, addEventListener/fireEvent, addObserver/notify - need kõik on erinevad kujud Observer patternist. See on väga levinud ja kasulik tehnika, mis aitab koodi modulaarsemaks ja taaskasutatavamaks muuta. Mõned näited, kus seda veel kasutatakse:
- Kasutaja klõpsab nupu peale - nupp teeb fireEvent ja kõik EventListenerid saavad reageerida.
- Programm alustab taustaprotsessina faili allalaadimist. Selle lõppedes saavad kõik DownloadObserverid teate, et fail on kasutamiseks valmis.
- Koodikomponent ootab võrgust tulevaid teateid. Vastuvõtja teavitab teda sobiva teate saabumisest.
Paralleelarvutused
Koosta paralleelarvutusprogramm, mis loeb ja töötleb paralleelselt mitut sisendfaili. Programm saab käsurea parameetritega sisendfailide nimed (relative pathid). Sisendfaile võib olla väga palju (üle 100 000).
Sisendfailid on utf-8 tekstifailid, millest igaüks sisaldab väga väga palju täisarve. Failides võivad kõik arvud olla tühikutega eraldatuna ühel real, aga võivad olla ka mitme rea peale jaotatud. Igas failis on vähemalt üks arv. Failid ja ka üksikud read võivad olla nii suured, et need ei mahu korraga mälusse ära.
Arvud võivad olla suuremad, kui mahub long tüüpi muutujasse. Sellega hakkama saamiseks peab programm kasutama arvude hoidmiseks BigInteger klassi.
Programm peab failide töötlemiseks looma protsessorituumadega võrdse arvu threade (workerid). Loo üks ühine BlockingQueue, millest kõik workerid töötlemist vajavate failide nimesi võtavad. Loo teine ühine BlockingQueue, kuhu workerid iga faili kohta järgneva komplekti lisavad: töödeldud faili nimi, selle faili suurim üksik arv ja kõigi arvude summa.
Programmi lõppedes peab main threadist ekraanile väljastama:
- Kõikide leitud arvude kogusumma
- Kõige suurema leitud üksiku arvu väärtuse ja vastava faili nime
- Kõige väiksema arvude summaga faili nime
Programm peab töötama korrektselt ilma ühtegi synchronized plokki vajamata.
NB! Tulemuste komplekti queue kaudu saatmisel ei tohi andmete õiged tüübid kaduma minna. Loo vajadusel tulemuste hoidmiseks eraldi klass.
Vihje: Vaata Practice12 PahupidiPööraja koodi.
Vihje: Faili lugemiseks üks mugavamaid variante on Scanner.next().
Soovi korral võib threadid+BlockingQueue asemel kasutada ExecutorService+Future.
Echo server v2
Täienda echo serverit.
- Server peab suutma paralleelselt teenindada mitut klienti (üks thread per socket).
- Server peab vastu võtma kahte tüüpi sõnumeid
- echo-request, mis sisaldab teksti. vastuseks tuleb saata sama tekst.
- file-request, mis sisaldab failinime. kui faili nimi on absolute path või faili ei leita, siis saata vastuseks error. muidu tuleb saata vastuseks faili sisu. faile peaks otsima working directoryst (sealt, kus server käivitati).
- Server võtab ühenduse vastu ja loeb requestide arvu (int). Seejärel loeb server kliendilt esimese requesti ja saadab sellele response. Seejärel loeb järgmise requesti ja saadab sellele response jne.
- Client käsurea parameetritega saab määrata, mis requeste ja mis järjekorras saadetakse. Käsurea parameetrid käivad paari kaupa: kõigepealt "file" või "echo" ja seejärel faili nimi või sõnumi sisu. Käsurida võib sisaldada mitu paari, nt
file shire.txt echo rivendell file mordor.jpg
. - Client saadab kõigepealt serverile requestide koguarvu. Seejärel saadab esimese requesti ja töötleb response. Seejärel saadab järgmise requesti ja töötleb response jne. Vastuvõetud failid salvestada kausta "received".
- Suhtluses tuleb kasutada mõistlikku süntaksi. Iga request peaks algama arvuga, mis näitab requesti tüüpi. Iga response peaks algama arvuga, mis näitab staatust (ok, error). Kõik variable length andmed peaks algama length prefixiga.
Vihje: kasulikud meetodid: Path.isAbsolute, Files.isRegularFile, Files.readAllBytes, Files.write
Vihje: socketi peaks sulgema see thread, mis viimasena socketiga midagi toimetab. kasuta try-with-resources:
AutoCloseable someResource; // field void method() { try (someResource) { someResource.use(); } // someResource pannakse kinni }
Echo server
- Loe https://github.com/mbakhoff/sockets-template
- Loo class Server, mis pordil 1337 ühendusi vastu võtab. Server võtab ühenduse vastu ja loeb oodatavate sõnumite arvu (int). Seejärel loeb server ühendusest ühe sõnumi (String) ja saadab sama sõnumi kohe tagasi. Seejärel loeb järgmise sõnumi ja saadab selle tagasi. Seda tuleb korrata sõnumite arv korda. Kui kõik sõnumid on loetud ja tagasi saadetud, tuleb ühendus sulgeda ja hakata teenindama järgmist ühendust.
- Loo class Client, mis saab käsurea parameetritega mitu sõnumit (stringi). Client ühendub samas masinas jooksva serveriga ja saadab sõnumite arvu (int). Seejärel saadab client esimese sõnumi, ootab serverilt vastuse (echo) ja prindib selle välja. Seejärel saadab järgmise sõnumi ja prindib vastuse välja. Sama korrata iga sõnumiga.
- Andmete saatmiseks ja lugemiseks kasutada DataOutputStream ja DataInputStream.
NB! Server ja client on kaks eri programmi, millel mõlemal on oma main meetod. Kogu kood võiks olla ühes projektis. Mõlema programmi korraga käivitamiseks on kõige lihtsam teha paremklõpsa mõlema main
peale ja Debug.
Dungeons & Dudes
Selles ülesandes ehitame väga lihtsustatud lahingusimulaatori. Loome erinevad tegelased, kes suudavad omavahel duelle pidada. Duell kestab, kuni üks tegelastest langeb. Tegelased käivad kordamööda ja saavad enda käigu ajal vastast erinevate efektidega rünnata. Efektid kulutavad action pointe, mis taastuvad käigu lõpus. Efektid võivad olla ühekordse mõjuga või kesta mitu käiku, mõjudes vastase käikude alguses ja/või lõpus.
- Loo abstraktne klass Dude, kes on kõigi tegelaste aluseks. Tal on muuhulgas järgnevad omadused: accuracy, armor, health ja action points. Lisaks on tal meetod
void takeTurn(Dude attackTarget)
jaboolean isAlive()
. - Loo interface Effect, milles on järgnevad meetodid:
void onHit(Dude effectTarget);
, mille käivitab ründaja, kui vastane saab efektiga pihtavoid onTurnStart(Dude effectTarget);
, mille käivitab efektiga pihta saanud vastane iga oma käigu algusesvoid onTurnEnd(Dude effectTarget);
, mille käivitab efektiga pihta saanud vastane iga oma käigu lõpusint requiredActionPoints();
boolean isExpired();
- Loo Dude alamklassid Fighter ja Wizard. Neil on erinevad accuracy, armor, health ja action points taastumise kiirus. Fighter ja Wizard kasutavad ründamiseks erinevaid efekte.
- Loo järgnevad Effect klassi implementatsioonid (võid ise täiendavaid välja mõelda):
WeaponAttack
- vähendab pihta minemise hetkel vastase healthKnockdown
- vähendab pihta minemise hetkel vastase actionPoints 0 pealeFirebolt
- vähendab vastase käigu lõpus vastase health. efekt lõppeb pärast health vähendamist.Spiderweb
- vähendab vastase iga käigu alguses tema action points. efekt lõpeb, kui vastast on kahe tema käigu jooksul mõjutatud.
Rünnakud võivad ebaõnnestuda (vastasest mööda minna). Iga rünnaku pihta/mööda minemise tuvastamiseks kasutatakse valemit "d20 + ründaja täpsus >= vastase kaitse", kus d20 on juhuslik arv [1..20].
Ühele tegelasele saab korraga rakenduda mitu sama tüüpi effekti. Iga dude peaks ise arvet pidama, mis efektid teda hetkel mõjutavad ja iga efekt peaks ise arvet pidama, kui kaua ta veel kestab. Näiteks wizard saab vastasele kaks käiku järjest spiderweb visata, mis juhul mõjutavad vastast vahepeal korraga kaks eraldiseisvat spiderwebi.
Efekti-spetsiifiline loogika peaks olema vastava efekti klassis. Dude klassis olev ründamise loogika (takeTurn
) peaks olema üldistatud ja kõigi tegelaste/efektide puhul täpselt ühesugune. Dude ei peaks teadma, mis alamklassid tal on ega mis konkreetseid efekte ründamiseks kasutatakse. Dude alamklassid teavad, mis efektidega nad rünnata oskavad, aga mitte seda, millega neid rünnata võidakse. Selle tulemusena on võimalik lisada uusi efekte ja Dude alamklasse, ilma et peaks teisi klasse muutma.
Kuidas Dude peaks valima rünnakuks sobiva efekti, kui ta ei tea konkreetsetest efektidest midagi? Hea mõte on lisada Dude klassi abstract method efekti valimiseks. Iga alamklass saab selle endale sobival viisil implementeerida.
Mõtle välja puudu olevad muutujad ja meetodid, nii et mäng toimiks. Tekita peameetod, mis tegelasi võitlema paneb ja tulemused välja kuulutab. Main meetod loob mängu alguses kaks tegelast. Pärast seda kutsutakse kordamööda dude objektidel takeTurn meetodit, kuni võitja on selgunud. Dude objektid peavad ise suutma välja mõelda, mida nad oma käigu ajal teevad. Võitluse ajal interaktiivselt sisendit ei küsita.
Nimede lühendamine
Failis nimed.txt on inimeste nimed, näiteks
Aadu Suur Mari Sale Blond Mari-Liis Maasikas Timothy Henry Charles Tamm
Eeldame, et iga nimi koosneb eesnimedest (neid võib olla mitu) ja perekonnanimest (viimane sõna). Eesnimi võib sisaldada ka sidekriipsu.
Kirjutada programm, mis sisaldab järgnevaid kahte meetodi:
readPersons
, mis võtab parameetriks failinime ja tagastab ArrayList<String> tüüpi objekti, mis elementidena sisaldab kõiki nimesid, mis sealt failist õnnestus lugeda. Kui antud faili pole olemas, siis tagastab null objekti.printPersons
, mis võtab parameetriks sellesama ArrayList<String> objekti ning väljastab ekraanile kõigi inimeste nimed kujul perekonnanimi ja eesnimede esimesed tähed koos punktiga ja tühikuga. Kui eesnimes on sidekriips, säilib see ka eesnimelühendis ja punkt sel juhul ainult teise eesnime tähe järel.main
, mis eelnevaid kasutab
Näiteks ülaltoodud faili puhul ilmub ekraanile
Suur A. Blond M. S. Maasikas M-L. Tamm T. H. C.
NB! Siin antud näidisandmetes algavad read tühikuga. See on courses wiki piirang. Päris sisendfailide ridade alguses tühikuid ei ole.
SortedUniquePersonList
Antud on klassid Person ja Test. Loo klass SortedUniquePersonList, mis on kollektsioon Person objektide hoidmiseks.
SortedUniquePersonList objektid peavad garanteerima järgmist:
- Hoitavate Person elementide isikukood on selle listi jaoks unikaalne - ei tohi olla võimalik, et kahel samas järjendis oleval Person objektil on sama ID kood.
- Elemendid on kasvavalt järjestatud isikukoodi väärtuse alusel - Person objekt isikukoodiga "1" peab olema väiksema indeksiga kui Person objekt isikukoodiga "2"
- Sisemiselt hoitakse Person objekte Person[] tüüpi massiivis - aga see massiiv ei tohi olla väljastpoolt objekti kättesaadav!
- Sisemise massiivi suurus ei tohi olla rohkem kui 2 korda suurem parasjagu hoitavate elementide arvust. See tähendab, et vastavalt vajadusele peab mõnikord uue suurema või väiksema suurusega massiivi looma ning kõik viited sinna üle kopeerima.
- Elementide lisamisel ja eemaldamisel peavad kõik järgnevad elemendid vastavalt nihkuma.
Person ja Test klassid ning SortedUniquePersonList klassi põhja leiad siit: https://gist.github.com/mbakhoff/9f8aa032656c6acf7696a84cc749b02e Lugege hoolikalt klassi ja meetodite kommentaare ning veenduge, et teie poolt implementeeritav funktsionaalsus vastab kommentaarides väljalubatud nõuetele.
Antud Test klass kontrollib elementaarseid toiminguid, aga ei pruugi kõiki vigu leida. Kontrolli oma kood ise ka üle ja ära jää ainult Test peale lootma.
NB! Siin ülesandes tuleb sisemiselt kasutada just Person[], mitte ArrayList<Person> vms sisseehitatud resizable andmestruktuure. Ülesande eesmärk ongi ehitada ise midagi ArrayList sarnast.
NB! Sisemise Person[] peal ei peaks olema vaja kutsuda sorteerimisalgoritme. Lisa uued elemendid kohe õigesse kohta ja vajadusel tõsta olemasolevaid elemete edasi.
Tantsupaarid v2
Koosta meetod combine
, mis võtab parameetriteks kaks täisarvumassiivi — poiste pikkuste massiiv ja tüdrukute pikkuste massiiv (pikkused on antud sentimeetrites). Kumbki massiiv ei pruugi olla pikkuste järgi järjestatud. Koostada programm, mis moodustab tantsupaarid (poiss ja tüdruk) järgmise eeskirja kohaselt.
- Kui poisse ja tüdrukuid on võrdselt, siis moodustatakse paarid nii, et kõige pikem poiss tantsib kõige pikema tüdrukuga, pikkuselt järgmised on omavahel paaris jne.
- Kui ühe soo esindajaid on rohkem kui teise soo esindajaid, siis jäetakse sellest soost sobiv arv kõige pikemaid ilma paariliseta.
Meetod peab tagastama kahemõõtmelise massiivi, kus on nii mitu elementi, kui tantsupaare koostati. Iga massiivi element on kahe elemendiga massiiv, kus esimene element on poisi pikkus ja teine tüdruku pikkus.
Koosta main
meetod, mis saab käsurealt parameetriteks poiste ja tüdrukute pikkused, koostab combine
meetodi abil tantsupaarid ja prindib need ilusti välja. Käsurida on järgnevas formaadis: poiste arv, iga poisi pikkus tühikutega eraldatud, tüdrukute arv, iga tüdruku pikkus tühikutega eraldatud.
Näide
Sisend:
3 176 179 169 2 172 167
Väljund:
176 ja 172 169 ja 167
NB! Käsurida (main
meetodi parameeter) mitte segi ajada interaktiivse sisendiga System.in
.
Vihje: Massiivi võib sorteerida kasutades meetodit java.util.Arrays.sort(int[])
.