wiki:s2013/demot/demo6
Last modified 4 years ago Last modified on 2013-10-17 17:45:54

Demot » Demo 6, 21.10.2013

Muista: Jotta konsolisovelluksen tekeminen olisi helpompaa, ota "parempi" template ConsoleMain Vinkki-sivun ohjeilla.

Demojen palautus NettiDemoWWW:llä ​​​https://www.mit.jyu.fi/demowww/ohj1/

Kysely 1

Vastaa kurssin välikyselyyn:

Vastaamisesta voit merkitä seuraavalle demokerralle yhden demopisteen tehtävänä K1 palauttamalla tiedoston valikysely.txt johon kopioit kohdan

  • "Analysoi omia vaikeuksiasi tai tarkenna edellisiä"

vastauksen. HUOM: Tällä ei saa kiertää minimivaatimusta 2:sta pisteestä/kerta, vaan ne on tehtävä muista tehtävistä.

Tauno 1

Katso ensin video ja mallivastaus Demo 5:n Tauno-tehtävän käsittelystä. Tee iTaunolla seuraavat tehtävät (jos Tauno ei vastaa, ota vara iTauno) :

  1. Ota tiedosto Tauno6.cs. ja tee iTaunolla siinä olevan 1. aliohjelman tehtävä. Jos sinulle on tehtävän ratkaisu C#:illa ilmeistä, saat siirtyä suoraan b-kohtaan.
  2. Tee toimiva ohjelma:
    1. Tee uusi konsoliprojekti projekti nimelle Tauno6.
    2. Korvaa tiedoston Tauno6.cs sisältö pohjatiedostolla Tauno6.cs.
    3. Aja ohjelma tuollaisena (ja jos teet ComTestejä, aja nekin).
    4. Korvaa TODO-kohdassa olevat tiedot Taunoon tekemilläsi. TODO-löytyy VisualStudiossa helposti kun ottaa View/Task List.
    5. Aja ja kokeile saatko oikeat tulokset.
  3. Laita tekemäsi koodi kommentteihin ja korvaa se koodilla, missä sama asia tehdään silmukassa. Kokeile. Aja miellellään testitkin. Kokeile myös erikokoisia taulukoita.
  4. Toista toiselle Tauno6.cs:ssä olevalle tehtävälle.

Palauta Tauno6.cs ja kirjoita luokan Summary-kohtaan mitä opit.

Huom! Tämä on "par 1" tehtävä, eli yksi apumuuttuja riittää (tarvitaan kaksi indeksimuuttujaa). Haluamasi muuttujan arvoa voit kasvattaa/vähentää yhdellä kun raahaat "laskupalkissa" olevan +1/-1 sen päälle. Olemassa olevaa muuttujaa voit käyttää indeksinä raahaamalla sen taulukon solun alla olevaan laatikkoon. Mikäli haluat käyttää toista indeksimuuttujaa, tulee sinun raahata toinen muuttuja toisen taulukon solun alle.

Huom! Tämän hetken Taunossa on sellainen bugi, että indeksit eivät saa mennä päistä ylitse. Et myöskään saa raahata samaa muuttujaa indeksiksi kahta kertaa tai "käy huonosi".

Tauno 2

Tätä ei tehdä oikealla Taunollo, mutta periaatteessa samalla idealla.

  1. Ota tiedosto Tauno62.cs. ja tee olevan aliohjelman tehtävä TAUNOMAISESTI, eli käyttäen vain vakionumeroita (yhteensä 7 lisäriviä mallikoodiin).
  2. muuta vastuaksesi niin, että käytät hyväksesi indeksejä ix,iy vakioiden sijaan niin että minkä tahansa ei-reunassa olevan ruudun naapurit voidaan laskea.

V1

Tee Ville-tehtävät: 5.6-5.8,9.4-9.6 . Muista: Villen käyttöohje ja Ville-tehtävien palauttamisohjeet.

TDD1

Jos tarkistat vähintään kahden funktion toiminnan automaattisella testillä (ComTest), saat merkitä yhden lisäpisteen. Palauta DemoWWW: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ä 1. Aliohjelman esittely

Wiki: Aliohjelmien kirjoittaminen Tee seuraavia aliohjelmakutsuja vastaavat aliohjelmien (tai funktioiden) esittelyrivit ja aliohjelmien lyhyimmät mahdolliset rungot, jotta aliohjelmat ovat syntaktisesti oikein (niiden ei tarvitse toimia loogisesti oikein, vielä).

