wiki:k2015/demot/demo5
Last modified 2 years ago Last modified on 2015-02-18 08:56:23

Demot » Demo 5, 16.2.2015

  • Muista: Hyväksytä harjoitustyön suunnitelma demo 5:n palautuksen määräpäivään mennessä.
  • Tehtävien nimeämisestä: Anna cs-tiedostoille kuvaavat nimet. Esim. G1.cs on huono. Opetellaan käyttämään nimiä, jotka toimisivat oikeassakin ohjelmassa. Pallopeli.cs on taas paljon parempi. Muista myös luokan ja tiedoston nimen suhde. Erityisesti, jos nimeät kaikki Program.cs:ksi, niin ne kirjoittavat NettiDemoWWW:ssä aina edellisen samannimisen tiedoston päälle :-(

Oppimistavoitteet

Tämän demokerran päätteeksi

  • ymmärrät mihin taulukkoa voi käyttää ja osaat tehdä taulukon
  • ymmärrät silmukkarakenteiden (while, for, do-while) toimintaperiaatteen
  • algoritminen ajattelusi kehittyy

Tehtävä 1

TODO OPETTAJILLE: seuraaville vuosille tähän väliin joku helpompi tehtävä, silmukka- ja taulukkodrillausta, ja tämä vasta myöhemmin

M: 15. Taulukot.

Ota Demon 4 tehtävän 5 mallivastaus (SuurinJaPienin.cs) ja muuta sen pääohjelma seuraavaksi.

public static void Main(string[] args)
{
  int[] luvut = new int[3];
  Console.Write("Anna 1. kokonaisluku >");
  luvut[0] = int.Parse(Console.ReadLine());
  Console.Write("Anna 2. kokonaisluku >");
  luvut[1] = int.Parse(Console.ReadLine());
  Console.Write("Anna 3. kokonaisluku >");
  luvut[2] = int.Parse(Console.ReadLine());
  
  int suurin = Suurin(luvut);
  int pienin = Pienin(luvut);
  
  Console.WriteLine("Suurin luku on " + suurin);
  Console.WriteLine("Pienin luku on " + pienin);
  Console.ReadKey();
}

a) Muuta funktiot Suurin ja Pienin niin, että ne käsittelevät kolmepaikkaista taulukkoa (tässä ensimmäisessä taulukkotehtävässäsi saat poikkeuksellisesti olettaa että taulukossa on tasan 3 alkiota, jatkossa tällaista oletusta ei saa tehdä). Ideana tässä on siis suurinpiirtein korvata koodissa (verrattuna demo4/tehtävä5:een)

 a => luvut[0]
 b => luvut[1]

b) Tee funktiot Suurin2 ja Pienin2 siten, että käyt taulukot for-silmukassa läpi (eli ei enää yksitellen lukujen vertailuja). Muuta pääohjelmaa siten, että ensin käyttäjältä kysytään, montako lukua halutaan, ja taulukosta tehdään niin iso. Esimerkki ohjelman toiminnasta.

Tehtävä 2

M: 16. Toistorakenteet.

Tee aliohjelma TulostaKertotaulu(n), joka tulostaa luvun n kertotaulun for-silmukalla.

Esimerkiksi kutsu TulostaKertotaulu(3) tulostaisi:

 1 * 3 =   3
 2 * 3 =   6
 3 * 3 =   9
 4 * 3 =  12
 5 * 3 =  15
 6 * 3 =  18
 7 * 3 =  21
 8 * 3 =  24
 9 * 3 =  27
10 * 3 =  30

Tee vielä TulostaKertotauluWhile(n, m), joka tulostaa n:än kertotaulusta m riviä ykkösestä alkaen. Toteutus while-silmukalla.

Esimerkiksi kutsu TulostaKertotauluWhile(3, 5) tulostaisi

 1 * 3 =   3
 2 * 3 =   6
 3 * 3 =   9
 4 * 3 =  12
 5 * 3 =  15

Tee sama vielä do-while-silmukalla. Mitä TulostaKertotauluDoWhile(6, 0) tulostaa jos ei tehdä mitään erikoislisäyksiä? Mitä pitäisi lisätä?

Tehtävä 3

