Ohjelmointi 1, tentti 16.5.2014. Tentaattori Antti-Jussi Lakanen.
Arviointiraportti
Yleistä
Tentti (http://users.jyu.fi/~anlakane/ohjelmointi1/tentit/2014-05-16-tentti2.pdf) oli vaikeudeltaan keskitasoa. Demopisteet lasketaan vielä tuohon päälle arvosanaa laskettaessa. Tehtäväkohtaiset pistekeskiarvot löytyvät alta kunkin tehtävän kohdalta.
Omasta tehtäväpaperista saa kopion saa Antti-Jussilta, huone C414.2. Jos en ole paikalla, laita sähköpostia tai soita 0500 603111. Papereihin on merkitty virheet, jotka voin käydä kanssasi läpi, tarvittaessa tarkastajan kanssa.
Ensimmäinen uusinta on 16.5.2014, ja toinen uusinta 13.6.2014.
Tehtävä | Teki | Keskiarvo | Tarkastaja |
---|---|---|---|
T1 | X | X | Antti-Jussi Lakanen |
T2 | X | X | Antti-Jussi Lakanen |
T3 | X | X | Antti-Jussi Lakanen |
T4 | X | X | Antti-Jussi Lakanen |
T5 | X | X | Antti-Jussi Lakanen |
Yht | X |
Tehtävä 1
- Teki: x opiskelijaa
- Keskiarvo: x.x pistettä
- Palautteet: mittaa x.x, vaikea x.x, arvio x.x, aika x min
- Tarkastaja: Antti-Jussi Lakanen
Malliratkaisu
// Tehdään kokonaislukutaulukko, jossa viisi alkiota: // 5, 11, -4, 0, 1 // Huomaa, että viimeinen luku on 1 koska 5/3 on int-lukuna 1. int[] luvut = { 5, 10 + 1, -4, 0, 5 / 3 }; // Tehdään totuusarvoja sisältävä lista, johon laitetaan // "valmiiksi" kaksi alkiota: true ja false List<bool> totuudet = new List<bool>() { true, false }; // Lisätään totuudet-listaan true, koska // luvut[0] on 5 // luvut[1] on 11 ja 11/2 on 5, joten 5 == 5 totuudet.Add(luvut[0] == (luvut[1] / 2)); // Lisätään totuudet-listaan false, koska // totuudet.Count on 3 ja luvut.Length on 5, ja // niinpä 3 == 5 palauttaa false totuudet.Add(totuudet.Count == luvut.Length); // Järjestetään luvut-taulukko. // Taulukko nyt {-4, 0, 1, 5, 11} Array.Sort(luvut); // Lisätään totuudet-listaan true, koska // luvut[2] on 1 ja luvut[0] + luvut[3] on 1 // niinpä 1 != 1 palauttaa false totuudet.Add(luvut[2] != (luvut[0] + luvut[3])); // Tulostetaan True, False, True, False, False // Huomaa, että totuusarvoja tulostettaessa eka kirjain tulee isolla // Pisteiden kannalta ei väliä kirjoittiko tulostuksen pienillä vai // isoilla kirjaimilla. foreach (bool arvo in totuudet) { Console.WriteLine(arvo); }
Yleiset huomiot
Tehtävä meni pääsääntöisesti aika hyvin. Vähän laiskasti tai epämääräisesti
oli kommentoitu rivejä, tai ei oltu ihan uskallettu kertoa, että mitä arvoja
bool
-listaan todella ollaan lisäämässä. Mitenkään valtavan ankara en
kuitenkaan ollut, jos vaikutelma kokonaisuudesta oli se, että ymmärrettiin
mitä oltiin tekemässä.
Pisteytys ja virheet
- Muiden pääohjelman rivien kommentoinnista enintään 4 pistettä yhteensä, mutta tulostuksesta ja sen oikeellisuudesta 2 pistettä.
- Piti siis tietää että mitä arvoja
bool
-listaan menee, muuten ei täysiä pisteitä tullut.
Lisätään
true
taifalse
, vertailemallatotuudet
-listan alkioiden määrääluvut
-taulukon alkioiden määrään.
- Yllä esimerkki kommentista, joka on totta, mutta jossa olisi pitänyt vielä mainita, että kumpi arvo listaan todella lisätään.
Tehtävä 2
- Teki: x opiskelijaa
- Keskiarvo: x.x pistettä
- Palautteet: mittaa x.x, vaikea x.x, arvio x.x, aika x min
- Tarkastaja: Antti-Jussi Lakanen
Malliratkaisu
/// @author anlakane /// @version 16.5.2014 /// <summary> /// Lasketaan palavien hehkulamppujen määrä, ja tulostetaan /// palavat lamput kun mennään sata kierrosta. /// </summary> public class T2 { /// <summary> /// Kaksinkertainen silmukka, jolla /// saadaan aikaan sata kierrosta. /// </summary> public static void Main() { bool[] lamput = new bool[101]; for (int i = 1; i < lamput.Length; i++) { for (int j = i; j < lamput.Length; j++) { if (j % i == 0) lamput[j] = !lamput[j]; } } int summa = 0; StringBuilder lamputPaalla = new StringBuilder("Sytytettyinä ovat lamput nro: "); String eteen = ""; for (int i = 0; i < lamput.Length; i++) { if (lamput[i]) { summa++; lamputPaalla.Append(eteen + i); eteen = ", "; } } lamputPaalla.Append("."); Console.WriteLine("Sytytettyjä lamppuja yht.: " + summa + " kpl."); Console.WriteLine(lamputPaalla); } }
Yleiset huomiot
Tehtävä osoittautui vaikeaksi, ja tehtävänanto melko monine vaiheineen hieman hankalaksi ymmärtää.
Pisteytys ja virheet
- Olin melko armollinen, vaikka kokonaisuus ei toiminutkaan. Hyvästä yrityksestä sai pisteitä.
- Jos oli kuitenkin tehty ihan väärää asiaa, niin siitä ei annettu pisteitä. Tällaisia olivat esimerkiksi seuraavat: silmukassa mentiin läpi väärää asiaa, lamppuja sytytettiin "miten sattuu", päällä olevien lamppujen kokonaismäärä laskettu täysin epäloogisesti, jne.
Tehtävä 3
- Teki: x opiskelijaa
- Keskiarvo: x.x pistettä
- Palautteet: mittaa x.x, vaikea x.x, arvio x.x, aika x min
- Tarkastaja: Antti-Jussi Lakanen
Malliratkaisu
- Kohta 1.
int
on kokonaislukutyyppi, jabool
totuusarvoinen tyyppi. Esimerkiksiint munIka = 31;
, taibool peliKaynnissa = false;
. - Kohta 2. Muuttujat nimetään C#:ssa nk. camelCasing-säännön mukaan, siis
ensimmäinen kirjain pienellä ja seuraavien sanojen ekat isolla. Ks.
esimerkkejä kohdassa 1. Vakiot nimetään suuraakkosin, ja sanojen väliin
tulee alaviiva, esimerkiksi
int PALLOJA_ALUKSI = 10;
. - Kohta 3. Esimerkki funktiosta ja sen käytöstä.
public static int Summa(int[] luvut) { int summa = 0; foreach(int luku in luvut) { summa += luku; } return summa; }
Ja tätä voi kutsua (esimerkiksi pääohjelmasta käsin)
int[] lukuja = {4, 5, 6, 1, 0}; int munSumma = Summa(lukuja);
- Kohta 4. Vertailuoperaattori palauttaa
true
taifalse
. Esimerkkejä:==
on yhtäsuuruusoperaattori, jolla voi vertailla esimerkiksi kokonaislukujen tai totuusarvojen yhtäsuuruutta. Vastaavasti!=
on erisuuruusoperaattori, esimerkiksi1 != 1
palauttaafalse
, sillä 1 ei ole erisuuri kuin 1. Edelleen,<
on "pienempi kuin" -operaattori, esimerkiksi5 < 4
, palauttaafalse
. - Kohta 5. Rekursiivisella aliohjelmalla tarkoitetaan sellaista aliohjelmaa, joka tarvitsee itseään ratkaistaakseen ongelman. Rekursiivinen aliohjelma siis kutsuu itse itseään.
- Kohta 6.
19.125_10
-->10011.001_2
19 = 2 * 9, jj 1 | 0.125 * 2 = 0.25 9 = 2 * 4, jj 1 | 0.25 * 2 = 0.5 4 = 2 * 2, jj 0 | 0.5 * 2 = 1 2 = 2 * 1, jj 0 | 1 = 2 * 0, jj 1 | Kokonaisosa 10011 | Desimaaliosa 100 (luetaan alh->ylos)| (luetaan ylh->alas) Siis koko luku 10011.001
Yleiset huomiot
- Meni pääsääntöisesti tosi hyvin. Ei isompia ongelmia.
Pisteytys ja virheet
- Kohta 1: Piti olla esimerkit tietotyypeistä (esimerkiksi
int
,bool
,char
,double
, jne.) sekä niiden käytöstä (esimint luku = 0;
,char kirjain = 'a'
, tms.) Jos ei ollut esimerkkiä niin puoli pistettä pois. - Kohta 3: Funktio palauttaa arvon, joten paluuarvon tyyppinä ei voi olla
void
vaan jotain muuta. Tätä eivät kaikki muistaneet. - Kohta 3: Jos funktion palauttamaa arvoa ei kutsun yhteydessä sijoitettu mihinkään, niin siitä pikku vähennys -0.25 p.
- Kohta 6: Jos laskutoimituksissa tai tulkinnassa virheitä niin melko armottomasti vähennyksiä tästä.
Tehtävä 4
- Teki: x opiskelijaa
- Keskiarvo: x.x pistettä
- Palautteet: mittaa x.x, vaikea x.x, arvio x.x, aika x min
- Tarkastaja: Antti-Jussi Lakanen
Malliratkaisu
Tulosmatriisi näyttää tältä
1 1 1 1 1 1 1 2 3 4 5 6 1 3 6 10 15 21 1 4 10 20 35 56 1 5 15 35 70 126 1 6 21 105 126 252
Joten reittejä oikeaan alakulmaan on 252 kappaletta, ja jokaiseen soluun
vievien reittien määrä saadaan laskettua summaamalla rivi-1
ja sarake-1
,
missä rivi
ja sarake
merkkaavat sitä paikkaa (indeksiä) missä ollaan
menossa, kun rivi
ja sarake > 0
. Miksi näin? Siksi, että ainoat
mahdollisuudet tulla kuhunkin soluun on yläkautta (rivi-1
) tai vasemmalta
(sarake-1
), joten nämä summaamalla saadaan kaikkien mahdollisten reittien
lukumäärä.
Alla olevassa koodissa on pituuden säästämiseksi jätetty kirjoittamatta
Tayta
-funktio sekä luokka, ja Main
-pääohjelman dokumentaatio. Koko ohjelma
dokumentaatioineen löytyy täältä:
http://users.jyu.fi/~anlakane/ohjelmointi1/tentit/2014-05-16/T4.cs
public static void Main() { int[,] matriisi = Tayta(6, 6, 1); for (int i = 1; i < matriisi.GetLength(0); i++) { for (int j = 1; j < matriisi.GetLength(1); j++) { matriisi[i, j] = LaskeReittienLukumaara(matriisi, i, j); } } Console.WriteLine(matriisi[5, 5]); } /// <summary> /// Funktio palauttaa matriisin tietyn paikan /// (rivi, sarake) reittien lukumäärän, kun solusta toiseen /// "liikkuminen" voi tapahtua ainoastaan oikealle ja alaspäin. /// Esimerkiksi, soluun (1, 1) voi tulla kahta eri reittiä; /// ensin oikealle ja alas, tai sitten ensin alas ja vasta /// sitten oikealle. /// </summary> /// <param name="matriisi">Matriisi</param> /// <param name="rivi">Rivi</param> /// <param name="sarake">Sarake</param> public static int LaskeReittienLukumaara(int[,] matriisi, int rivi, int sarake) { if (rivi == 0) { return matriisi[rivi, sarake-1]; } if (sarake == 0) { return matriisi[rivi-1 , sarake]; } return matriisi[rivi - 1, sarake] + matriisi[rivi, sarake - 1]; }
Yleiset huomiot
Tässä tehtävässä kävi vähän niin, että joko saatiin selkeästi kiinni, mistä on kysymys, tai sitten ei lainkaan ymmärretty. Tämä teki pisteytyksestä vähän "binääristä", eli joko aika lailla 6 p. tai 0 p. Vaikeuksia oli joillakin saada kiinni siitä, mitä ollaan tekemässä (algoritminen ajattelu). Kuten edellisessä kohdassa sanottiin, oleellista oli huomata, että solun reittien määrä saadaan summaamalla yläsolu + vasen solu. Ohjelmoinnin kannalta tehtävä oli aika helppo, tästä lisää alla.
Varsinainen kirjoitettava osa tässä tehtävässä oli Main
-pääohjelman kaksi
sisäkkäistä silmukkaa, jonka sisään tuli LaskeReittienLukumaara
-funktiokutsu
ja arvojen sijoitus sopivasti matriisi
-muuttujaan.
LaskeReittienLukumaara
-funktio itsessään oli hyvin lyhyt ja simppeli, joten
sinänsä tehtävä oli ohjelmointimielessä helppo.
Pääohjelman sisäkkäiset silmukat voidaan aloittaa riviltä 1 ja sarakkeesta 1, koska ekalle vaaka- ja pystyriville voidaan todellakin tulla vain yhtä reittiä pitkin, joten niiden reittien lukumäärää ei tarvitse "uudestaan" laskea pääohjelmassa.
Pisteytys ja virheet
- Kuten sanottu, pisteytys meni aika lailla 0 p. tai 6 p. Epäoleellisista pikkuvirheistä ei sakotettu. Dokumentaatiot puuttuivat joltakin, siitä -1 p.
Tehtävä 5
- Teki: x opiskelijaa
- Keskiarvo: x.x pistettä
- Palautteet: mittaa x.x, vaikea x.x, arvio x.x, aika x min
- Tarkastaja: Antti-Jussi Lakanen
Malliratkaisu
using System; using System.Text; using System.Linq; using System.Collections.Generic; /// @author anlakane /// @version 16.5.2014 /// <summary> /// Lotto-ohjelma, joka arpoo ja tulostaa 7 /// varsinaista numeroa ja 3 lisänumeroa väliltä 1-39. /// </summary> public class T5 { /// <summary> /// Arvotaan ja tulostetaan numerot. /// </summary> public static void Main() { int[] pallot = new int[39]; // Taulukon paikkaan nro i tulee aina luku i+1 // eli paikkaan 0 arvo 1, paikkaan 1 arvo 2, ..., // paikkaan 38 (viimeinen paikka) luku 39. for (int i = 0; i < pallot.Length; i++) { pallot[i] = i + 1; } Sekoita(pallot); Console.WriteLine("Varsinaiset numerot:"); for (int i = 0; i < 7; i++) { Console.WriteLine(pallot[i]); } Console.WriteLine("Lisänumerot:"); for (int i = 7; i < 10; i++) { Console.WriteLine(pallot[i]); } } /// <summary> /// Aliohjelma sekoittaa annetun kokonaislukutaulukon /// alkiot keskenään Fisher-Yates-algoritmilla /// </summary> /// <param name="luvut">Sekoitettava taulukko.</param> public static void Sekoita(int[] luvut) { Random r = new Random(); for (int i = luvut.Length - 1; i > 0; i--) { int j = r.Next(i); int apu = luvut[j]; luvut[j] = luvut[i]; luvut[i] = apu; } } }
Yleiset huomiot
Hieman yllättäen taulukon (tai listan), jossa on lukuja peräkkäin, tekeminen
oli yllättävän haastavaa. Näkyi esimerkiksi ehdotus int[] luvut = new int[1,
..., 39]
, joka on valitettavasti väärin. Pitää muistaa, että hakasulkujen
sisään tulee taulukon koko, eikä alkioiden arvoja. Sivujuonteena mainitsen
vain, että olisi hirveän kiva jos muoto int[] luvut = {1..30}
(huomaa
aaltosulut) toimisi C#:ssa, tähän tyyliin perättäisten lukujen jono tehdään
monissa kielissä, esimerkiksi Haskellissa.
Vielä kerran: Jos pitää toistaa useita kertoja jotakin juttua (esimerkiksi laittaa monta lukua tai arvoa taulukkoon), niin silloin tarvitaan toistorakennetta eli silmukoita. Ks. alla.
int luvut = new int[39]; // Tehdään taulukko, jonka pituus 39 for(int i = 0; i < luvut.Length; i++) { // Laitetaan kuhunkin taulukon alkioon arvo i + 1 // (tarkempi selitys malliratkaisussa) luvut[i] = i + 1; }
Jos ei päästy kiinni siihen, miten luvut saadaan taulukkoon, niin herkästi ne jäi sitten myös sekoittamatta (ja tulostamatta). Eli tässäkin tehtävässä tuppasi olemaan hivenen kaksihuippuinen arvostelujakauma.
Pisteytys ja virheet
- Ei oltu laitettu lukuja 1-39 taulukkoon lainkaan tai oli laitettu väärin, -1 p.
- Muut virheet tapauskohtaisest.