public static void Main()
{
    StringBuilder muuttuvaJono;
    String jono;
    int i;
    double d;
    int[] luvut;
    double[] t;
    bool onko;

    muuttuvaJono = new StringBuilder("kissa istuu puussa");
    onko = PoistaJonosta(muuttuvaJono, "istuu"); // 

    luvut = new int[]{2,3,2,6,2};
    i = LaskeMaara(luvut, 2);  // laskee montako 2:sta on luvuissa

    jono = PoistaTyhjat("kissa   istuu"); // poistaa kaikki välilyönnit

    t = LuoTaulukko(10, 3.0, 1.1);  // luo taulukon jossa 10 lukua 
                                    // aloittaen 3.0 ja kasvattaen 1.1:llä
                                    // 3.0, 4.1, 5.2, ...
    d = Keskiarvo(t); 
}

Tehtävä 2. Itseisarvo ja etäisyys

Seuraavat kannattaa kirjoittaa samaan projektiin.

  1. M: 13. Ehtolauseet. Kirjoita ilman minkään valmiin funktion käyttöä funktioaliohjelma jota voi kutsua muodossa
     double lukuEiNegatiivisena = Itseisarvo(luku);
    
    joka palauttaa luvun aina positiivisena (tai nollana).. Aloita kirjoittamalla sopiva testipääohjelma (tai ComTest-testit), jossa kutsut funktiota erilaisilla testattavilla arvoilla.
  2. M: 9. Aliohjelman paluuarvo. Kirjoita funktioaliohjelma
    double a,b;
    ...
    double et = Etaisyys(a,b);
    
    joka palauttaa kahden reaaliluvun välisen etäisyyden. Esimerkiksi Etaisyys(3.2, 8.5) on melkein 5.3, samoin Etaisyys(8.5, 3.2).

Tehtävä 3. Miidi

Tämäkin voi kannattaa (=on aika tyhmää olla tekemättä) tehdä edellisen tehtävän kanssa samaan projektiin.

M: 16. Toistorakenteet, 15. Taulukot: Katso Wikipediasta Keskiluvut-kohdasta erilaisia keskilukuja. Yksi lisää voisi olla keskiarvoa lähinnä oleva joukon alkio (josta tässä käytetään nimitystä miidi, jota nimeä ei siis oikeasti ole olemassa). Tee funktioaliohjelma Miidi(double[] luvut) , joka palauttaa reaalilukutaulukon lukujen miidin.

double[] luvut = {1, 2, 3, 2, 5}; // keskiarvo == 2.6
double m1 = Miidi(luvut);             // 3
double m2 = Miidi(new double[]{1});   // 1
double m3 = Miidi(new double[]{3, 3}); // 3
double m4 = Miidi(new double[]{});    // 0
// tulosta m1-m4

Tee tämä Hajoita ja hallitse menetelmällä, eli

  • kopioi luentojen esimerkin Summa-funktio ja tee siitä double luvuilla toimiva versio.
  • tällä voit helposti laskea keskiarvon
  • sitten tee funktio
    public static EtsinLahin(double[] t, double luku)
    
    joka etsii annetusta taulukosta lähintä lukua ja paluttaa sen (katso lähimmän etsimiseen ideaa Pienin ja Suurin -esimerkistä]
  • lopuksi Miidi syntyy keskiarvon ja lähimmän etsimisellä parilla rivillä.

Vinkki: Lähimmän etsimiseksi unohda aluksi koko C# ja tee kynällä ja paperilla vastaava tehtävä ja mieti vaiheittain mitä joudut tekemään ja mitä "apumuuttujia" käyttämään. Ajattele niin, että joku näyttää sinulle yksi kerrallaan yhtä lukua ja sinun pitää pitää yllä tietoa siitä, mikä on toistaiseksi lähinnä etsittävää lukua.

"Algoritmin" selvittämiseksi voi "leikkiä" myös Taunolla tai kokeellisella: Taulukot -ohjelmalla. Talleta ohjelma johonkin ja aja se.

Tehtävä 4. Pisteiden välinen etäisyys

M: 9. Aliohjelman paluuarvo. Muistele koulusta (tai katso Wikipediasta), miten laskettiin suorakulmaisen kolmion hypotenuusa Pythagoraan kaavalla. Päättele miten tämän tiedon avulla voit laskea 2-ulotteisella tasolla olevan kahden pisteen välisen etäisyyden (piirrä kuva paperille, se on 2-ulotteinen taso :-). Kirjoita sitten funktio

double Etaisyys(double x1, double y1, double x2, double y2)

