Demo 9
Palauta viimeistään ma klo 11:59.
Ajankäyttösi tällä viikolla
Työtuntien kirjaamisesta saa 0.5 demopistettä. Aseta pisteesi Set Custom Points -toiminnolla.
Demokerran päätteeksi kirjoita arvio tällä viikolla käyttämästäsi työmäärästä. Laske työmäärään mukaan kaikki tällä viikolla käyttämäsi aika: lähiopetukseen osallistuminen, oppimateriaalin lukeminen, demotehtävien tekeminen, luentovideon katsominen, demojen purkutilaisuuteen osallistuminen (maanantaina) ja niin edelleen. Voit päivittää lukua viikon edetessä, se voi helpottaa arvion tekemistä. Huom! Siis tähän ei laiteta kurssin alusta kaikkia tunteja yhteensä, vaan vain tämän viikon tunnit.
Jokaisella opiskelijalla on oikeus ja velvollisuus arvioida itse omien pisteidensä oikeellisuus. Mikäli ohjelmasi ei toimi, niin aseta itsellesi Custom pointsit itsearviosi mukaisesti, esim. mikäli ajattelet että olet saavuttanut 50% tehtävän tavoitteista niin silloin laitat itsellesi enintään 0.5 pistettä. Vastaavasti, jos arvioit että tehtäväsi on 90%:sti oikein, mutta automaattinen arviointi antaa sinulle jostain syystä vähemmän pisteitä, aseta itsellesi 0.9 pistettä.
PP4, perjantai klo 12-16 (Teams -> PP)
PP-tehtävät (näistä saa pisteitä vain käymällä perjantain PP-ryhmässä. Tulevan perjantain PP-tehtävät jaetaan perjantaina.) Mitä ovat PP-tehtävät?
Harjoittelutehtäviä
Jos tehtävissä 1 tai 2 on yhtään haasteita, niin kokeile harjoittelutehtäviä. Harjoittelutehtävien tarkoitus on viedä opiskelija ohjatusti vaihe vaiheelta kohti tehtävän ratkaisua.
Tehtävä 1*
Lue ensin: 15. Taulukot.
Toteuta funktio PisinKasvava
, joka palauttaa int
-lukuja sisältävän taulukon pisimmän aidosti kasvavan osajonon pituuden. Huomaa, että mikäli perättäiset alkiot ovat yhtä suuria, niin silloin kyseinen kahden alkion osajono ei ole aidosti kasvava. Tee funktiolle myös vähintään kolme erilaista testiä, joista yksi on alla olevan esimerkin mukainen.
Huomaa, että funktio palauttaa nimenomaan jonon pituuden, eli yhden kokonaisluvun.
Esimerkkejä:
- Taulukon
3, 3, 4, 4, 4, 0, 3, 4, 6, 6, 2
pisin aidosti kasvava osajono on0, 3, 4, 6
. Sen pituus on 4, joten funktio palauttaa arvon 4. - Taulukon
2, 2, 2
pisimmän aidosti kasvavan osajonon pituus on 1 (osajono jossa on vain alkio2
).
Huomaa, että ratkaisussasi et saa olettaa että parametrina tuleva taulukko on aina juuri kyseinen yllä oleva taulukko; ratkaisusi tulee toimia kaikenlaisilla taulukoilla.
Pisteytys: 0.5 pistettä kun funktio kääntyy, 0.4 pistettä itse tehdyistä ja läpi menevistä testeistä, ja 0.1 pistettä dokumentaatiosivun luomisesta ja tämän sivun avaamisesta (Document-linkki vastauslaatikon alapuolella).
Halutaan siis etsiä alkuperäisestä jonosta t
pisin osajono, missä kaikki alkiot toteuttavat ehdon t[i-1] < t[i]
.
Tässä vielä toinen esimerkki ko. tehtävään:
Lukujonon
3, 5, 4, 4, 0, 1, 4, 6, 2
pisin aidosti kasvava osajono on
0, 1, 4, 6
ja tämä kyseinen osajono siis "alkaa" alkuperäisen jonon viidennestä alkiosta (luku 0) ja päättyy alkuperäisen jonon kahdeksanteen alkioon (luku 6).
Tässä pyydetään tehtävänannossa tekemään funktio nimeltä PisinKasvava, mutta tarkistin kaipaa funktiota nimellä PisinNouseva.
Kiitos huomiosta, tarkistinta on nyt päivitetty. Funktion nimi pitää nyt ihan oikeasti olla PisinKasvava. -AJL
—Hei, miksihän pisteet 0,4 vaikka kaikki toimii ja testit menee läpi?
Ratkaisusi antaa väärän tulosteen (ks. Näytä koko koodi). -AJL
—Vinkki: Jos algoritmi ei ole kristallin kirkas, harjoittele Taunolla ja/tai kynällä ja paperilla.
Tehtävä 2*
Palataan hetkeksi kurssin alkupuolen laatikkotehtävään. Muuta ohjelmaa hieman. Begin
-aliohjelman tulisi näyttää tältä.
Tässä viedään siis PiirraNelio
-aliohjelmalle laatikon vasemman alakulman sijainti Vector
-oliona. Funktio piirtää laatikon ja palauttaa piirtämänsä laatikon oikean yläkulman koordinaatin. Nyt seuraavan laatikon piirtäminen on yksinkertaista koska se voidaan aloittaa edellisen kutsun palauttamasta paikasta.
Piirrä vielä pieni punainen ympyrä, joka on pisteessä (0, 0). Ympyrän saat muiden olioiden päälle varmasti kun lisäät sen "ylemmälle" tasolle seuraavasti:
Kuva siitä, miltä toimiva ohjelma näyttää ruudulla:
Vinkki: Aliohjelma ottaa siis parametrina neliön vasemman alareunan koordinaatin. Tee Vector keskipiste
, johon lasket keskipisteen sijainnin kun tiedät vasemman alareunan sijainnin ja sivun pituuden. Vastaavasti voit tehdä Vector oikeaYlakulma
, johon lasket oikean yläkulman sijainnin vastaavia tietoja käyttämällä.
Tehtävä 3
Tee ohjelma, joka tulostaa taulukon kaikki mahdolliset lukuparit ja niiden summat. Esimerkiksi jos taulukko olisi:
int[] luvut = new int[] { 2, 3, 9, -5 };
niin tulostuksen pitäisi näyttää tältä:
2 ja 3, summa on: 5
2 ja 9, summa on: 11
2 ja -5, summa on: -3
3 ja 2, summa on: 5
3 ja 9, summa on: 12
3 ja -5, summa on: -2
9 ja 2, summa on: 11
9 ja 3, summa on: 12
9 ja -5, summa on: 4
-5 ja 2, summa on: -3
-5 ja 3, summa on: -2
-5 ja 9, summa on: 4
Voit tehdä koko ohjelman Main-pääohjelman sisään. Aliohjelmia ei tarvita. Lukuparit saa tulostaa kahteen kertaan järjestystä vaihtaen; esimerkiksi yllä muiden muassa "2 ja 3" (taulukon paikat 0 ja 1) sekä "3 ja 2" (taulukon paikat 1 ja 0) ovat sama lukupari mutta vain järjestys vaihtuu. Tulostuksia ei saa tehdä "manuaalisesti", vaan ohjelman pitää toimia myös siinä tilanteessa, että taulukkoa muutetaan.
Arviointi: Merkitse pisteesi käyttäen Set custom points -toimintoa.
Tehtävä kääntyy riderissa. Miksi palautuslaatikossa ajettaessa tulee error?
VL: Se pitää olla System.Console
. En tiedä miksi Rider päästää läpi ilman.
Varmaankin using-lauseet unohtui copy-pastettaa tähän vastauslaatikkoon. -AJL
—Tehtävä 4 (1-2 p.)
Varsinainen tehtävä (1 p.): Tee funktio nimeltä OnkoSummaa
, joka ottaa kaksi parametria: int
-taulukon ja int
-luvun. Funktio palauttaa bool
-arvon sen perusteella, löytyykö annetusta taulukosta lukupari, jonka summa on parametrina annettu int
-luku.
Esimerkiksi kutsu
int[] t = new int[] {1, 2, 3, 9};
bool loytyyko = OnkoSummaa(t, 8);
palauttaisi false
, sillä taulukosta ei löydy kahta lukua jotka summautuisivat lukuun 8. Sen sijaan kutsu
int[] t = new int[] {1, 2, 4, 4};
bool loytyyko = OnkoSummaa(t, 8);
palauttaisi true
, sillä 4 + 4 = 8.
Jatko-osa (+ 1 p.): Oletetaan että saatu aineisto on suuruusjärjestyksessä. Käytä Array.Sort
-metodia järjestääksesi kokonaislukutaulukko. Ota alla oleva mallikoodi Rideriin ja kokeile, kuinka kauan funktiosi ajo kestää 100,000 alkiolle. Jos saat ajan alle 50 millisekuntiin, voit merkitä itsellesi tästä toisen pisteen.
Onko tässä tarkoitus käyttää rekursiota?
Ei. Tai ainakaan en itse keksi miten tuon saa menemään "nopeasti" rekursiolla :D. -AJL
Saisiko vinkkiä miten sen saisi nopeasti? :D
—Huom: koska mukana on satunnaisuutta, niin riittää, että "tavallisesti" ajo menee tuohon alle 50 millisekuntiin. Ei haittaa jos joissain yksittäisissä tapauksissa menisikin hieman kauemmin, kunhan tulokset eivät ole tuhansien millisekuntien luokkaa kuten raakaan voimaan perustuvissa algoritmeissa. Toimiva ratkaisu läpäisee myös Main
in alussa olevan pienimuotoisen toiminnallisuustestin.
using System;
using System.Collections.Generic;
using System.Diagnostics;
public class Summa
{
public static void Main()
{
int[] testi = new int[] {1,2,2,3,5};
bool testiLapi = !OnkoSummaa(testi,1) && !OnkoSummaa(testi,2) &&
OnkoSummaa(testi,4) && OnkoSummaa(testi,6);
Console.WriteLine(testiLapi ? "Testit läpäisty." :
"Testit epäonnistuivat, virheellinen toteutus!");
const int MONTAKO = 100000;
int[] luvut = LuoSatunnainenTaulukko(MONTAKO, 0, MONTAKO / 2);
Array.Sort(luvut);
Stopwatch sw = Stopwatch.StartNew();
bool loytyykoPari = OnkoSummaa(luvut, MONTAKO);
sw.Stop();
double ms = sw.Elapsed.TotalMilliseconds;
Console.WriteLine("Kesti: " + ms + " millisekuntia.");
}
private static int[] LuoSatunnainenTaulukko(int pituus, int min, int max)
{
Random r = new Random();
int[] luvut = new int[pituus];
for (int i = 0; i < luvut.Length; i++)
luvut[i] = r.Next(min, max);
return luvut;
}
}
Tehtävä 5 (1-2 p.)
TODO opettajille: Erota nämä kahdeksi eri tehtäväksi.
Lue ensin: 23. Dynaamiset tietorakenteet.
Kohta 1: Tee funktio PisinJono
, joka etsii merkkijonolistan (List<string>
) pisimmän merkkijonon ja palauttaa kyseisen merkkijonon. (1 p.)
Kohta 2: Tee funktio PoistaJonot
, joka ottaa vastaan merkkijonolistan (List<string>
), sekä poistettavan merkkijonon (string
). Funktio poistaa listasta kaikki jälkimmäisen merkkijonon esiintymät. (1 p.)
TODO Opettajille: Kohdassa 2 tulee mainita että/jos muutetaan listan sisältöä aliohjelmassa.
Automaattinen arvostelu kertoi tarkistamisen yhteydessä että PisinJono-funktioni on osittain väärin, sillä syötteellä "täi, täi, täi" se palautti "täi" ja sen olisi pitänyt palauttaa "sisu". Onko tämä virhe tarkistuksessa vai ymmärränkö jonkin asian tässä väärin?
Kyllä sinulla pieni virhe siellä on (ks. if-lause kun löytyy uusi pidempi jono). En ollut tuollaista virhettä osannut odottaa, joten tarkastajan virhe on ehkä vähän mystinen :-). Korjailen sen kun ehdin. -AJL
Virheen korjaamisen jälkeen tajusin, miksi tarkastaja hämmentyi. Vähän kyllä kiinnostaa miten koodini sekoitti tarkastajan noin pahasti... Kiitos avusta joka tapauksessa.
—Pisteytys: Tehtävässä on automaattinen arvostelu.
Huomautus: ComTest-testit eivät tällä hetkellä toimi tässä tehtävässä. Selvittelemme vikaa. (Testien puuttuminen ei vaikuta tässä pisteisiin.) Lisäys: NYt pitäisi testienkin toimia. Ilmoitelkaa jos tehtävässä on vielä probleemaa.
Tehtävä 6
Valmistelut: Ota Kotuksen nykysuomen sanalista (klikkaa hiiren oikealla ja sitten Tallenna linkki nimellä).
Tee uusi ConsoleMain -projekti ja lisää lataamasi tekstitiedosto projektiin: hiiren oikealla projektin päälle \(\rightarrow\) Add \(\rightarrow\) Existing Item \(\rightarrow\) Etsi juuri äsken lataamasi .txt
-tiedosto. Nyt kun tiedosto on projektissa, klikkaa siitä vielä hiiren oikealla \(\rightarrow\) Properties \(\rightarrow\) Copy to output directory -kohtaan laita Copy if newer
.
Tiedoston sisältämän aineiston saat luettua String
-taulukkoon kirjoittamalla Main
-pääohjelmaan:
Kirjoita vielä ohjelmakoodin alkuun nimiavaruusviite using System.IO;
Tehtävä: Tee ohjelma, joka kysyy käyttäjältä merkkijonon. Toteuta sitten funktio joka palauttaa listan niistä Kotus-listan sanoista, jotka sisältävät kaikki käyttäjän antamat merkit. Lopuksi ohjelma tulostaa löydetyt sanat ruudulle.
Ota alla olevasta SisaltaaKaikkiMerkit
-funktiosta kopio omaan ohjelmaasi ja käytä sitä hyväksesi. Tämä funktio palauttaa true
tai false
sen mukaan sisältääkö annettu (yksi) merkkijono kaikki annetut merkit.
Pisteytys: 0.9 pistettä kun funktio kääntyy ja 0.1 pistettä dokumentaatiosivun luomisesta ja tämän sivun avaamisesta (Document-linkki vastauslaatikon alapuolella).
/// <summary>
/// Funktiossa tutkitaan voidaanko annettu merkkijono
/// "upottaa toiseen merkkijonoon", eli
/// sisaltaako sana kaikki annetut merkit.
/// </summary>
/// <param name="sana">Sana, johon upotetaan</param>
/// <param name="merkit">Upotettava sana (eli tämän sanan
/// kirjaimet pitää löytyä ekasta sanasta)</param>
/// <returns>Onnistuko uptus</returns>
/// <example>
/// <pre name="test">
/// SisaltaaKaikkiMerkit("antti", "antti") === true;
/// SisaltaaKaikkiMerkit("antti", "at") === true;
/// SisaltaaKaikkiMerkit("at", "antti") === false;
/// SisaltaaKaikkiMerkit("anttijussi", "tia") === true;
/// SisaltaaKaikkiMerkit("anttijussi", "") === true;
/// SisaltaaKaikkiMerkit("anttijussi", "tiaa") === false;
/// SisaltaaKaikkiMerkit("", "") === true;
/// SisaltaaKaikkiMerkit("", "a") === false;
/// </pre>
/// </example>
public static bool SisaltaaKaikkiMerkit(String sana, String merkit)
{
StringBuilder merkitNyt = new StringBuilder(merkit);
StringBuilder sanaNyt = new StringBuilder(sana);
int i = 0;
while (i < merkit.Length)
{
char merkkiNyt = merkit[i];
// Tehdään seuraavaksi koodi jonka avulla
// löydetään merkin paikka StringBuilder-oliossa.
// Tämä vastaa String-olion IndexOf-metodia, jota
// ei valitettavasti löydy StringBuilderille.
int merkinPaikka = -1; // arvataan aluksi että merkkiä ei löydy.
int j = 0;
while (j < sanaNyt.Length)
{
if (sanaNyt[j] == merkkiNyt)
{
merkinPaikka = j;
break;
}
j++;
}
if (merkinPaikka >= 0)
{
sanaNyt = sanaNyt.Remove(merkinPaikka, 1);
}
else return false;
i++;
}
return true;
}
Dokumentointi palauttaa virheilmoituksen. Mistähän tämä voisi johtua? Command '['/cs/doxygen/csdoc.sh /tmp/user/ dca0f620c6587de449edbce894d6a2292eab1ca21529b38ec056318bd9bf41dc/505225 /csgenerated/docs/--/301f3541-5bb4-4944-a4f6-a111b46a31ec /csgenerated/docs/--']' returned non-zero exit status 2.
—V1
Tällä viikolla ei ole uusia Ville-tehtäviä. Voit halutessasi tehdä 5 kappaletta tekemättömiä silmukka- ja/tai taulukkotehtäviä tai muita, joita et aikaisemmin ymmärtänyt. Muista Villen käyttöohje.
TDD1
Jos tarkistat vähintään kahden funktion toiminnan itse kirjoittamillasi automaattisilla testeillä (ComTest), saat tästä tehtävästä yhden pisteen. Kirjoita, minkä tehtävän ja minkä funktion/funktioiden toiminnan testasit ja millaisilla testeillä. Voit antaa samassa tiedostossa palautetta ja kehitysehdotuksia Comtestin käytöstä.
B1
Tee tehtävän 6 ohjelmasta interaktiivinen siten, että käyttäjä voi syöttää sanan kirjain kerrallaan, ja ohjelma näyttää tulokset heti. Katso video.
B2-3
Tee seuraava Console Application -peli.
Kaksi pelaajaa kilpailee siitä, kumpi saa noppaa heittämällä ensin 100 pistettä. Jokaisella vuorolla pelaaja heittää toistuvasti noppaa, kunnes saa joko numeron 1 tai pelaaja sanoo "pankki" jolloin hänen vuorollaan heitettyjen silmälukujen summa lisätään hänen kokonaispistemääräänsä.
Pelaaja kullakin heittokerralla joutuu siis tekemään seuraavan valinnan
- heitto - arvotaan nopan silmäluku 1-6, ja jos tulos on
- 1: pelaaja menettää kaikki omalla vuorollaan heittämänsä pisteet ja vuoro vaihtuu vastustajalle
- 2-6: silmäluku lisätään pelaajan "turn totaliin" ja pelaajan vuoro jatkuu
- pankki - pelaajan omalla vuorollaan heittämät pisteet (eli "turn total") lisätään hänen kokonaispistemääräänsä ja vuoro vaihtuu vastustajalle
B4
Tee algoritmi kokonaislukutaulukon sekoittamiseksi. Tee void-
aliohjelma, joka ottaa parametrina int
-taulukon ja sekoittaa sen alkiot. Testaa algoritmiasi taulukolla, johon on alustettu järjestyksessä luvut 1, 2, 3, ..., 52. Palauta toimiva ohjelmakoodi, jossa on hyvin kommentoituna mitä algoritmissa tehdään.
Lukuja 1, 2, 3, ..., 52 ei tietenkään kannata laittaa taulukkoon manuaalisesti, koska helpompiakin tapoja on jo opittu ;).
Huom: Tässä ei ole tarkoitus "keksiä" omaa algoritmia, vaan käyttää ideaa jostakin valmiista algoritmista sekoittamiseen. Hyvä algoritmi on esim: Fisher-Yates shuffle. Tästä on toteutus Jypelin RandomGen -luokan Shuffle-aliohjelmassa. Jos matkit tätä, niin vaihda T
:n tilalle int
ja listan tilalle int
-taulukko. Funktion alkuun pitää lisätä nyt Random rand = new Random();
jotta Random
-olio on olemassa. Jypelin esimerkissä se on luokan attribuutti.
G1-2
Tee aliohjelma ToistotonTaulukko
, joka saa parametrinaan taulukon, jossa on kokonaislukuja, ja palauttaa taulukon, jossa on alkuperäisen taulukon alkiot kukin vain yhden kerran järjestettynä niiden esiintymiskertojen määrän mukaan nousevaan järjestykseen. (1,5 p.) Täysiä pisteitä varten kirjoita aliohjelmalle myös testit. (0,5 p.)
Esim. taulukosta {1, 2, 3, 34, 34, 2, 1, 34, 1, 1, 1}
palautetaan {3, 2, 34, 1}
.
These are the current permissions for this document; please modify if needed. You can always modify these permissions from the manage page.