M: 12.3 Muokattavat merkkijonot: StringBuilder.

Tee seuraavaan pääohjelmaan tarvittava aliohjelma:

public static void Main(string[] args)
{
  StringBuilder jono = new StringBuilder("kissa istuu");
  LisaaAlkuunJaLoppuun(jono, "***"); // jono muuttuu aliohjelmassa
  Console.WriteLine("Jono on nyt " + jono); 
  // tulostaa: Jono on nyt *** kissa istuu ***
}

Vinkki: Katso StringBuilderin dokumentaatiosta miten voit lisätä tekstiä jonon keskelle ja miten loppuun.

Tehtävä 4

M: 15. Taulukot, 16. Toistorakenteet.

Olkoon meillä taulukko, joka sisältää int-tyyppisiä kokonaislukuja.

Tee aliohjelma TulostaYli(taulukko, raja), joka tulostaa taulukosta kaikki ne luvut (alkiot), jotka ylittävät annetun rajan eli tietyn luvun. Päätä itse ja dokumentoi, että kuuluuko raja tulostettaviin vai ei.

Tee vastaava funktio SummaYli(taulukko, raja), joka palauttaa rajan ylittävien taulukon lukujen summan.

Esimerkiksi pääohjelma...

public static void Main(string[] args)
{
  int raja = 4; 
  int[] luvut = { 12, 3, 5, 9, 7, 1, 4, 9 };
  TulostaYli(luvut, raja);
  int summa = SummaYli(luvut, raja);
  Console.WriteLine("Yli " + raja + " olevien lukujen summa on: " + summa);
  Console.ReadKey();
}

...tulostaisi...

12 5 9 7 9
Yli 4 olevien lukujen summa on: 42

Tehtävä 5

Et tarvitse Visual Studiota/C#:ia tässä tehtävässä.

M: Moniulotteiset taulukot

Olkoon meillä 4 x 4 matriisi, siis 2-ulotteinen taulukko (voit ajatella ruudukkona), jossa on 16 alkiota. Tässä hakasulut kuvaavat vain matriisin reunoja, ei mitään sen "syvällisempää".

[ 1 0 1 1 ]
[ 0 1 1 0 ]
[ 1 0 0 0 ]
[ 1 0 0 1 ]

Ykköset kuvaavat tässä "sopuleita", ja nollat ovat tyhjiä paikkoja.

Lisäksi olkoon seuraavanlainen algoritmi:

Jos ruudussa on sopuli (eli alkion arvo on 1)
  * Jos sillä on naapureita (ykkösiä) yksi tai 
    nolla kappaletta, se kuolee yksinäisyyteen 
    (muuttuu nollaksi).
  * Jos sillä on neljä tai enemmän naapureita, 
    se kuolee ylikansoitukseen (muuttuu nollaksi).
  * Sellainen, jolla on täsmälleen kaksi tai kolme 
    naapuria, selviää hengissä.
Jos ruutu on tyhjä (eli arvo on 0)
  * Jos on täsmälleen kolme naapuria, ruutu "herää 
    eloon" (muuttuu ykköseksi).

Tee yllä olevalle matriisille kolme seuraavaa generaatiota, eli käy jokainen alkio läpi yllä annettua algoritmia käyttäen. Naapureita ovat sekä pysty-, vaaka- että "vinot" naapurit.

Tee tehtävä kahdella eri tavalla:

  1. Niin, että aina teet uuden tyhjän taulukon ja siihen vastinpaikkaan kuuluvan alkion arvon katsot edellisestä taulukosta em. säännöillä.
  2. Kopioit edellisen taulukon ja lähdet kopiota muuttamaan "laskemalla" arvot kopiotaulukosta itsestään. Alkiot käsitellään vasemmalta oikealle, ylhäältä alas.

Tuleeko eri tavoilla tehtynä eri tulos? Miksi?

Palauta tehtävä tekstitiedostona teht5.txt, joka sisältää alkuperäisen taulukon lisäksi kumpaankin eri tapaan kolme uutta samankokoista taulukkoa. Kirjoita taulukot allekkain tekstitiedostoon.

(Lue tästä vinkki, jos tehtävä ei lähde aukeamaan.)