joka laskee kahden pisteen p1 ja p2 (missä p1=(x1,y1) ja p2=(x2,y2)) välisen euklidisen (eli tuon meidän parhaiten ymmärtämän) etäisyyden.

Tehtävä 5. Reaalilukujen vertaaminen

Voi olla T2:n kanssa samassa projektissa koska ehkä kannattaa hyödyntää sen aliohjelmia.

M: 13. Ehtolauseet. Reaalilukuja ei (erittäin harvoja erikoistilanteita lukuun ottamatta) saa verrata == -operaattorilla. Kirjoita reaalilukujen yhtäsuuruusvertailun avuksi funktioaliohjelmat, joita voisi käyttää esimerkiksi seuraavasti:

double a = 7.1001;
double b = 7.1002;
double c = 7.2002;
bool likella = Samat(a, b, 0.01);
if ( likella )          Console.WriteLine("Ovat melkein samoja");
if (!Samat(a, b))       Console.WriteLine("Ovat eri suuria");
if (!Samat(a, c, 0.01)) Console.WriteLine("Ovat eri suuria");
if (Samat(a, c, 0.2))   Console.WriteLine("Ovat sinnepäin");

Samat–funktion ideana on siis se, että jos kaksi lukua ovat "riittävän" lähellä toisiaan, palautetaan true, muuten false. Esimerkissä "riittävän" on 0.01 ja 0.2. Jos tarkkuutta ei anneta, silloin käytetään esimerkiksi 0.00001 tms. varsin pientä lukua. Huomaa että toinen kutsu on vähemmillä parametreillä kuin muut (kuormitettu funktio, function overloading, hoituu C#:issa myös oletusparametreillä). Tee aina ensin aliohjelma sellaiseksi, että ne ovat syntaktisesti oikein, mutta eivät tee mitään järkevää. Esimerkiksi ensin tuo aliohjelma muotoon:

public static bool Samat(double a, double b, double eps=0.00001) 
{
  return false;
}

Sitten aja ohjelma ja totea se syntaktisesti oikeaksi. Ja tämän jälkeen pienillä muutoksilla tee siitä kunnolla toimiva. Kiinnitä myös huomiota aliohjelmien kommentoitiin ja muuttujien nimeämiseen. VS:n Auto Method Stubin tekemät nimet eivät ole kovinkaan kuvaavia.

Tehtävä 6. Skaalaa

M: 9. Aliohjelman paluuarvo. Tee funktioaliohjelma

Skaalaa(double luku, double min, double max)

joka skaalaa välillä [0, 1] olevan luvun välille [min, max]. Esimerkkejä:

Skaalaa(0.2, -3, 3) ~~~ -1.8;
Skaalaa(0.2, 1, 6)  ~~~ 2.0;
Skaalaa(0.0, 1, 6)  ~~~ 1.0;
Skaalaa(1.0, 1, 6)  ~~~ 6.0;

Eli esimerkiksi 1. kutsu tarkoittaa että välin [0,1] luku 0.2 on omaan väliinsä nähden samassa suhteessa kuin luku -1.8 on väliin [-3,3]. Piirrä vaikka molemmat välit ja ko. luvut oman välinsä sisälle.

Vinkki: jos sinulla on luku x väliltä [0, 1] ja haluat saada siitä luvun välille [a, b], niin mieti mitä pitää tehdä jotta 0:sta tulisi a ja 1:stä b. (eli f(x) = a + (b-a)*x ).

Perustelu: Edellä vinkissä on väli olisi voinut olla [0,1] esimerkkinä, koska ohjelmointikielten tyypillinen satunnaislukugeneraattori tuottaa lukuja puoliavoimelle välille 0-1, ja jatkossa meillä on tälle Skaalaa-funktiolle käyttöä nimenomaan tuottamaan satunnaisia lukuja muillekin väleille. Tosin onneksi esim. Jypelissä tämä on valmiina. Pyöristysten kanssa on nimittäin oltava tarkkana :-)

B1. Matriisin suurin

M: 15.5 Moniulotteiset taulukot: Tee funktioaliohjelma, joka etsii 2-ulotteisen reaalilukutaulukon suurimman alkion. Käyttöesimerkki:

public static void Main(String[] args) 
{
  double[,] mat1 = {{1, 2, 3}, {2, 2, 2}, {4, 2, 3}};
  double[,] mat2 = {{9, 2, 8}, {1, 2, 5}, {3, 19, -3}};
  double suurin1 = Suurin(mat1);
  double suurin2 = Suurin(mat2);        
}

Tulosta lopuksi tulos.

B2. Suhteellisesti samat

M: 13. Ehtolauseet: Tehtävässä 5 vertailit ehkä lukujen absoluuttista suuruutta. Kuitenkin esimerkiksi 1000 ja 1100 ovat samoja 10% tarkkuudella, mutta eivät 0.1:n tarkkuudella. Usein voikin jolla järkevä puhua suhteellisesti yhtäsuuruudesta absoluuttisen yhtäsuuruuden sijaan. Kirjoita vielä yksi funktioaliohjelma, jolle pätee:

SuhtSamat(0.10, 0.12, 0.1) === false
SuhtSamat(0.10, 0.11, 0.1) === true
SuhtSamat(1.0, 1.2, 0.1)   === false
SuhtSamat(1.0, 1.1, 0.1)   === true
SuhtSamat(10, 12, 0.1)     === false
SuhtSamat(10, 11, 0.1)     === true
SuhtSamat(1000, 1200, 0.1) === false
SuhtSamat(1000, 1100, 0.1) === true

B3. GameOfLife

Ota edellisen demokerran Sopulit.cs ja tee siitä graafinen versio jossa on paljon ruutuja (suuruusluokkaa 60 y-suunnassa) ja sukupolvia lasketaan 0.1 sekunnin välein. Luo uusi Fysiikka-peli ja kirjoita luokkaan seuraava koodi ja täydennä aliohjelmat (ja metodit). Liitä projektiin tuo Sopulit.cs ja käytä sitä sukupolvi-taulukoiden päivittämiseen.

Projektiin liittäminen:

  • kopioi tiedosto samaan paikkaan kuin projektin muut .cs tiedostot
  • Solution Explorerissa paina hiiren oikeata projektin nimen päällä
  • Add/Existing Item
  • valitse lisättävä tiedosto ja Add
  • lisää omaan .cs tiedostoon alkuun (tässä esimerkissä)
    using Demo5;
    
    tällöin kääntäjä tietää että esim kutsut:
     Sopulit.Arvo(sukupolvi, 0, 1);
     Demo5.Sopulit.Arvo(sukupolvi, 0, 1);
    
    ovat samoja.

Koodipohjaa uudelle pelille:

public class GameOfLife : PhysicsGame
{
    private const int NY = 60;
    private int[,] sukupolvi;
    private int[,] seuraavaSukupolvi;
    private GameObject[,] oliot;
    private Timer timer = new Timer();
    private Color[] varit = {Color.Black, Color.White};

    public override void Begin()
    {
        Level.Background.Color = Color.Black;

        double dy = Screen.Height / NY; // Lasketaan ruudun korkeus pikseleinä
        int nx = (int)(Screen.Width / dy);  // ja montako mahtuu X-suuntaan
        int ny = NY;

        sukupolvi = new int[ny, nx];     //  Luodaan taulukot
        seuraavaSukupolvi = new int[ny, nx];
        oliot = new GameObject[ny, nx];
        // seuraavaSukupolvi = sukupolvi; // jos tämä on mukana, käyttäytyy eri tavalla

        LuoOliot(this,oliot);

        Camera.ZoomToAllObjects();

        timer.Interval = 0.1; // timeri antamaan tapahtuma 0.1 sek välein
        timer.Timeout += LaskeJaPiirraSeuraavaSukupolvi;
        ArvoSukupolvi();  // jos halutaan käynnistää automaattisesti
    }

    private void ArvoSukupolvi()
    {
        Sopulit.Arvo(sukupolvi, 0, 1);
        timer.Start();
    }

    private static void LuoOliot(PhysicsGame game, GameObject[,] oliot)
    {
      /// Täydennä niin, että luodaan yhtä monta suorakaidetta kuin
      /// on taulukoissa alkioita ja kukin luotu suorakaide tallennetaan
      /// oliot taulukkoon, jotta sen väriä päästään muuttamaan jatkossa.
      /// Koordinaatison yksikkönä kannattaa käyttää 1 ruutu = 1 yksikkö,
      /// ja origo on vasemmalla alhaalla.  Kameran zoomaus hoitaa
      /// kuvan kuntoon sitten.   
    }

    private void LaskeJaPiirraSeuraavaSukupolvi()
    {
      /// Täydennä niin, että lasketaan seuraava sukupolvi 
      /// (ks. demo5:n SeuraavaSukupolvi, kutsu sitä)
      /// ja sitten sukupolven taulukosta otetaan värit oliot-taulukon
      /// olioille siten että 0 => musta ja 1 => valkoinen
    }
}