Tehtävä 6

(a) (0.5 p.) Lataa ja asenna ComTest. Voit laittaa itsellesi puoli pistettä kun ko. sivulla oleva esimerkkitesti (Example Test) menee läpi.

(b) (0.5 p.) Täydennä seuraavaan funktioon ComTest-testit, missä toinen laskettavista luvuista on negatiivinen, sekä ainakin yksi sellainen testi, missä tulos on negatiivinen. Paikka, mihin testit kirjoitetaan on tässä kommentoitu TODO-sanalla. Kirjoita myös ympärille luokka, sekä luokan pääohjelma omatoimisesti. Pääohjelma voi olla "tyhjä", eli sen ei tarvitse tehdä mitään. Palauta .cs tiedosto.

Toteuta myös itse funktio ja täydennä puuttuvat sanat, jotka on alla xxx:llä. Aja testit ja totea että ne menevät läpi.

/// <summary>Lasketaan yhteen kaksi lukua</summary>
/// <param name="luku1">ensimmäinen yhteenlaskettava</param>
/// <param name="luku2">toinen yhteenlaskettava</param>
/// <returns>lukujen summa</returns>
/// <example>
/// <pre name="test">
///  Laskut.LaskeYhteen(2, 3) ~~~ 5;
///  Laskut.LaskeYhteen(2.4, 0) ~~~ 2.4;
///  // TODO: testi jossa toinen on negatiivinen ja tulos positiivinen
///  // TODO: testi jossa toinen on positiivinen ja tulos negatiivinen
/// </pre>
/// </example>
public static xxx LaskeYhteen(xxx luku1, xxx luku2)
{
  // toteuta funktio
}

Huomaa: Liukulukuja (eli double, float tai decimal-lukuja) ei saa verrata ComTestissa kolmella yhtäsuuruusmerkillä (===), vaan niitä täytyy verrata kolmella matomerkillä ~~~.

Syy, miksi reaalilukuja ei voi (muutamia poikkeuksia lukuunottamatta) verrata ComTestissä === -merkinnällä, eikä tavallisessa koodissa == -vertailuoperaattorilla, on, että tietokoneella voidaan tarkasti ilmoittaa ainoastaan 2-potenssien summia (muistatko vielä binäärilukujen perusteet?)

Esimerkiksi luku 0.1 ei ole 2-potenssien summa, joten tietokoneen näkökulmasta se onkin tietokoneen näkökulmasta jotain himpun verran yli 0.1 (ks. http://bit.ly/1589Imk).

Luku 0.75 sen sijaan onkin 2-potenssien summa (ks. http://bit.ly/zn6R9Y)...

1 * 2-1 + 1 * 2-2

...joten tietokoneen näkökulmasta se on tasan 0.75.

Aihetta käsitellään vielä luennoilla ja demoissa, mutta tässä vaiheessa on tärkeintä muistaa:

  • jos funktion paluuarvo double, niin vertailu tehdään ComTestissa ~~~ -merkinnällä
  • "normaalissa" koodissa ollaan varovaisia double-lukujen vertailuun == -operaattorilla, koska yleensä se menee pieleen

Ville 1

Tee Ville-tehtävät: 4.5, 4.6, 5.1-5.5, 9.1, 9.2, 9.3.

Huom: Lue tarkasti kysymykset (montako kertaa, montako tulostetaan). Villen mallissa loppusulkuun } mennään kun silmukka loppuu.

TDD1

Jos tarkistat vähintään kahden funktion toiminnan automaattisella testillä (ComTest), saat merkitä yhden lisäpisteen. Huom: Tehtävästä 6 et voi kuitenkaan saada tuplapisteitä :-)

Käyttääksesi ComTestiä asenna se tietokoneellesi edellä löytyvän linkin ohjeiden mukaan. Voit varmistaa että asennus on mennyt oikein läpi näin:

  1. Tee uusi projekti
  2. Copy-pasteta tämä testikoodi projektiisi
  3. Aja ComTest (Tools -> ComTest -> ComTest solution)
  4. Jos avautuu alas Test Results ja vihreä pallo missä lukee Passed, niin kaikki meni oikein. Muussa tapauksessa tutki asennusohjeita uudestaan ja kysy tarvittaessa apua ohjaajilta.

Palauta NettiDemoWWW:ssä tekstitiedosto tdd.txt (jonka siis arvostelet yhden pisteen arvoiseksi), missä kerrot minkä tehtävän ja minkä funktion/funktioiden toiminnan testasit. Voit antaa samassa tiedostossa palautetta ja kehitysehdotuksia Comtestin käytöstä. Tehtävän "numeroksi" anna TDD1.

Taulukon testaaminen Comtestilla:

/// int[] luvut = {1,3,6};
/// String.Join(luvut, " ") === "1 3 6";

Jos haluat viedä testiin taulukon ilman, että luot apumuuttujaa, niin tee seuraavasti.

/// SuurinJaPienin.Pienin(new int[]{1, 2 ,3}) === 1;

Valitettavasti 2-ulotteiselle taulukolle ei ole vastaavaa Join-funktiota, vaan sellaisen joutuu tekemään itse (Voit copy-pastettaa tämän tai tehdä oman.)

StringBuilderin arvon testaaminen pitää suorittaa ToString()-metodin avulla

/// StringBuilder j1 = new StringBuilder("123");
/// Jonoja.LisaaAlkuunJaLoppuun(j1, "XX");
/// j1.ToString() === "XX 123 XX";

B1

M: 12. Merkkijonot.: Tuliko Demo 4 tehtävässä 4 isot kirjaimet huomioitua? Muuta tehtävän 4 vastausta niin, että teet funktioaliohjelman (palauttaa siis merkkijonon), jota kutsutaan seuraavasti:

String tulos = MuutaKirjaimet(jono, 'k', 'g');

Funktio muuttaa sekä isot että pienet kirjaimet. Tee tuota funktiota käyttäen ohjelma joka toimii seuraavasti:

Toistan mitä sanot, mutta en osaa sanoa kirjainta g.
Anna teksti > Kalle tykkää jätskistä.
Sanoit siis : Galle tyggää jätsgistä.

Ohjelma saadaan siis kahden merkin vaihtamisella toimimaan edellisen kerran tehtävän 3 vastauksena (siinähän piti r:t vaihtaa l:ksi).

B2

Ota Demo 4:n bonus ja guru-tehtävien pallopelin mallivastaus.

Katso Jypelin ohjeista miten lisätään pistelaskuri ja sille tapahtuma kun tulee tarpeeksi pisteitä.

Lisää pallopeliin laskuri jonka arvo kasvaa aina kun saat "metsästettyä" pallon puolen välin yläpuolella. Kun 10 palloa on saatu poksautettua, lisää tähän joku onnittelu (vaikka MessageDisplay-oliolla).

Mallivastauksessa käytetyt kuvat saat käyttöön seuraavasti:

  • ota kuvat.zip
  • pura se johonkin hakemistoon
  • mene siihen kansioon, johon purit kuvat
  • raahaa kuvat PallotContent -nimen päällä Visual Studiossa

Jos et halua käyttää kuvia, kommentoi koodista pois kaikki kuviin liittyä tai laita omia kuvia tilalle.

G1-2

Tee konsoliohjelma, joka tulostaa vaiheittain tehtävän 5 generaatioita.

Saat 2 pistettä, kun tehtävässä on myös automaattiset testit kummankin tapauksen 3:lle generaatiolle.

Testaamisen helpottamiseksi voit käyttää valmista funktiota, joka palauttaa matriisin merkkijonona.

G3

  • Mitä eroa on seuraavilla taulukoilla?
  • Miksi C#:ssa on kaksi eri tapaa ilmaista moniulotteisia taulukoita?
int[,] a = new int[3, 2];
int[][] b = new int[3][];

G4-5

a) (1 p.) Tee tehtävä 4 käyttäen C#:n LINQ:lla tai lambdoilla. Vinkki (jos tarvit :)): Saat muutettua Where:n palauttaman IEnumerable:n taulukoksi ToArray:llä.

b) (1 p.) Ota tehtävä 4:n taulukko ja sieltä sellaiset luvut, jotka ovat suurempia kuin 5 ja parillisissa indekseissä.