G1. Parannettu GameOfLife

Täydennä GameOfLife (ks. B3) siten, että voit Delete napista tyhjentää kentän ja sitten hiirellä klikkailla päälle ja pois ruutuja. Hiiren klikkaus pysäyttää aina animaation ja sitten voi rauhassa rakentaa haluamansa kuvion (ks: http://www.bitstorm.org/gameoflife/ ja Wikipedia) ja sitten laittaa Enter-nappulalla animoinnin uudelleen käyntiin. Välilyönti arpoo kokonaan uuden alkutilanteen.

G2. Toiston poisto

StringFormat.cs -esimerkissä on paljon Copy-Paste -koodia. Muotoiluesimerkin muuttaminen vaatisi paljon muutoksia koodiin. Samoin esimerkkinumeroiden. Tee ohjelma, jossa on yhdessä taulukossa muotoiluesimerkit ja toisessa käytetyt numerot ja sitten itse ohjelman (mahdollisten aliohjelmien kanssa) toteutus perustuu vain näiden kahden taulukon käyttöön. Nyt muotoiluesimerkin muuttaminen on vain yksi muutos yhdessä paikassa. Samoin kuin yhden esimerkkinumeron muuttaminen tai jopa lisääminen.

PP

PP tehtävät (Pahasti Pihalla) on tarkoitettu niille, joilla on vaikeuksia aivan perusasioissa. Tehtävät on tarkoitus tehdä PP ohjauksissa, ei itsenäisesti tehtäviksi, sillä ne saattavat vaatia ohjaajan tehtävälle tekemää pohjustusta. Ja tehtävät voivat pohjautua edellisiin PP tehtäviin.

Tarkoitus on että nämä ovat helpompia ja kertaavia tehtäviä, joiden avulla pakollisen viikottaisen 2 pisteen saaminen on mahdollista. PP tehtävät eivät ole tarkoitettu niille, jotka ovat tehneet säännöllisesti 4 tai enemmän tehtäviä/kerta. Arvioi tehtävät PP1 ja PP2 asteikolla 0..1, eli tekemällä kaikki PP-tehtävät voit saada enintään 2 pistettä.

PP-tehtäviä voivat palauttaa vain ne, ketkä osallistuvat erillisiin PP-ohjaustuokioihin. Ilmoittaudu niihin Korpissa. Jos et ole niihin osallistunut, niin voit skipata tehtävät PP1 ja PP2.

PP1

Tee pääohjelma, joka kysyy käyttäjältä 5 kokonaislukua. Kun kokonaisluvut on kysytty, laskee ohjelma niiden keskiarvon.

Tämän jälkeen ohjelma kysyy vielä yhden kokonaisluvun ja kertoo, onko se pienempi vai suurempi kuin aikaisemman 5 kysytyn luvun keskiarvo.

Kun teet ohjelmaa, älä käytä toistoa tyyliin

    int luku1 = Int32.Parse(Console.ReadLine());
    int luku2 = Int32.Parse(Console.ReadLine());
    int luku3 = Int32.Parse(Console.ReadLine());
    ...

vaan käytä silmukkaa. Esim. M: 16.4 for-silmukka

PP2

Tee ohjelma, jossa lisäät kahdessa eri silmukassa lukuja ja tekstiä merkkijonotaulukkoon. Ensimmäisessä silmukassa lisää taulukon parillisiin indekseihin niitä vastaavat luvut ja teksti "parillinen luku" siten, että taulukko on seuraavanlainen:

taulukko[0] = "0 parillinen luku"
taulukko[1] = 
taulukko[2] = "2 parillinen luku"
taulukko[3] = 
taulukko[4] = "4 parillinen luku"
taulukko[5] = 
taulukko[6] = "6 parillinen luku"
      .
      .
      .

Vastaavasti tee myös toinen silmukka, joka tekee saman kuin ensiksi mainittu silmukka mutta parittomille luvuille. Käytä tehtävässä for ja while -silmukoita. Taulukon koon saat päättä itse. Valmiin ohjelman on tuotettava seuraavanlainen taulukko:

taulukko[0] = "0 parillinen luku"
taulukko[1] = "1 pariton luku"
taulukko[2] = "2 parillinen luku"
taulukko[3] = "3 pariton luku"
taulukko[4] = "4 parillinen luku"
taulukko[5] = "5 pariton luku"
taulukko[6] = "6 parillinen luku"
      .
      .
      .

Wiki: Taulukot