@ -0,0 +1,23 @@ | |||
## 1 Moi maailma | |||
**Tehtävä:** | |||
Kurssin ensimmäinen tehtävä on alan klassikko, eli "Moi maailma" Ruby-ohjelmointikielellä toteutettuna. Tee siis ohjelma, joka tulostaa kaksi riviä tekstiä; ensimmäiselle riville tulee siis tulla teksti "Moi maailma!", ja toiselle "Tästä se sitten lähtee!". | |||
Toimiessaan oikein ohjelma tulostaa siis seuraavaa: | |||
Example output: | |||
``` | |||
Moi maailma! | |||
Tästä se sitten lähtee! | |||
``` | |||
**Vastaus:** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
puts "Moi maailma!\nTästä se sitten lähtee!" | |||
``` |
@ -0,0 +1,30 @@ | |||
## 2 Muuttujat ja tulostus | |||
**Tehtävä:** | |||
Luvun toisessa tehtävässä kokeillaan muuttujien tekemistä ja käyttämistä. Määrittele kaksi muuttujaa, joista ensimmäiselle annetaan arvoksi merkkijono "Tekstiä!" ja toiselle kokonaisluku 100. Tämän jälkeen määrittele kolmas muuttuja käyttäen apunasi muuttujaa, johon määriteltiin kokonaisluku 100. Kerro muuttujan arvo kahdella, ja jaa tämä tulos kymmenellä. | |||
Laita tämän jälkeen muuttujan arvo osaksi tulostettavaa tekstiä seuraavasti: "Muuttujia voi laittaa tulosteisiin: [muuttujan arvo]", sekä laskun lopputulos muodossa: "Niillä voi myös laskeä: [vastaus]" | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Muuttujia voi laittaa tulosteisiin: Tekstiä! | |||
Niillä voi myös laskea: 20 | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
teksti = "Tekstiä!" | |||
luku = 100 | |||
luku = luku * 2 / 10 | |||
puts "Muuttujia voi laittaa tulosteisiin: " + teksti | |||
puts "Niillä voi myös laskea: " + luku.to_s | |||
``` |
@ -0,0 +1,37 @@ | |||
## 3 Binaarilukukone | |||
**Tehtävä:** | |||
Luvun kolmas tehtävä esittelee syötteen pyytämisen käyttäjältä ja testaa tyyppimuunnosfunktioita käytännössä. Tee siis ohjelma, joka pyytää käyttäjältä luvun kysymyksellä "Anna joku luku:". Tämän jälkeen ohjelma ilmoittaa käyttäjälle annetun luvun binaarilukuna muodossa "Antamasti luku on binaariarvoina [tulos]" sekä heksalukuna muodossa "ja heksoina [tulos]". Helpoiten tehtävää kannattaa lähestyä to_s(2) ja to_s(16)-metodeja apuna käyttäen. | |||
Tehtävässä voidaan lisäksi olettaa, että käyttäjä ei anna virheellisiä syötteitä, joten siihen ei tarvitse varautua. Lisäksi kannattaa muistaa, että käyttäjältä vastaanotetun syötteen loppuun tallentuu aina rivinvaihtomerkki, josta pääsee eroon parhaiten chop! tai chomp!-metodeilla. | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Anna joku luku: | |||
2343 | |||
Antamasi luku on binaariarvoina 100100100111 | |||
ja heksoina 927 | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
begin | |||
puts "Anna joku luku:" | |||
#luku = gets.to_i | |||
luku = Integer(gets.strip.chomp) | |||
rescue ArgumentError | |||
warn "Ei ole kokonaisluku" | |||
retry | |||
end | |||
puts "Antamasi luku on binaariarvoina " + luku.to_s(2) + \ | |||
"\nja heksoina " + luku.to_s(16) | |||
``` |
@ -0,0 +1,33 @@ | |||
## 4 Pyöristäjä | |||
**Tehtävä:** | |||
Neljäs harjoitustehtävä käsittelee Rubyn erilaisia tapoja käsittää lukuarvoja sekä pyöristämistoimintoja. Tehtävänä onkin rakentaa ohjelma, jolle voidaan antaa mielivaltaisen mittainen desimaaliluku, jonka ohjelma pyöristää yhden desimaalin tarkkuuteen. | |||
Toteutetaan ohjelma siten, että ohjelma aloittaa pyytämällä desimaalilukua muodossa "Anna jokin desimaaliluku: ". Tämän jälkeen ohjelma laskee pyöristetyn luvun, ja tulostaa "Luku on pyöristettynä [vastaus]". | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Anna jokin desimaaliluku: 8.49334545 | |||
Luku on pyöristettynä 8.5 | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
begin | |||
print "Anna jokin desimaaliluku: " | |||
#luku = gets.to_f | |||
luku = Float(gets.strip.chomp) | |||
rescue ArgumentError | |||
warn "Ei ole desimaaliluku" | |||
retry | |||
end | |||
printf("Luku on pyöristettynä %s", luku.round(1).to_s) | |||
``` |
@ -0,0 +1,26 @@ | |||
## 5 Satunnaisluvun arpominen | |||
**Tehtävä:** | |||
Luvun viimeinen tehtävä koskee satunnaislukugeneraattorin käyttämistä. Tee ohjelma, joka heittää 20-sivuista noppaa, eli käytännössä arpoo satunnaisluvun väliltä 1-20. Nopanheiton tulos ilmoitetaan käyttäjälle muodossa "Noppa heitti tuloksen [tulos]". | |||
Tehtävässä kannattaa muistaa, että satunnaislukugeneraattori arpoo luvun siten, että annettu yläraja ei kuulu tulokseen, mutta 0 kuuluu, eli vaikkapa rand(3) voi antaa vastauksen 0, 1 tai 2, muttei koskaan 3. | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Noppa heitti tuloksen 9 | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
luku = rand(20) + 1 | |||
printf("Noppa heitti tuloksen %s\n", luku) | |||
``` |
@ -0,0 +1,26 @@ | |||
## 1 Merkkijonon yhdistäminen | |||
**Tehtävä:** | |||
Luvun ensimmäinen harjoitustehtävä harjoittelee merkkijonojen yhdistämistä. Määritellään kaksi muuttujaa, joista ensimmäinen saa arvoksi merkkijonon "Balin palapeli" ja toinen merkkijonon "tehdas!\n". Apunakäyttäen merkkijonoilla työskentelyyn tarkoitettuja metodeja, yhdistä nämä kaksi merkkijona kolmanteen muuttujaan, ja tulosta lopputulos. | |||
Toimiessaan oikein ohjelma tulostaa siis seuraavaa: | |||
Example output: | |||
``` | |||
Balin palapelitehdas! | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
muuttuja1 = "Balin palapeli" | |||
muuttuja2 = "tehdas!\n" | |||
muuttuja3 = [muuttuja1, muuttuja2] | |||
puts muuttuja3.join() | |||
``` |
@ -0,0 +1,23 @@ | |||
## 2 Merkkijonon muokkausmetodit | |||
**Tehtävä:** | |||
Luvun toisessa harjoitustehtävässä jatketaan merkkijonoilla työskentelyä. Määritellään muuttuja, jolle annetaan arvoksi merkkijono "Balin palapelitehdas!!". Hyödyntäen merkkijonoille käytettävissä olevia metodeja, tee seuraavat muutokset; Ensinnäkin, poista merkkijonosta kaksi viimeistä merkkiä. Toisekseen, korvaa kaikki "li"-kohdat merkkijonosta "ke"-merkkijonolla. | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Baken palapeketehdas | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
muuttuja = "Balin palapelitehdas!!".gsub("li", "ke")[0...-2] | |||
print muuttuja | |||
``` |
@ -0,0 +1,40 @@ | |||
## 3 Leikkaukset | |||
**Tehtävä:** | |||
Kolmas tehtävä käsittelee merkkijonojen leikkauksia. Tee ohjelma, joka ensin pyytää käyttäjältä syötettä muodossa "Kirjoita jotain: ". Tämän jälkeen poista syötteen loppuun tuleva rivinvaihto. | |||
Seuraavaksi ohjelma tulostaa kolme leikkausta. Ensimmäiseksi tulostetaan ensimmäisen kolme merkkiä muodossa "Ensimmäiset kolme kirjainta: [leikkaus]", tämän jälkeen viimeiset kaksi merkkiä muodossa "Viimeiset kaksi merkkiä: [leikkaus]" ja lopuksi kaikki merkit kolmannesta eteenpäin muodossa "Kolmannesta merkistä eteenpäin: [leikkaus]" | |||
Tehtävässä voidaan olettaa, että käyttäjä ymmärtää antaa riittävän pitkän merkkijonon syötteenä, joten tähän ei tarvitse erikseen varautua eikä sitä tarvitse erikseen tarkastaa. | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Kirjoita jotain: | |||
Apina? | |||
Ensimmäiset kolme merkkiä: Api | |||
Viimeiset kaksi merkkiä: a? | |||
Kolmannesta merkistä eteenpäin: ina? | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
puts "Kirjoita jotain: " | |||
lause = String(gets.chomp) | |||
#lause = "Testimerkkijono" | |||
printf( | |||
"Ensimmäiset kolme merkkiä: %s\n\ | |||
Viimeiset kaksi merkkiä: %s\n\ | |||
Kolmannesta merkistä eteenpäin: %s\n", | |||
lause[0...3], | |||
lause[-2, 2], | |||
lause[2..-1] | |||
) | |||
``` |
@ -0,0 +1,39 @@ | |||
## 4 Taulukon määrittely ja muokkaaminen | |||
**Tehtävä:** | |||
Ensimmäinen taulukkoja koskeva tehtävä käsittelee taulukosta tehdyn listan luomista ja muokkaamista. | |||
Määrittele ohjelmaasi lista, jossa on alkioina merkkijonot "banaani", "turtana", "ananas", "kaneli" ja "unikko". Tämän jälkeen materiaalin ohjeita apunakäyttäen tee seuraavat toimenpiteet: | |||
(1) Lisää listalle alkio, jolle annetaan arvoksi "karhea", (2) poista listalta se alkio, jonka arvo on kaneli ja (3) laita taulukon alkiot aakkosjärjestykseen. Lopuksi vielä tulosta taulukko komennolla "puts [taulukonnimi]". | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
ananas | |||
banaani | |||
karhea | |||
turtana | |||
unikko | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
lista = ["banaani", "turtana", "ananas", "kaneli", "unikko"] | |||
lista.push("karhea") | |||
# Tai vaihtoehtoisesti | |||
# lista.insert(-1, "karhea") | |||
lista.delete("kaneli") | |||
lista = lista.sort | |||
puts lista | |||
``` |
@ -0,0 +1,35 @@ | |||
## 5 Taulukko ja merkkijono | |||
**Tehtävä:** | |||
Luvun viimeisessä tehtävässä harjoitellaan lisää merkkijonoilla ja taulukoilla työskentelyä. | |||
Tee ohjelma, joka ensin pyytää käyttäjältä tekstisyötteen muodossa "Kirjoita jotain: ". Tämän jälkeen, merkkijonojen ja taulukoiden metodeja apunakäyttäen tee merkkijonosta taulukko katkaisemalla taulukko aina välilyöntimerkin (" ") kohdalta. Tämän jälkeen poista taulukosta kaikki ne alkiot, jotka ovat kopioita muista alkioista, ja järjestä nämä sanat aakkosjärjestykseen. Lopuksi tulosta lista sanoista muodossa "Tässä sanat aakkosjärjestyksessä: [lista]". Taulukon tulostukseen voit käyttää yksinkertaista puts [taulukonnimi] -komentoa. Ohjelmassa voidaan olettaa, että kaikki sanat kirjoitetaan pelkästään pienillä alkukirjaimilla. | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Kirjoita jotain: tapettiin kärpänen tapettiin | |||
Tässä sanat aakkosjärjestyksessä: | |||
kärpänen | |||
tapettiin | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
print "Kirjoita jotain: " | |||
#lause = String(gets.chomp) | |||
lause = "tapettiin kärpänen tapettiin" | |||
lista = lause.split(" ").sort.uniq | |||
puts "Tässä sanat aakkosjärjestyksessä:" | |||
lista.each { |indeksiarvo| puts indeksiarvo } | |||
# Tai vain yksinkertaisesti: puts lista | |||
``` |
@ -0,0 +1,77 @@ | |||
## 1 Yksinkertainen valinta, laskin | |||
**Tehtävä:** | |||
Ensimmäisessä tehtävässä kootaan laskin, jolla on kolme mahdollista toimintatapaa. Aloitetaan ohjelma sillä, että pyydetänä käyttäjältä kaksi syötettä tekstillä "Anna 1. luku:" ja "Anna 2. luku:" , jotka tallennetaan kahteen eri muuttujaan, ja muutetaan ne liukuluvuiksi tyyppimuunnoksella. Tämän jälkeen esitetään käyttäjälle vaihtoehdot muodossa "(Y)hteen-, (V)ähennys- vai (K)ertolasku?" ja tallennetaan käyttäjän valinta kolmanteen muuttujaan. | |||
Jos käyttäjä antoi syötteen "Y", lasketaan syötetyt arvot yhteen. Jos "V", vähennetään ne toisistaan ja jos "K", kerrotaan ne keskenään. Lopuksi annetaan vastaus "Tulos on [vastaus]". Jos käyttäjä ei valitse joko "Y", "V" tai "K", tulostetaan teksti "Virheellinen valinta." Ohjelma lopetetaan kun vastaus on tulostettu, ja lisksi voidaan olettaa, että käyttäjä ymmärtää antaa numeroarvoksi muuntuvan syötteen lukuihin, sekä ymmärtää, että laskutoimituksen valinta tehdään käyttäen isoja kirjaimia. | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Anna 1. luku: | |||
2 | |||
Anna 2. luku: | |||
3 | |||
(Y)hteen-, (V)ähennys- vai (K)ertolasku? | |||
K | |||
Tulos on 6.0 | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
def tarkistaSyote(kysymys, virheviesti, tyyppi, strip=false) | |||
begin | |||
print kysymys | |||
if strip | |||
syote = eval(tyyppi + "(gets.chomp).strip") | |||
else | |||
syote = eval(tyyppi + "(gets.chomp)") | |||
end | |||
rescue ArgumentError | |||
warn virheviesti | |||
retry | |||
end | |||
return syote | |||
end | |||
def pyydaLuku(luku) | |||
return tarkistaSyote("Anna #{luku}. luku: \n", | |||
"Et antanut kelvollista valintaa.", | |||
"Integer" | |||
) | |||
end | |||
def laskuToimitus(luku1, luku2) | |||
input = tarkistaSyote("(Y)hteen-, (V)ähennys- vai (K)ertolasku?\n", | |||
"Et antanut kelvollista valintaa.", | |||
"String" | |||
) | |||
luku1 = luku1.to_f | |||
luku2 = luku2.to_f | |||
case input.upcase | |||
when "Y", "YHTEEN" | |||
t = luku1 + luku2 | |||
when "V", "VÄHENNYS" | |||
t = luku1 - luku2 | |||
when "K", "KERTOLASKU" | |||
t = luku1 * luku2 | |||
else | |||
warn "'#{input}' ole sopiva vaihtoehto" | |||
t = "tuntematon" | |||
end | |||
puts "Tulos on #{t}" | |||
end | |||
laskuToimitus(pyydaLuku(1), pyydaLuku(2)) | |||
``` |
@ -0,0 +1,83 @@ | |||
## 2 Monta valintaehtoa | |||
**Tehtävä:** | |||
Luvun toisessa tehtävässä tehdään ohjelma, joka käsittelee koordinaatistoa. Tee ohjelma, joka pyytää käyttäjältä X-akselin ja Y-akselin arvot kokonaislukuina. Tämän jälkeen tee ohjelmaan valintarakenne, joka päättelee missä kohtaa 10*10-koordinaatistoa käyttäjä on: | |||
Jos X- ja Y-arvo on pienempi kuin 5, tulostetaan "Olet vasemmassa alakulmassa.". Jos X on pienempi, mutta Y suurempi tai yhtäsuuri kuin 5, tulostetaan "Olet vasemmassa yläkulmassa.". Vastaavasti X >=5 ja Y < 5 tulostaa "Olet oikeassa alakulmassa." ja molempien ollessa viisi tai enemmän, "Olet oikeassa yläkulmassa.". Lisäksi, jos jompikumpi luvuista on pienempi kuin nolla, tulostetaan "Annoit negatiivisen arvon.". | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Valitse x-akselin arvo väliltä 0-9: 2 | |||
Valitse y-akselin arvo väliltä 0-9: -6 | |||
Annoit negatiivisen arvon. | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
def tarkistaSyote(kysymys, virheviesti, tyyppi, strip=false, *arvovali) | |||
begin | |||
print kysymys | |||
if strip | |||
syote = eval(tyyppi + "(gets.chomp).strip") | |||
else | |||
syote = eval(tyyppi + "(gets.chomp)") | |||
end | |||
if tyyppi == "Integer" && arvovali[0] | |||
if syote < 0 | |||
# Enforced by assignment description | |||
return syote | |||
elsif syote < arvovali[0][0] || syote > arvovali[0][1] | |||
throw ArgumentError | |||
end | |||
end | |||
rescue ArgumentError | |||
warn virheviesti | |||
retry | |||
end | |||
return syote | |||
end | |||
########## | |||
def valitseKoordinaatti(akseli) | |||
arvovali = [0,9] | |||
return tarkistaSyote("Valitse #{akseli}-akselin arvo väliltä #{arvovali[0]}-#{arvovali[1]}: ", | |||
"Syötteesi oli virheellinen.", | |||
"Integer", | |||
false, | |||
arvovali | |||
) | |||
end | |||
########## | |||
x = valitseKoordinaatti("x") | |||
y = valitseKoordinaatti("y") | |||
if x < 0 or y < 0 | |||
puts "Annoit negatiivisen arvon." | |||
elsif x < 5 and y < 5 | |||
puts "Olet vasemmassa alakulmassa." | |||
elsif x < 5 and y >= 5 | |||
puts "Olet vasemmassa yläkulmassa." | |||
elsif y < 5 and x >= 5 | |||
puts "Olet oikeassa alakulmassa." | |||
elsif y >= 5 and x >= 5 | |||
puts "Olet oikeassa yläkulmassa." | |||
end | |||
``` |
@ -0,0 +1,52 @@ | |||
## 3 Salasanakysely | |||
**Tehtävä:** | |||
Luvun kolmannessa tehtävässä toteutetaan nimeä ja salasanaa pyytävä valintarakenne. Ensin ohjelma pyytää nimeä muodossa "Anna nimi: ". Jos käyttäjä antaa nimen "Erkki", pyydetään lisäksi salasana muodossa "Anna salasana: ". Jos salasana on "haukionkala", tervehditään käyttäjää tulosteella "Hei Erkki!". Jos käyttäjä antaa väärän nimen, tulostetaan "En tunne sinua.", ja jos salasana on väärin, "Et ole Erkki.". | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Anna nimi: | |||
Erkki | |||
Anna salasana: | |||
hahaa! | |||
Et ole Erkki. | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
def tarkistaSyote(kysymys, tyyppi, strip=false) | |||
begin | |||
print kysymys | |||
if strip | |||
syote = eval(tyyppi + "(gets.chomp).strip") | |||
else | |||
syote = eval(tyyppi + "(gets.chomp)") | |||
end | |||
rescue ArgumentError | |||
warn "Syöttämäsi valinta ei ole kelvollinen" | |||
retry | |||
end | |||
return syote | |||
end | |||
nimi = tarkistaSyote("Anna nimi: \n", "String") | |||
case nimi when "Erkki" | |||
salasana = tarkistaSyote("Anna salasana: \n", "String") | |||
case salasana when "haukionkala" | |||
puts "Hei #{nimi}!" | |||
else | |||
puts "Et ole #{nimi}." | |||
end | |||
else | |||
puts "En tunne sinua." | |||
end | |||
``` |
@ -0,0 +1,61 @@ | |||
## 4 Oraakkeli | |||
**Tehtävä:** | |||
Luvun neljännessä tehtävässä harjoitellaan case-valinnan käyttöä, sekä luodaan arkielämää helpottava, erehtymätön, Oraakkeli-ohjelma. Ohjelma käynnistyy antamalla lyhyen selityksen itsestään: "Oraakkeli vastaa kyllä/ei-muodossa". Tämän jälkeen pyydetään käyttäjältä kysymys "Kirjoita kysymyksesi Oraakkelille:". Tämän jälkeen ohjelma arpoo luvun väliltä 0-99 ja vastaa käyttäjälle seuraavassa muodossa: | |||
"Kysymyksesi oli: [esitetty kysymys]", "Tähän Oraakkeli vastasi:" ja mikäli satunnaisluku oli 0-19, "Ei missään nimessä!", 20-44 "Ei varmaankaan", 45-54 "En osaa sanoa.", 55-79 "Luultavasti kyllä." ja 80-99 "Ehdottomasti kyllä". | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Oraakkeli vastaa kyllä/ei-muodossa | |||
Kirjoita kysymyksesi Oraakkelille: | |||
Onko nyt hyvä päivä? | |||
Kysymyksesi oli: Onko nyt hyvä päivä? | |||
Tähän Oraakkeli vastasi: | |||
En osaa sanoa. | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
puts "Oraakkeli vastaa kyllä/ei-muodossa\n\ | |||
Kirjoita kysymyksesi Oraakkelille:" | |||
begin | |||
kysymys = String(gets.chomp) | |||
if not kysymys[-1] == "?" | |||
puts "Ei ole kysymys" | |||
throw ArgumentError | |||
end | |||
rescue ArgumentError | |||
warn "Syötteesi ei ole kelvollinen" | |||
retry | |||
end | |||
puts "Kysymyksesi oli: #{kysymys}" | |||
x = rand(0..99) | |||
case x | |||
when 0..19 | |||
vastaus = "Ei missään nimessä!" | |||
when 20..44 | |||
vastaus = "Ei varmaankaan" | |||
when 45..54 | |||
vastaus = "En osaa sanoa." | |||
when 55..79 | |||
vastaus = "Luultavasti kyllä." | |||
when 80..99 | |||
vastaus = "Ehdottomasti kyllä." | |||
# else-vaihtoehto ei koskaan toteutuisi, mikäli x on aina väliltä 0-99, | |||
# ja edellämainitut tilanteet kattavat koko kyseisen arvovälin | |||
end | |||
print "Tähän Oraakkeli vastasi:\n#{vastaus}" | |||
``` |
@ -0,0 +1,89 @@ | |||
## 5 Torakka-Jalka-Ydinpommi | |||
**Tehtävä:** | |||
Luvun viimeinen tehtävä on luoda klassinen Torakka-Jalka-Ydinpommi-peli tietokoneelle. Pelin säännöt on yksinkertaiset; pelaaja ja tietokone valitsevat joko torakan, jalan tai ydinpommin. Jalka voittaa torakan, ydinpommi voittaa jalan ja torakka voittaa ydinpommin. Kyseessä ei siis ole todellakaan kivi-paperi-sakset-tyylinen peli. | |||
Joka kierroksen alussa pelaaja voi valita jonkin kolmesta vaihtoehdosta syötteellä "1: Torakka 2: Jalka 3: Ydinpommi 4: lopeta", "Valitse (1-4):". Tämän jälkeen tietokone valitsee omansa arpomalla satunnaisen vaihtoehdon. Tämän jälkeen tulostetaan tilanne "Valitsit [valinta], tietokone valitsi [valinta].", sekä lopputulos "Tietokone voitti.", "Voitit!" tai "Valitsitte saman, tasapeli.". Kierroksen lopuksi vielä tulostetaan tilanne muodossa "Peli on pelaaja [pelaajan voittamat kierrokset] : tietokone [tietokoneen voittamat kierrokset]" | |||
Tavallisuudesta poiketen tässä tehtävässä siis tarvitaan seuraavan luvun toistorakenteita ratkaisun toteuttamiseen, joten mikäli tehtävä tuntuu tässä vaiheessa vaikealta, kannattaa tähän tehtävään palata seuraavan luvun päätteeksi. | |||
Toimiessaan oikein erä tietokonetta vastaan voi olla vaikka seuraavanlainen: | |||
Example output: | |||
``` | |||
1: Torakka 2: Jalka 3: Ydinpommi 4: lopeta | |||
Valitse (1-4): | |||
3 | |||
Valitsit ydinpommin, tietokone valitsi torakan. | |||
Tietokone voitti. | |||
Peli on pelaaja 0 : tietokone 1 | |||
1: Torakka 2: Jalka 3: Ydinpommi 4: lopeta | |||
Valitse (1-4): | |||
4 | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
def peli(voitot=0, tasapelit=0, haviot=0) | |||
valintaMap = { | |||
1 => "torakan", | |||
2 => "jalan", | |||
3 => "ydinpommin" | |||
} | |||
loop do | |||
printf("1: Torakka 2: Jalka 3: Ydinpommi 4: lopeta\nValitse (1-4):\n") | |||
begin | |||
valintaUser = Integer(gets.chomp) | |||
if valintaUser < 1 || valintaUser > 4 | |||
throw ArgumentError | |||
end | |||
rescue ArgumentError | |||
warn "Valintasi ei ole kelvollinen kokonaisluku" | |||
retry | |||
end | |||
arpalukuAI = rand(1..3) | |||
if valintaUser == 4 | |||
Process.exit(0) | |||
end | |||
valintaMap.each do |key, value| | |||
if key == valintaUser | |||
if key != arpalukuAI | |||
printf("Valitsit " + value + ", tietokone valitsi " + valintaMap[arpalukuAI] + ".\n") | |||
end | |||
if ((key == 2 and arpalukuAI == 1) or | |||
(key == 3 and arpalukuAI == 2) or | |||
(key == 1 and arpalukuAI == 3)) | |||
voitot += 1 | |||
printf("Voitit!\n") | |||
elsif key == arpalukuAI | |||
tasapelit += 1 | |||
printf("Valitsitte saman, tasapeli.\n") | |||
else | |||
haviot += 1 | |||
printf("Tietokone voitti.\n") | |||
end | |||
break | |||
end | |||
end | |||
printf("Peli on pelaaja " + voitot.to_s + " : " + "tietokone " + haviot.to_s + "\n") | |||
end | |||
end | |||
peli | |||
``` |
@ -0,0 +1,47 @@ | |||
## 1 Potenssien lasku whilella | |||
**Tehtävä:** | |||
Luvun ensimmäisenä tehtävänä tehdään yksinkertainen while-toistoon pohjautuva laskuri, joka laskee käyttäjän antamasta luvusta 10 ensimmäistä potenssia. Eli jos käyttäjä vaikka antaa arvon 3, lasketaan 2. kierroksella laskutoimituksen 3*3 tulos, kolmannella 3*3*3 tulos jne... | |||
Ohjelma alkaa pyytämällä käyttäjältä luvun muodossa "Anna luku: " ja tämän jälkeen tulostaa potenssit muodossa "[kierros]. potenssi on [tulos]". Ohjelma siis tarvitsee erikseen muuttujan jolla seurataan kierrosmäärää, sekä toisen muuttujan johon joka kierroksella lasketaan uusi tulos. Ohjelma lopettaa automaattisesti kun 10. potenssin tulos on laskettu ja tulostettu. | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Anna luku: | |||
3 | |||
1. potenssi on 3 | |||
2. potenssi on 9 | |||
3. potenssi on 27 | |||
4. potenssi on 81 | |||
5. potenssi on 243 | |||
6. potenssi on 729 | |||
7. potenssi on 2187 | |||
8. potenssi on 6561 | |||
9. potenssi on 19683 | |||
10. potenssi on 59049 | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
begin | |||
puts "Anna luku: " | |||
luku = Integer(gets.strip.chomp) | |||
rescue ArgumentError | |||
warn "Ei ole kelvollinen luku. Yritä uudelleen." | |||
retry | |||
end | |||
i = 1 | |||
while i <= 10 | |||
puts "#{i}. potenssi on #{luku**i}" | |||
i += 1 | |||
end | |||
``` |
@ -0,0 +1,75 @@ | |||
## 2 Autonkulutuslaskuri | |||
**Tehtävä:** | |||
Luvun toisessa tehtävässä tehdään laskuri, jolla lasketaan paljonko autolla ajaminen tulee maksamaan bensan hinnassa mitattuna. Pyydetään ensiksi käyttäjältä kaksi syötettä "Anna autolla ajetut kilometrit: " sekä "Anna bensanhinta: ". Tämän jälkeen käyttäjä voi valita, onko matka maantie- vai kaupunkiajoa valinnalla "Onko matka (1) maantieajoa vai (2) kaupunkiajoa?: ". | |||
Oletetaan, että käyttäjän auto kuluttaa 5 litraa bensiiniä sadalla kilometrillä jos matka ajetaan maantiellä, ja 9 litraa jos matka ajetaan kaupungissa. Kun lukemat on tiedossa, lasketaan vastaus kaavalla (bensanhinta*kulutus litroina*matka kilmetreinä) / 100.0, ja tulostetaan se muodossa "Matka maksoi [tulos] euroa.". Ilmoitetaan tulos desimaalien tarkkuudella, joskaan vastausta ei tarvitse erikseen pyöristää. Lopuksi kysytään käyttäjältä "Lasketaanko toinen matka? (k/e): ". Jos käyttäjä valitsee "k", aloitetaan alusta. Jos "e", lopetetaan. Ohjelmassa voidaan olettaa, että käyttäjä syöttää ainoastaan oikeita lukuarvoja ja valitsee ainoastaan kelvollisia vaihtoehtoja. | |||
Toimiessaan oikein ohjelma tulostaa esimerkiksi seuraavaa: | |||
Example output: | |||
``` | |||
Anna autolla ajetut kilometrit: 140 | |||
Anna bensanhinta: 1.44 | |||
Onko matka (1) maantieajoa vai (2) kaupunkiajoa?: 2 | |||
Matka maksoi 18.144 euroa | |||
Lasketaanko toinen matka? (k/e)?: e | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
def tarkistaSyote(kysymys, tyyppi, strip=false) | |||
begin | |||
print kysymys | |||
if strip | |||
syote = eval(tyyppi + "(gets.chomp).strip") | |||
else | |||
syote = eval(tyyppi + "(gets.chomp)") | |||
end | |||
rescue ArgumentError | |||
warn "Syöttämäsi valinta ei ole kelvollinen" | |||
retry | |||
end | |||
return syote | |||
end | |||
def laskuri() | |||
km = tarkistaSyote("Anna autolla ajetut kilometrit: ", "Integer") | |||
hinta = tarkistaSyote("Anna bensanhinta: ", "Float") | |||
valinta = tarkistaSyote("Onko matka (1) maantieajoa vai (2) kaupunkiajoa?: ", "Integer") | |||
case valinta | |||
when 1 | |||
kulutus = 5 | |||
when 2 | |||
kulutus = 9 | |||
else | |||
warn "Tuntematon valinta" | |||
return | |||
end | |||
puts "Matka maksoi #{(hinta*kulutus*km)/100.0} euroa" | |||
end | |||
loop do | |||
laskuri | |||
print "Lasketaanko toinen matka? (k/e)?: " | |||
vastaus = String(gets.strip.chomp) | |||
case vastaus | |||
when "e" | |||
#Process.exit(0) | |||
break | |||
when "k" | |||
next | |||
else | |||
warn "Tuntematon valinta" | |||
end | |||
end | |||
``` |
@ -0,0 +1,65 @@ | |||
## 3 Luvunetsintä | |||
**Tehtävä:** | |||
Luvun kolmas tehtävä on yksinkertainen luvunetsintäohjelma. Tee ohjelma, joka ensin pyytää käyttäjältä kokonaisluvun syötteellä "Anna aloituspaikka:". Tämän jälkeen ohjelma alkaa läpikäymään lukuja käyttäjän antamasta aloituspaikasta eteenpäin. | |||
Ohjelman tehtävänä on etsiä luku, joka on jaollinen luvuilla 3, 5 ja 7, eli siten että [luku] / [3, 5 tai 7] menee aina tasan ja tuottaa desimaalittoman (esim. 6.0, 1724) . Jos testattava luku ei mene tasan, tulostetaan "[luku] ei kelpaa..." ja siirrytään seuraavaan lukuun. Kun sopiva luku löytyy, tulostetaan "Sopiva luku löytyi: [luku]" ja lopetetaan ohjelma siihen paikkaan. | |||
Kannattaa huomata, että käytävien kierrosten määrää on hyvin vaikea ennustaa etukäteen, joten ohjelma kannattaa toteuttaa toistonohjauksen avulla. Lisäksi ohjelmaa tehtäessä kannattaa tutustua jakojäännös-operaattoriin (%). | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Anna aloituspaikka: | |||
100 | |||
100 ei kelpaa... | |||
101 ei kelpaa... | |||
102 ei kelpaa... | |||
103 ei kelpaa... | |||
104 ei kelpaa... | |||
Sopiva luku löytyi: 105 | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
def jaonTarkistus(luku, jakajat) | |||
i = 0 | |||
for jakaja in jakajat | |||
if (luku.to_f % jakaja) == 0 | |||
i += 1 | |||
end | |||
end | |||
if i == jakajat.length | |||
puts "Sopiva luku löytyi: #{luku}" | |||
return true | |||
else | |||
puts "#{luku} ei kelpaa..." | |||
return false | |||
end | |||
end | |||
begin | |||
puts "Anna aloituspaikka:" | |||
paikka = Integer(gets.strip.chomp) | |||
rescue ArgumentError | |||
warn "Anna kokonaisluku" | |||
retry | |||
end | |||
while true | |||
if jaonTarkistus(paikka, jakajat) | |||
Process.exit(0) | |||
end | |||
paikka += 1 | |||
end | |||
``` |
@ -0,0 +1,51 @@ | |||
## 4 Fibonaccin lukusarja | |||
**Tehtävä:** | |||
Luvun neljännessä tehtävässä toteutetaan Fibonaccin lukusarjaa laskeva ohjelma. | |||
Fibonaccin lukusarja on matemaattinen sarja, jossa sarjan seuraava luku on kahden edellisen luvun summa, eli uusi luku = edellinen luku + toiseksi uusin. Lukusarja menee siis seuraavalla tavalla: 0 1 1 2 3 5 8 13 21 ... jne. | |||
Tehtävänäsi onkin rakentaa ohjelma, joka laskee käyttäjälle lukusarjaa eteenpäin. Lähtötietona ohjelmalle voidaan kerta ensimmäiset kaksi lukua, 0 ja 1. Tämän jälkeen ohjelma kysyy "Montako kierrosta lasketaan?: ", ja tulostaa Fibonaccin lukusarjan lukuja annetun määrän muodossa "Seuraava Fibonaccin luku on [vastaus]". | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Montako kierrosta lasketaan?: 5 | |||
Seuraava Fibonaccin luku on 1. | |||
Seuraava Fibonaccin luku on 2. | |||
Seuraava Fibonaccin luku on 3. | |||
Seuraava Fibonaccin luku on 5. | |||
Seuraava Fibonaccin luku on 8. | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
i = 0; lukutmp = 0; fibonacci = [0,1] | |||
begin | |||
print "Montako kierrosta lasketaan?: " | |||
kierrokset = Integer(gets.strip.chomp) | |||
rescue ArgumentError | |||
warn "Syötä kokonaisluku" | |||
retry | |||
end | |||
while i < kierrokset | |||
lukutmp = fibonacci[1] | |||
i += 1 | |||
puts "Seuraava Fibonaccin luku on #{fibonacci[0] + fibonacci[1]}." | |||
fibonacci[1] = lukutmp + fibonacci[0] | |||
fibonacci[0] = lukutmp | |||
end | |||
``` |
@ -0,0 +1,66 @@ | |||
## 5 Ostoslistaaja | |||
**Tehtävä:** | |||
Neljännen luvun viimeisessä tehtävässä tehdään taulukkoa apunakäyttäen ohjelma, joka ylläpitää ostoslistaa. | |||
Ohjelmassa on kolme toimintoa; (1) Lisää tuote (2) Poista listan viimeinen tuote ja (3) Lopeta. Valinta 1 lisää uuden tuotteen listaan, valinta 2 poistaa listan vanhimman merkinnän ja 3 lopettaa ohjelman. Lisäksi lista päivitetään joka kerta kun siihen lisätään jotain "Ostoslistalla on seuraavaa; [tuotteet]" ja lopuksi tulostetaan mitä koriin jäi: "Koriin jäi [määrä] tuotetta: [lista]". | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Ostoslistalla on seuraavaa; | |||
(1) Lisää tuote (2) Poista listan viimeinen tuote (3) Lopeta: | |||
1 | |||
Mitä lisätään?: | |||
nakkeja | |||
Ostoslistalla on seuraavaa; | |||
nakkeja | |||
(1) Lisää tuote (2) Poista listan viimeinen tuote (3) Lopeta: | |||
2 | |||
Poistetaan nakkeja | |||
Ostoslistalla on seuraavaa; | |||
(1) Lisää tuote (2) Poista listan viimeinen tuote (3) Lopeta: | |||
3 | |||
Koriin jäi 0 tuotetta: | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
def kori(lista) | |||
puts "Ostoslistalla on seuraavaa;" | |||
lista.each{ |name| print name + " " }; print "\n" | |||
puts "(1) Lisää tuote (2) Poista listan viimeinen tuote (3) Lopeta:" | |||
valintaUser = Integer(gets.chomp) | |||
case valintaUser | |||
when 1 | |||
puts "Mitä lisätään?: " | |||
lista.insert(-1,String(gets.chomp)) | |||
# Tai vaihtoehtoisesti | |||
# lista.push(String(gets.chomp)) | |||
when 2 | |||
puts "Poistetaan #{lista.shift()}" | |||
when 3 | |||
puts "Koriin jäi #{lista.length} tuotetta:" | |||
puts lista | |||
Process.exit(0) | |||
else | |||
warn "Virheellinen valinta" | |||
end | |||
end | |||
ostoslista = [] | |||
while true | |||
kori(ostoslista) | |||
end | |||
``` |
@ -0,0 +1,47 @@ | |||
## 1 Tiedoston lukeminen | |||
**Tehtävä:** | |||
Ensimmäinen tehtävä on variantti Moi maailma!-tehtävästä, joka on eräänlainen ikiaikainen klassikko ohjelmointitehtävien parissa. Tälläkertaa tehtävänä on lukea tiedostoon nimeltä "5-1_tiedosto.txt" tallennettu viesti, ja tulostaa se ruudulle. Tiedoston sisältö voidaan tulostaa ruudulle sellaisenaan. | |||
Kun ohjelma toimii oikein, tulostaa se seuraavaa: | |||
Example output: | |||
``` | |||
Hei, | |||
testataan,testataan. | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
# Joko yksinkertaisesti näin (Ruby sulkee tiedoston ohjelman päätyttyä) | |||
# tiedosto = "5-1_tiedosto.txt" | |||
# | |||
# print File.read(tiedosto) | |||
########## | |||
# Tai jos halutaan käyttää .close -metodia, niin vaikkapa näin | |||
tiedosto = File.open("5-1_tiedosto.txt", "r") | |||
print tiedosto.read | |||
tiedosto.close | |||
``` | |||
Tiedosto `5-1_tiedosto.txt`: | |||
``` | |||
Hei, | |||
testataan,testataan. | |||
``` |
@ -0,0 +1,66 @@ | |||
## 2 Tiedostoon kirjoittaminen | |||
**Tehtävä:** | |||
Luvun toisessa tehtävässä harjoitellaan tiedostoon kirjoittamista luomalla ohjelma, joka jatkaa kirjoittamista niin kauan kunnes käyttäjä pyytää ohjelmaa lopettamaan. Ohjelma pyytää käyttäjältä syötettä käskyllä "Kirjoita jotain (lopeta lopettaa):" ja jatkaa niin kauan kunnes käyttäjä kirjoittaa lopeta. Tässä vaiheessa ohjelma tallentaa muun, aiemmin kirjoitetun tekstin tiedostoon, ja tulostaa käyttäjälle tiedoksi tiedon "Tiedostoon kirjoitettiin:\n `[syötetty teksti]`". | |||
Kirjoitus tehdään tiedostoon nimeltä "5-2_tiedosto.txt", joka tyhjennetään aina ennen tiedostoon kirjoittamista. | |||
Toimiessaan oikein ohjelma tulostaa vaikkapa seuraavaa: | |||
Example output: | |||
``` | |||
Kirjoita jotain (lopeta lopettaa): | |||
testii | |||
Kirjoita jotain (lopeta lopettaa): | |||
kalle | |||
Kirjoita jotain (lopeta lopettaa): | |||
lopeta | |||
Tiedostoon kirjoitettiin: | |||
testii | |||
kalle | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
sanat = [] | |||
tiedosto = "5-2_tiedosto.txt" | |||
# Luodaan tiedosto hallitusti | |||
if (!File.exists?(tiedosto)) | |||
begin | |||
# Luodaan tiedosto 0644-tilassa. Kenellekään ei anneta tiedostoon (suoritus/)x-oikeutta. | |||
File.open(tiedosto, File::RDWR|File::CREAT, 0644) | |||
rescue | |||
# Varaudutaan tilanteeseen, jossa käyttäjällä ei ole oikeutta kirjoittaa | |||
# nykyisessä työhakemistossa (PWD) | |||
puts "Tiedostoon #{tiedosto} ei voida kirjoittaa" | |||
Process.exit(1) | |||
end | |||
end | |||
while true | |||
puts "Kirjoita jotain (lopeta lopettaa):" | |||
sana = String(gets.chomp).encode(Encoding::UTF_8) | |||
if sana == "lopeta" | |||
break | |||
else | |||
sanat.insert(-1, sana) | |||
# Tai sanat.push(sana) | |||
end | |||
end | |||
File.open(tiedosto, "w+") do |f| | |||
f.flock(File::LOCK_EX) | |||
sanat.each { |word| f.puts word } | |||
end | |||
puts "Tiedostoon kirjoitettiin:\n" + File.read(tiedosto) | |||
# Tiedosto suljetaan automaattisesti ohjelman päätyttyä. | |||
``` |
@ -0,0 +1,101 @@ | |||
## 3 Kirjainlaskuri | |||
**Tehtävä:** | |||
Tiedostojenkäsittelyn kolmas tehtävä keskittyy tiedoston sisällön tutkimiseen. Ohjelmaa varten on luotu tiedosto "5-3_tiedosto.txt", johon on tallennettu pätkä tekstiä. Tee ohjelma, joka laskee kuinka monta merkkiä pitkä tämä teksti on, ja kuinka monta pientä 'a'- ja 'f'-kirjainta tekstistä löytyy. | |||
Tulos ilmoitetaan muodossa "[pituus] merkkiä: [määrä] a:ta, [määrä] f:ää.". Lopuksi tämä sama tulos kirjoitetaan tiedoston loppuun uudelle riville. | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa ja kirjoittaa saman tekstin tiedostoon "5-3_tiedosto.txt" tiedoston loppuun uudelle riville: | |||
Example output: | |||
``` | |||
987 merkkiä: 57 a:ta, 7 f:ää. | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
tiedosto = "5-3_tiedosto.txt" | |||
if (!File.exists?(tiedosto)) | |||
begin | |||
File.open(tiedosto, File::RDWR|File::CREAT, 0644) | |||
rescue | |||
puts "Tiedostoon #{tiedosto} ei voida kirjoittaa" | |||
Process.exit(1) | |||
end | |||
end | |||
def kirjoita(tiedosto, *sanat) | |||
File.open(tiedosto, "w+:UTF-8") do |f| | |||
f.flock(File::LOCK_EX) | |||
sanat.each { |word| f.puts word } | |||
end | |||
end | |||
def kirjainLaskuri(tiedosto, naytaMaara=true, kirjoitaMaara=false, *kirjaimet) | |||
# Oheinen menetelmä antaa *rivikohtaista* tietoa merkkien esiintyvyydestä | |||
# Tietoa voitaisiin käyttää hyödyksi tiedoston sisällön analytiikassa | |||
# (esim. kirjaimien keskm. esiintyvyys tiedoston eri riveillä) | |||
countAll = 0 | |||
fileCounts = [] | |||
summaryCounts = {} | |||
File.foreach(tiedosto) do |line| | |||
lineCounts = {} | |||
# Laske jokaisen merkin esiintyvyys rivikohtaisesti, | |||
# säilytä tieto avain-arvo -parina lineCounts-muuttujaan | |||
for kirjain in kirjaimet | |||
lineCounts.merge!(Hash[kirjain[0], line.count(kirjain[0])]) | |||
end | |||
# Talleta rivikohtainen merkkimäärä | |||
countAll += line.chomp.length | |||
# Talleta jokaisen merkin esiintyvyys rivikohtaisesti, | |||
# muuttujaan fileCounts | |||
fileCounts.insert(0,lineCounts) | |||
end | |||
# Tuota yhteenveto merkkien esiintyvyydestä tiedostossa | |||
for kirjain in kirjaimet | |||
if not kirjain[0] =~ /^[a-zA-Z]{1}$/ | |||
warn "Virheellinen merkki #{kirjain[0]}\nOhitetaan..." | |||
next | |||
end | |||
charCount = 0 | |||
for i in fileCounts | |||
charCount += i.values_at(kirjain[0]).join("").to_i | |||
end | |||
summaryCounts.merge!(Hash[(kirjain[0] + ":" + kirjain[1]).to_s, charCount]) | |||
end | |||
kirjainLause = summaryCounts.map { |key, value| "#{value} #{key}" }.join(", ") | |||
kokoLause = "#{countAll} merkkiä: #{kirjainLause}.\n" | |||
if naytaMaara | |||
print kokoLause | |||
end | |||
if kirjoitaMaara | |||
File.open(tiedosto, "a:UTF-8").write(kokoLause) | |||
end | |||
end | |||
kirjoita(tiedosto, "hela fafifa muutti", "pikkukakkonen titityy", "nurisija nurisi nurkassa") | |||
kirjainLaskuri(tiedosto, true, true, ["a", "ta"], ["f", "ää"]) | |||
``` |
@ -0,0 +1,65 @@ | |||
## 4 Ankka-Hanhi | |||
**Tehtävä:** | |||
Tiedostojenkäsittelyn neljäs tehtävä käsittelee myös tiedostojen sisällön tutkimista. Tällä kertaa palvelimelle on luotu tiedosto "5-4_tiedosto.txt", johon on tallenettu riville joko teksti "ankka" tai "hanhi". Koska hanhet on varsin ikäviä eläimiä, halutaan etukäteen selvittää, millä tiedoston riveillä hanhia sijaitsee. | |||
Tee siis ohjelma, joka avaa tiedoston, ja läpikäy sen rivi riviltä. Jos rivillä lukee "hanhi", tulostetaan käyttäjälle varoitus "Hanhi rivillä [rivinumero]!". Rivinumerointi alkaa 1:stä, eli tiedoston ensimmäinen rivi on rivi numero 1. | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Hanhi rivillä 7! | |||
Hanhi rivillä 14! | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
tiedosto = "5-4_tiedosto.txt" | |||
if (!File.exists?(tiedosto)) | |||
begin | |||
File.open(tiedosto, File::RDWR|File::CREAT, 0644) | |||
rescue | |||
puts "Tiedostoon #{tiedosto} ei voida kirjoittaa" | |||
Process.exit(1) | |||
end | |||
end | |||
def kirjoita(tiedosto, *sanat) | |||
File.open(tiedosto, "w+:UTF-8") do |f| | |||
f.flock(File::LOCK_EX) | |||
sanat.each { |word| f.puts word } | |||
end | |||
end | |||
def etsiSana(tiedosto, sana) | |||
count = 1 | |||
sana = sana.downcase | |||
if (File.readable?(tiedosto)) | |||
File.foreach(tiedosto) do |line| | |||
line = line.downcase | |||
if line.to_s.match("^.*" + sana + ".*$") | |||
puts "#{sana.capitalize} rivillä #{count}!" | |||
end | |||
count += 1 | |||
end | |||
end | |||
# Tiedosto suljetaan automaattisesti. | |||
end | |||
kirjoita(tiedosto, "ankka", "hanhi", "hanhi", "ankka", "ankka", "hanhi") | |||
etsiSana(tiedosto, "hanhi") | |||
``` |
@ -0,0 +1,92 @@ | |||
## 5 Luova kone | |||
**Tehtävä:** | |||
Luvun viimeinen tehtävä on hieman tavallisuudesta poikkeava, sillä tiedostoja apuna käyttäen tarkoituksenamme on rakentaa luovia ideoita ehdottava ohjelma. | |||
Ohjelma toteutaan siten, että palvelimella on kolme tiedostoa "5-5a_tiedosto.txt","5-5b_tiedosto.txt" ja "5-5c_tiedosto.txt". Näistä ensimmäinen, "A"-tiedosto sisältää joukon adjektiiveja kuten iso, tarpeeton tai kirkas. "B"-tiedosto sisältää joukon substantiiveja, kuten poliisi, palomies tai vesipullo. "C"-tiedosto sisältää erilaisia tekstityyppejä kuten novelli, kertomus, tarina tai balladi. Jokaisessa tiedostossa on aina yksi sana per rivi, ja se on valmiiksi taivutettu oikeaan sijamuotoon. | |||
Ohjelma tekee siis seuraavaa; luetaan jokainen tiedosto omaan taulukkoonsa siten, että yksi rivi on aina yhdessä alkiossa. Tämän jälkeen arvotaan jokaisesta taulukosta yksi alkio, ja koostetaan niistä tarinan idea muodossa "[adjektiivi] [substantiivi] [tarinatyyppi]". Ohjelma tulostaa ajettaessa ainoastaan tekstin "Uuden jutun nimi voisi olla vaikkapa seuraava:\n [arvottu nimi]". | |||
Toimiessaan oikein ohjelma voi ehdottaa vaikka seuraavaa: | |||
Example output: | |||
``` | |||
Uuden jutun nimi voisi olla vaikkapa seuraava: | |||
Punaisen hanhen kertomus | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
adjektiiviTiedosto = "5-5a_tiedosto.txt" | |||
substantiiviTiedosto = "5-5b_tiedosto.txt" | |||
tarinatyyppiTiedosto = "5-5c_tiedosto.txt" | |||
def luoTiedosto(tiedosto) | |||
if (!File.exists?(tiedosto)) | |||
begin | |||
File.open(tiedosto, File::RDWR|File::CREAT, 0644) | |||
rescue | |||
puts "Tiedostoon #{tiedosto} ei voida kirjoittaa" | |||
Process.exit(1) | |||
end | |||
end | |||
end | |||
def kirjoita(tiedostohash) | |||
tiedostohash.each { |tiedosto, sanat| | |||
luoTiedosto(tiedosto) | |||
File.open(tiedosto, "w+:UTF-8") do |f| | |||
f.flock(File::LOCK_EX) | |||
sanat.each { |word| f.puts word } | |||
end | |||
} | |||
end | |||
kirjoita( | |||
{ | |||
#adjektiiviTiedosto => ["iso", "tarpeeton", "kirkas"], | |||
#substantiiviTiedosto => ["poliisi", "palomies", "vesipullo"], | |||
#tarinatyyppiTiedosto => ["novelli", "kertomus", "tarina", "balladi"] | |||
adjektiiviTiedosto => ["ison", "tarpeettoman", "kirkkaan"], | |||
substantiiviTiedosto => ["poliisin", "palomiehen", "vesipullon"], | |||
tarinatyyppiTiedosto => ["novelli", "kertomus", "tarina", "balladi"] | |||
} | |||
) | |||
######################################## | |||
def arvoLause(tiedostolista) | |||
lauseenSanat = [] | |||
for tiedosto in tiedostolista | |||
sanaLista = [] | |||
if (File.readable?(tiedosto)) | |||
File.foreach(tiedosto) do |line| | |||
sanaLista.insert(-1, line.to_s.chomp) | |||
end | |||
arvottuSana = sanaLista[rand(0...(sanaLista.length - 1))] | |||
lauseenSanat.insert(-1, arvottuSana) | |||
end | |||
end | |||
return lauseenSanat.join(" ").capitalize | |||
end | |||
printf("Uuden jutun nimi voisi olla vaikkapa seuraava:\n%s\n", | |||
arvoLause([adjektiiviTiedosto, substantiiviTiedosto, tarinatyyppiTiedosto]) | |||
) | |||
``` |
@ -0,0 +1,52 @@ | |||
## 1 Yksinkertainen metodi | |||
**Tehtävä:** | |||
Kuudennen luvun ensimmäisessä tehtävässä määritellään yksinkertainen tulostusmetodi. Tehtävänä onkin määritellä metodi tulostaja, joka saa kutsuttaessa kaksi argumenttia, sana ja kertaa. Metodin tehtävä on tulostaa annettu argumentti sana niin monta kertaa, kuin argumentissa kertaa on määrätty. | |||
Kun metodi on valmis, lisää ohjelmaan kaksi metodikutsua: | |||
``` | |||
tulostaja("Metodit jyrää.",5) | |||
tulostaja("Näin on.",2) | |||
``` | |||
Jos metodi on määritelty oikein, pitäisi sen tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Metodit jyrää. | |||
Metodit jyrää. | |||
Metodit jyrää. | |||
Metodit jyrää. | |||
Metodit jyrää. | |||
Näin on. | |||
Näin on. | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
def tulostaja(lause, kerrat) | |||
# Joko perinteisessä while-loopissa... | |||
# i = 0 | |||
# while i < kerrat | |||
# puts lause | |||
# i += 1 | |||
# end | |||
# ...tai yksinkertaisemmin käyttämällä Ruby:n oletusmetodeja: | |||
kerrat.times { | |||
puts lause | |||
} | |||
end | |||
tulostaja("Metodit jyrää.",5) | |||
tulostaja("Näin on.",2) | |||
``` |
@ -0,0 +1,48 @@ | |||
## 2 Argumentit ja paluuarvot | |||
**Tehtävä:** | |||
Toinen metodeja käsittelevä ohjelma on myös yksinkertainen syötteitä muokkaava ohjelma. | |||
Määrittele ohjelmaan metodi muuntaja, joka saa syötteenä yhden argumentin nimeltä syote. Lisää metodiin toiminnot, jotka muuttavat kaikki syote-merkkijonon a-kirjaimet y:ksi, l-kirjaimet g:ksi ja lopuksi kaikki kirjaimet isoiksi kirjaimiksi. | |||
Lisätään ohjelmaan myös käyttöliittymä; ohjelma alkaa pyytämällä käyttäjältä tekstiä muodossa "Kirjoita jotain:". Kun syöte on käsitelty, tulostetaan tulos muodossa "Käsittelyn jälkeen tulos on: [muutettu syöte]" | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Kirjoita jotain: | |||
ohjelmointia | |||
Käsittelyn jälkeen tulos on: OHJEGMOINTIY | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
def muuntaja(lause, muutaSuureksi=true, *kirjainmuutokset) | |||
for muutos in kirjainmuutokset | |||
if muutos.length > 2 | |||
puts "Varoitus: liian pitkä lista: #{muutos}" | |||
end | |||
lause = lause.gsub(muutos[0], muutos[1]) | |||
end | |||
if muutaSuureksi | |||
lause = lause.upcase | |||
end | |||
return lause | |||
end | |||
puts "Kirjoita jotain: " | |||
syote = String(gets.chomp) | |||
printf("Käsittelyn jälkeen tulos on: %s\n", muuntaja(syote, true, ["a", "y"], ["l", "g"] )) | |||
``` |
@ -0,0 +1,125 @@ | |||
## 3 Sensuroija | |||
**Tehtävä:** | |||
Luvun kolemannessa tehtävässä tehdään jälleen yleishyödyllisiä toimintoja, ja luodaan vähästä harmistuvia varten työkalu, jolla on helppo poistaa vaarallisia ajatuksia ja sanoja tekstistä. Toisin sanoen, teemme sensurointityökalun, jolla tuhma teksti voidaan muuttaa näppärästi ketään loukkaamattomaan muotoon. | |||
Rakenteellisesti ohjelma on varsin yksinkertainen. Tiedostoon "6-3a_tiedosto.txt" on tallennettu sanoja tai merkkiyhdistelmiä yksi per rivi. Tiedostossa "6-3c_tiedosto.txt" on teksti, joka saattaa sisältää näitä sensuroitaviksi haluttavia sanoja tai kirjainyhdistelmiä. A-tiedoston sanat ja merkkiyhdistelmät siis luetaan taulukkoon, ja C-tiedoston tekstistä poistetaan kaikki A-taulukossa olevat sanat ja kirjainyhdistelmät, korvaten ne viidellä tähti (*****)-merkillä. | |||
Kun vaihto on tehty, tulostetaan ruudulle teksti "Tallennetaan siistitty versio...", ja kirjoitetaan siistitty teksti tiedostoon "6-3b_tiedosto.txt". Lopuksi vielä tulostetaan ruudulle teksti "Valmis! Lopetetaan." | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Tallennetaan siistitty versio... | |||
Valmis! Lopetetaan. | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
sensuurisanatTiedosto = "6-3a_tiedosto.txt" | |||
tekstiTiedosto = "6-3c_tiedosto.txt" | |||
kohdeTiedosto = "6-3b_tiedosto.txt" | |||
$_sensuurimerkki = "*" | |||
$_sensuurimerkkiMaara = 5 | |||
def luoTiedosto(tiedosto) | |||
if (!File.exists?(tiedosto)) | |||
begin | |||
File.open(tiedosto, File::RDWR|File::CREAT, 0644) | |||
rescue | |||
puts "Tiedostoon #{tiedosto} ei voida kirjoittaa" | |||
Process.exit(1) | |||
end | |||
end | |||
end | |||
def kirjoita(tiedostohash) | |||
tiedostohash.each { |tiedosto, sanat| | |||
luoTiedosto(tiedosto) | |||
File.open(tiedosto, "w+:UTF-8") do |f| | |||
f.flock(File::LOCK_EX) | |||
sanat.each { |word| f.puts word } | |||
end | |||
} | |||
end | |||
kirjoita( | |||
{ | |||
tekstiTiedosto => ["Monesti kuitenkin käy niin, että lataan jonkin moduulin tai koitan selvitellä mistä vitusta oikein on keksinyt vaatia kaiken mahdollisen tupleina, tai vaihtoehtoisesti haluaisin käyttää jotain umpimielistä paskaa tekemään monimutkaisia asioita. Älä keksi pyörää uudestaan” on mielestäni ihan hyvä periaate; ikävä kyllä alkuperäisen keksijä jättää monesti kertomatta mihin tätä uutta hienoa pyörää voisi käyttää. Helpot tapaukset on niitä, joissa API on kuvattu skriptillä pureskeltuna generoituna tekstinä, joka ei aukea oikeastaan sen enempää kuin itse lähdesontakaan. Kehittäjille ehkä hyödyllinen, käyttäjille vihamielinen. Pahimmillaan olen nähnyt tilanteita, missä kaksi, jopa kolme, idioottia ovat keskenään ristiriitaisia ja neuvovat tekemään asiat eri tavoin, tai painottavat täysin eri asioita. Lopulta usein tuleekin paskaa, että on kokoamassa pelkkiin faktoihin perustuvaa kuvausta urheilukilpailusta haastattelemalla ulos heitettyjä humaltuneita katsojia, tai olevansa loukussa ”yksi valehtelee aina, yksi joskus ja loput puhuu totta”-tyyppisessä logiikkatestissä.","", "Mutta joo. Jo ohjelmistotekniikan peruskurssilla opetetaan, että ainoa asia joka on huonompi kuin puutteellinen ohjelmointi on virheellinen ohjelmointi, ja että kaikista viisain eläin on majava joka sukeltaa sateelta suojaan. Dokumentaatio ja käyttöohjeet voivat monesti vaikuttaa turhalta perseeltä, mutta ne eivät olekkaan tarkoitettu devaajille itselleen, vaan niille jotka käyttävät heidän tekemiään työkaluja. Ja vaikka ajatus vahingon kiertämään laittamisesta voikin houkuttaa, olisi siinä tapauksessa harkitsemisen arvoista ennemmin ryhtyä vaikka autokauppiaaksi.",""], | |||
sensuurisanatTiedosto => ["moduuli", "vitu", "paskaa", "sonta", "idiootti", "ohjelm", "perse"] | |||
} | |||
) | |||
######################################## | |||
def muodostaLista(tiedosto) | |||
sanalista = [] | |||
if (File.readable?(tiedosto)) | |||
File.foreach(tiedosto) do |line| | |||
sanalista.insert(0, line.chomp) | |||
end | |||
end | |||
return sanalista | |||
end | |||
def sensuroiSanat(tekstiTiedosto, sanaTiedosto) | |||
korvaavaSana = "" | |||
i = 0 | |||
while i < $_sensuurimerkkiMaara | |||
korvaavaSana += $_sensuurimerkki | |||
i += 1 | |||
end | |||
sensuuriLista = muodostaLista(sanaTiedosto) | |||
korvaavatRivit = [] | |||
if (File.readable?(tekstiTiedosto)) | |||
File.foreach(tekstiTiedosto) do |line| | |||
#rivinUudetSanat = [] | |||
uusiRivi = [] | |||
#for sana in line.split(" ") | |||
# TODO Add upper/lowercase support | |||
for sensuuriSana in sensuuriLista | |||
line = line.gsub(sensuuriSana, korvaavaSana) | |||
end | |||
uusiRivi.insert(-1, line) | |||
korvaavatRivit.insert(-1, uusiRivi) | |||
end | |||
end | |||
return korvaavatRivit | |||
end | |||
def kirjoitaTiedostoon(tiedosto, lista) | |||
File.open(tiedosto, "w+:UTF-8") do |f| | |||
puts "Tallennetaan siistitty versio..." | |||
f.flock(File::LOCK_EX) | |||
#lista.each { |rivi| f.print rivi } | |||
f.puts lista | |||
end | |||
puts "Valmis! Lopetetaan." | |||
end | |||
kirjoitaTiedostoon(kohdeTiedosto, sensuroiSanat(tekstiTiedosto, sensuurisanatTiedosto)) | |||
``` |
@ -0,0 +1,66 @@ | |||
## 4 Palindrominkokeilija | |||
**Tehtävä:** | |||
Luvun kuusi neljäs harjoitustehtävä on luoda ohjelma, joka testaa onko käyttäjän antama merkkijono palindromi, eli merkkijono, joka on etu- ja takaperin luettuna sama. Esimerkiksi "saippuakauppias" tai lause "Nalle vai Viivi Avellan?" ovat palindromeja, koska ne voidaan lukea samalla tavoin etu- ja takaperin. | |||
Tee siis ohjelma, joka pyytää käyttäjältä testattavaa lausetta kysymällä "Kirjoita testattava lause: " ja testaa syötteen, vastaten joko "[syöte] on palindromi." tai "[syöte] ei ole palindromi; se on väärinpäin [syöte väärinpäin].". Lisäksi, mikäli käyttäjän antama syöte on alle 5 merkkiä pitkä, annetaan virheilmoitus "[syöte] ei ole kelvollinen sana.". Lopuksi käyttäjältä vielä kysytään "Testataanko lisää? (k/e): ". | |||
Toteuta ohjelmasti siten, että palindromin tunnistus onnistuu epäsymmetrisesti asetelluista välilyönneistä ja isoista kirjaimista huolimatta. Välimerkkejä (!,?, : jne...) järjestelmän ei tarvitse tunnistaa; oletetaan että käyttäjä ei kirjoita niitä testisyötteisiin. | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Kirjoita testattava lause: saippua | |||
saippua ei ole palindromi; se on väärinpäin auppias. | |||
Testataanko lisää? (k/e): k | |||
Kirjoita testattava lause: saippuakauppias | |||
saippuakauppias on palindromi. | |||
Testataanko lisää? (k/e): e | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
def palindromi(syote) | |||
if syote.length < 5 | |||
puts "#{syote} ei ole kelvollinen sana." | |||
return | |||
end | |||
syotecp = syote.downcase.gsub(" ", "") | |||
if syotecp == syotecp.reverse | |||
puts "#{syote} on palindromi." | |||
else | |||
puts "#{syote} ei ole palindromi; se on väärinpäin #{syote.reverse}." | |||
end | |||
end | |||
while true | |||
print "Kirjoita testattava lause: " | |||
palindromi(String(gets.chomp)) | |||
begin | |||
print "Testataanko lisää? (k/e): " | |||
input = String(gets.strip.chomp) | |||
case input | |||
when "k" | |||
next | |||
when "e" | |||
Process.exit(0) | |||
else | |||
throw ArgumentError | |||
end | |||
rescue ArgumentError | |||
warn "Tuntematon valinta" | |||
retry | |||
end | |||
end | |||
``` |
@ -0,0 +1,57 @@ | |||
## 5 Metodien oletusarvot | |||
**Tehtävä:** | |||
Luvun viimeinen tehtävä on variaatio ensimmäisestä tehtävästä. Muuta kyseinen tehtävän ratkaisua siten, että metodin argumenteille annetaan oletusarvot; sana saa oletusarvon "Oletusarvo" ja kertaa oletusarvon 5. Lisäksi muuta koodia siten, että tulostus tapahtuu samalle riville, ja vasta koko rivin loppuun tulee rivinvaihto. | |||
Tämän jälkeen lisää lähdekoodiisi seuraavat metodikutsut: | |||
``` | |||
tulostaja("Metodeilla voimaa!", 2) | |||
tulostaja("Toimii!") | |||
tulostaja | |||
``` | |||
Toimiessaan oikein tulostusmetodi tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Metodeilla voimaa! Metodeilla voimaa! | |||
Toimii! Toimii! Toimii! Toimii! Toimii! | |||
Oletusarvo Oletusarvo Oletusarvo Oletusarvo Oletusarvo | |||
Oletusarvo Oletusarvo Oletusarvo Oletusarvo Oletusarvo | |||
Testi Testi Testi Testi Testi | |||
Oikein Oikein Oikein | |||
Metodeilla voimaa! Metodeilla voimaa! | |||
Toimii! Toimii! Toimii! Toimii! Toimii! | |||
Oletusarvo Oletusarvo Oletusarvo Oletusarvo Oletusarvo | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
def tulostaja(lause="Oletusarvo", kerrat=5) | |||
# Perinteinen while-loop | |||
i = 0 | |||
while i < kerrat | |||
printf("%s ", lause) | |||
i += 1 | |||
end | |||
# Tai tyypillinen Ruby-ratkaisu... | |||
# kerrat.times { | |||
# printf("%s ", lause) | |||
# } | |||
puts | |||
end | |||
tulostaja("Metodeilla voimaa!", 2) | |||
tulostaja("Toimii!") | |||
tulostaja | |||
``` |
@ -0,0 +1,77 @@ | |||
## 1 Alkuluvut | |||
**Tehtävä:** | |||
Alkuluvut ovat matemaattisessa mielessä mielenkiintoinen lukujoukko. Ne ovat lukuja, jotka ovat tasan jaollisia ainoastaan itsellään tai yhdellä (eli [alkuluku] % [muu kuin 1 tai itse]!= 0). Tämän ominaisuuden vuoksi ne ovat hyvin suosittuja osia esimerkiksi salausalgoritmeissa, koska niiden katsotaan olevan "turvallisempia" luku. Esimerkiksi 2, 3, 5 ,7 ,11, 13 ja 17 ovat alkulukuja, kun taas esimerkiksi 57 ei ole (jaollinen 3:lla), 1243645614636 ei myöskään (jaollinen 2:lla) jne. Ylipäänsä parilliset luvut eivät voi olla alkulukuja, koska ne ovat aina jaollisia itsensä ja yhden lisäksi 2:lla. | |||
Toinen mielenkiintoinen ominaisuus luvuissa on, että niiden ennustaminen on vaikeaa. Mitä pidemmälle luonnollisten kokonaislukujen joukossa mennään, sitä satunnaisemmin ja harvemmin vastaan tuleva luku on alkuluku. Itseasiassa näiden lukujen etsintä onkin aikaisemmin ollut eräänlainen kilpailumuoto supertietokoneiden kesken. | |||
Tässä vaiheessa ei varmaan ole vaikea arvata, että tarkoituksena on tehdä ohjelma, joka etsii alkulukuja. Tee siis ohjelma, joka aloittaa kokonaislukujen läpikäynnin luvusta 2, ja jatkaa siitä ylöspäin käyttäjän antamaan ylärajaan asti. Yläraja määräytyy kysymällä "Monenteenko lukuun asti etsitään?: ". Jos luku on jaollinen jollain aikaisemmin läpikäydyllä luvulla, tulostetaan "[luku] ei ole alkuluku.", jos taas ei ole, voidaan tulostaa "[luku] on alkuluku!". | |||
Ohjelmasta pystyy tekemään helposti sellaisen, että se jumittaa tietokoneen, koska siihen on helppo tehdä vahingossa useita sisäkkäisiä toistoja. Toteuta ohjelmasi kuitenkin siten, että se pystyy läpikäymään ensimmäiset 2500 lukua ilman isompia ongelmia. Toimiessaan oikein ohjelma tulostaa vaikkapa seuraavaa: | |||
Example output: | |||
``` | |||
Monenteenko lukuun asti etsitään?: 10 | |||
2 on alkuluku! | |||
3 on alkuluku! | |||
4 ei ole alkuluku. | |||
5 on alkuluku! | |||
6 ei ole alkuluku. | |||
7 on alkuluku! | |||
8 ei ole alkuluku. | |||
9 ei ole alkuluku. | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
def tarkistaSyote(kysymys, tyyppi, strip=false) | |||
begin | |||
print kysymys | |||
if strip | |||
syote = eval(tyyppi + "(gets.strip.chomp)") | |||
else | |||
syote = eval(tyyppi + "(gets.chomp)") | |||
end | |||
rescue ArgumentError | |||
warn "Syöttämäsi valinta ei ole kelvollinen" | |||
retry | |||
end | |||
return syote | |||
end | |||
########## | |||
def onkoAlkuluku(luku) | |||
#if luku <= 1 | |||
# puts "Syötteen tulee olla lukua 1 suurempi kokonaisluku. Annoit #{luku}" | |||
# return | |||
#end | |||
i = 2 | |||
while i < luku | |||
if luku % i == 0 | |||
return "#{luku} ei ole alkuluku." | |||
end | |||
i += 1 | |||
end | |||
return "#{luku} on alkuluku!" | |||
end | |||
luku = tarkistaSyote("Monenteenko lukuun asti etsitään?: ", "Integer", true) | |||
i = 2 | |||
while i < luku | |||
printf("%s\n", onkoAlkuluku(i)) | |||
i += 1 | |||
end | |||
``` |
@ -0,0 +1,120 @@ | |||
## 2 Tiedoston järjesteleminen | |||
**Tehtävä:** | |||
Luvun toisessa tehtävässä Työskellään tiedostojen kanssa ja tehdään yksinkertainen suodatin joka läpikäy tiedoston sisällön, järjestelee sen ja poistaa sieltä turhat merkinnät. | |||
Tee ohjelma, joka lukee tiedostosta "7-2a_tiedosto.txt" listan sanoja, joita on aina yksi per rivi. Nämä sanat voivat olla mitä tahansa, ja ne saattaa esiintyä tiedostossa useaan kertaan. Tee ohjelma, joka lukee listan, poistaa sieltä kaikki ylimääräiset, useampaan kertaan olevat alkiot (1 kpl jätetään talteen), lajittelee sanat aakkosjärjestykseen ja tulostaa tuloksen tiedostoon "7-2b_tiedosto.txt". Toimiessaan oikein ohjelma ei tulosta mitään. | |||
Jos oletetaan, että käsiteltävän tiedoston sisältö on seuraavanlainen: | |||
``` | |||
kivitasku | |||
nakki | |||
suihkuturbiini | |||
aapinen | |||
avantgarde | |||
lakana | |||
zylofoni | |||
celsius | |||
byrokraatti | |||
lukihäriö | |||
mustikka | |||
magneetti | |||
kolikko | |||
avantgarde | |||
lakana | |||
zylofoni | |||
celsius | |||
koivu | |||
lusikka | |||
kahvikuppi | |||
salama | |||
kotelo | |||
puhelin | |||
avaimet | |||
lukihäriö | |||
kahvikuppi | |||
kahvikuppi | |||
kahvikuppi | |||
kahvikuppi | |||
aapinen | |||
``` | |||
... on siitä tuotettu siistitty ja suodatettu versio seuraavanlainen: | |||
``` | |||
aapinenaapinen | |||
avaimet | |||
avantgarde | |||
byrokraatti | |||
celsius | |||
kahvikuppi | |||
kivitasku | |||
koivu | |||
kolikko | |||
kotelo | |||
lakana | |||
lukihäriö | |||
lusikka | |||
magneetti | |||
mustikka | |||
nakki | |||
puhelin | |||
salama | |||
suihkuturbiini | |||
zylofoni | |||
``` | |||
Example output: | |||
``` | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
tiedostoIn = "7-2a_tiedosto.txt" | |||
tiedostoOut = "7-2b_tiedosto.txt" | |||
if (!File.exists?(tiedostoIn)) | |||
begin | |||
File.open(tiedostoIn, File::RDWR|File::CREAT, 0644) | |||
rescue | |||
puts "Tiedostoon #{tiedostoIn} ei voida kirjoittaa" | |||
Process.exit(1) | |||
end | |||
end | |||
def kirjoita(tiedosto, sanat) | |||
File.open(tiedosto, "w+:UTF-8") do |f| | |||
f.flock(File::LOCK_EX) | |||
sanat.each { |sana| f.puts sana } | |||
end | |||
end | |||
kirjoita(tiedostoIn, ["kivitasku", "nakki", "suihkuturbiini", "aapinen", "avantgarde", "lakana", "zylofoni", "celsius", "byrokraatti", "lukihäriö", "mustikka", "magneetti", "kolikko", "avantgarde", "lakana", "zylofoni", "celsius", "koivu", "lusikka", "kahvikuppi", "salama", "kotelo", "puhelin", "avaimet", "lukihäriö", "kahvikuppi", "kahvikuppi", "kahvikuppi", "kahvikuppi", "aapinen"]) | |||
############################### | |||
def jarjestaRivit(tiedostoLahde, tiedostoTulos) | |||
sanalista = [] | |||
if (File.readable?(tiedostoLahde)) | |||
File.foreach(tiedostoLahde) do |line| | |||
sanalista.insert(-1, line | |||
end | |||
end | |||
kirjoita(tiedostoTulos, sanalista.sort.uniq) | |||
end | |||
jarjestaRivit(tiedostoIn, tiedostoOut) | |||
``` |
@ -0,0 +1,104 @@ | |||
## 3 Salasanageneraattori | |||
**Tehtävä:** | |||
Luvun kolmas tehtävä on jälleen eräänlainen hyötyohjelma. Tällä kertaa tarkoituksena on luoda ohjelma, joka luo uusia sanasalasanoja, jotka muodostuvat yhdeksästä satunnaisesta kirjaimesta. | |||
Ohjelmaa varten on luotu tiedosto 7-3_tiedosto.txt, jossa on 1000 satunnaista kirjain- ja numeromerkkiä. Tee seuraavaksi ohjelma, joka pyytää käyttäjältä 9 lukua väliltä 0-999 muodossa "Anna X. luku väliltä 0-999: ". Tämän jälkeen tee ohjelma, joka hakee tiedostosta lukua vastaavan merkin, eli jos käyttäjä antaa arvon 0, haetaan tiedoston ensimmäinen merkki, jos 876, haetaan merkki joka on tiedoston 876. paikalla. | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Luodaan salasana. | |||
Anna 1. luku väliltä 0-999: 234 | |||
Anna 2. luku väliltä 0-999: 22 | |||
Anna 3. luku väliltä 0-999: 1 | |||
Anna 4. luku väliltä 0-999: 76 | |||
Anna 5. luku väliltä 0-999: 45 | |||
Anna 6. luku väliltä 0-999: 23 | |||
Anna 7. luku väliltä 0-999: 27 | |||
Anna 8. luku väliltä 0-999: 87 | |||
Anna 9. luku väliltä 0-999: 3 | |||
Ohjelma loi salasanan cf5HAsu66 | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
require 'securerandom' | |||
merkkiTiedosto = "7-3_tiedosto.txt" | |||
def luoTiedosto(tiedosto) | |||
if (!File.exists?(tiedosto)) | |||
begin | |||
File.open(tiedosto, File::RDWR|File::CREAT, 0644) | |||
rescue | |||
warn "Tiedostoon #{tiedosto} ei voida kirjoittaa" | |||
Process.exit(1) | |||
end | |||
end | |||
end | |||
def kirjoitaRandom(tiedosto, maara) | |||
File.open(tiedosto, "w+:UTF-8") do |f| | |||
f.flock(File::LOCK_EX) | |||
f.puts SecureRandom.urlsafe_base64(maara) | |||
end | |||
end | |||
luoTiedosto(merkkiTiedosto) | |||
kirjoitaRandom(merkkiTiedosto, 1000) | |||
################################################## | |||
def salasanaGeneraattori(tiedosto, merkkimaara, lukuvali) | |||
merkit = [] | |||
i = 0 | |||
salasana = "" | |||
if lukuvali.length != 2 | |||
warn "Lukuvälin täytyy koostua alarajasta ja ylärajasta, jotka annetaan kokonaislukuina." | |||
return | |||
end | |||
if (File.readable?(tiedosto)) | |||
File.foreach(tiedosto) do |line| | |||
merkit += line.chomp.split("") | |||
end | |||
end | |||
if merkit.length < lukuvali[1] | |||
warn "Annettu yläraja #{lukuvali[1]} on suurempi kuin merkkien määrä tiedostossa (#{merkit.length})." | |||
warn "Sallittu yläraja asetetaan arvoon #{merkit.length}." | |||
end | |||
puts "Luodaan salasana." | |||
while i < 9 | |||
begin | |||
print "Anna #{i+1}. luku väliltä #{lukuvali[0]}-#{lukuvali[1]}: " | |||
valinta = Integer(gets.chomp) | |||
salasana += merkit[valinta].to_s | |||
rescue | |||
warn "Et antanut kokonaislukua. Yritä uudelleen." | |||
next | |||
end | |||
i += 1 | |||
end | |||
puts "Ohjelma loi salasanan #{salasana}" | |||
end | |||
salasanaGeneraattori(merkkiTiedosto, 9, [0,999]) | |||
``` |
@ -0,0 +1,75 @@ | |||
## 4 Oma moduuli, nimiavaruus | |||
**Tehtävä:** | |||
Seitsämännen luvun viimeinen tehtävä on luoda oma moduuli, joka sisältää oman nimiavaruuden. Myös tälläkin kertaa tarkoituksena on luoda itse moduuli, jota käytetään jo olemassaolevan ohjelman toimesta. | |||
Ohjelmaa varten on luotu seuraavanlainen koodi, joka käyttöönottaa moduulin MuuntajaModuuli ja kutsuu siihen määriteltyjä metodeja: | |||
``` | |||
require "7-4" | |||
include MuuntajaModuuli | |||
MuuntajaModuuli::muunna("Vesihiisi sihisee") | |||
tulos = MuuntajaModuuli::parillinen?(1024) | |||
if tulos == true | |||
puts "Testattu luku oli parillinen!" | |||
end | |||
``` | |||
Tehtävänäsi on siis luoda tämä moduuli, ja määritellä siihen kaksi metodia `muunna` ja `parillinen?`. Metodi `parillinen?` ottaa vastaan yhden kokonaisluvun, ja kokeilee onko luku parillinen vai ei. Jos luku on parillinen, palautetaan `true`, jos pariton tai epäkelpo arvo, palautetaan `false`. Testinä voidaan käyttää yksinkertaisesti "jakojäännös kahdella"-testiä. Metodi muunna taas vastaanottaa yhden merkkijonon, josta se muuttaa "i"-kirjaimet tähtimerkiksi ("*"), "h"-kirjaimet väliviiväksi ("-") ja "s"-kirjaimet alaviivoiksi ("_"). Tämän jälkeen metodi tulostaa muunnetun merkkijonon. | |||
Kun moduuli toimii oikein, tulostaa ohjelma seuraavaa: | |||
Example output: | |||
``` | |||
Ve_*_uk_* lu*_taa | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
require "./7-4_omamoduuli.rb" | |||
include MuuntajaModuuli | |||
MuuntajaModuuli::muunna("Vesihiisi sihisee") | |||
tulos = MuuntajaModuuli::parillinen?(1024) | |||
if tulos == true | |||
puts "Testattu luku oli parillinen!" | |||
end | |||
``` | |||
Tiedosto 7-4_omamoduuli.rb: | |||
``` | |||
# coding: utf-8 | |||
module MuuntajaModuuli | |||
def muunna(lause) | |||
# muuttaa kaikki i-kirjaimet tähtimerkeiksi | |||
# muuttaa h-kirjaimet väliviivoiksi | |||
# muuttaa s-kirjaimet alaviivoiksi | |||
chars = { "i" => "*", "h" => "-", "s" => "_" } | |||
chars.each { |avain,arvo| lause = lause.gsub(avain, arvo) } | |||
puts lause | |||
end | |||
def parillinen?(luku) | |||
# kokeilee, onko luku parillinen vai ei | |||
# palauta true, jos parillinen | |||
# palauta false, jos pariton tai epäkelpo arvo | |||
return true if luku % 2 == 0 | |||
return false | |||
end | |||
end | |||
``` |
@ -0,0 +1,85 @@ | |||
## 5 HTML-purkaja | |||
**Tehtävä:** | |||
Luvun viimeinen tehtävä on hieman poikkeuksellinen, koska tällä kertaa ei luoda itse pääohjelmaa, vaan ainaostaan kirjastomoduuli, joka toteuttaa ohjelman haluaman toiminnon. Itse ohjelmassa poistetaan HTML-muotoilumerkintöjä tekstin seasta ja tulostetaan siistitty teksti ruudulle. | |||
Tehtävää varten on luotu ohjelmakoodi, joka kutsuu metodia nimeltä siisti; argumentiksi metodi saa yhden täyden HTML-kuvauksen yhtenä pitkänä merkkijonona. lähdekooditiedosto on seuraavanlainen: | |||
``` | |||
require "7-5" | |||
tiedosto = File.open("7-5_tiedosto.txt") | |||
rivit = "" | |||
tiedosto.each{|rivi| rivit << rivi} | |||
tiedosto.close | |||
tulos = siisti(rivit) | |||
puts tulos | |||
``` | |||
HTML-kuvaus tarkoittaa verkkosivujen muotoilukuvausta, jossa esimerkiksi tekstipalstat ja otsikoksi tarkoitetut tekstit on merkitty -merkkien väliin tulevilla HTML-kuvauskielen komennoilla. | |||
Ohjelmalla on siis tarkoitus poistaa hakasulkeiden sisällä olevat muotoiluohjeet luettavasta tulosteesta. Käytännössä tämä tarkoittaa sitä, että tehtävänäsi on määritellä uusi moduuli, jossa on metodi siisti, joka läpikäy argumenttina saamansa merkkijonon ja poistaa html-kuvausmerkit ja niiden sisällön korvaamalla ne välilyönneillä. | |||
Jos kirjoitettu moduuli toimii oikein, tulostaa ohjelma seuraavaa: | |||
Example output: | |||
``` | |||
"Rails-singulariteetti" on tavallinen termi Ruby- | |||
työkalujen ja ympäristöjen keskuudessa. Se tarkoittaa kehitysympäristölle | |||
yhteensopivuustasoa, jolla ympäristö pystyy toteuttamaan Ruby on Rails-kehyksen | |||
toiminnot. Näitä kehitysympäristöjä ei ole montaa. | |||
Rubyn suunnittelun lähtökohtana on ollut käytettävyys ja tehokkuus. Kielen | |||
alkuperäinen suunnittelija, Yukihiro Matsumoto, onkin korostanut tätä ajatusta | |||
toteamalla, että perinteinen ohjelmointitapa pyrkii selittämään asioita | |||
tietokoneen ymmärtämällä tavalla huolimatta siitä, että loppujenlopuksi | |||
tietokoneen tulisi ainoastaan olla laite, jonka avulla ihmiset voivat hyödyntää | |||
toistensa tekemää työtä. | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
require "./7-5_purkaja.rb" | |||
tiedosto = File.open("7-5_tiedosto.txt") | |||
rivit = "" | |||
tiedosto.each{|rivi| rivit << rivi} | |||
tiedosto.close | |||
tulos = siisti(rivit) | |||
puts tulos | |||
``` | |||
Tiedosto 7-5_purkaja.rb: | |||
``` | |||
# coding: utf-8 | |||
def siisti(rivit) | |||
s = [] | |||
for rivi in rivit.split("\n") | |||
# Kuinka monta merkkiä korvataan? | |||
merkkiMaara = rivi.split("").length - rivi.gsub(/<[^>]*>/, "").split("").length | |||
korv = "" | |||
i = 0 | |||
while i < valit | |||
merkkiMaara += " " | |||
i += 1 | |||
end | |||
s.insert(-1, rivi.gsub(/<[^>]*>/, korv)) | |||
end | |||
return s | |||
end | |||
``` |
@ -0,0 +1,48 @@ | |||
## 1 Tiedostonlukija | |||
**Tehtävä:** | |||
Luvun ensimmäisessä tehtävässä harjoitellaan oikeaoppista tiedoston avaamista lukemista varten, koska kyseinen kohta on tavallisin käyttäjän toimesta tapahtuvan virheilmoituksen tuottava toiminto. | |||
Tee siis ohjelma, joka kysyy käyttäjältä tiedostonnimeä muodossa "Anna luettavan tiedoston nimi:" ja yrittää avata kyseisen tiedoston. Luo ohjelmaan virheenkäsittelyrutiini siten, että virheellisen tiedoston antaminen ei aiheuta virhetilannetta, ja toteuta muu ohjelma siten, että tiedoston nimeä pyydetään niin monta kertaa, että kelvollinen tiedostonnimi annetaan. Jos tiedostonnimi on oikein, lue ja tulosta tiedoston sisältö ruudulle. | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Anna luettavan tiedoston nimi: | |||
testii | |||
Tiedoston nimi ei kelpaa. | |||
Anna luettavan tiedoston nimi: | |||
8-1_tiedosto2.txt | |||
Terve! | |||
Testii | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
# Toteutus myös begin; rescue (retry) -rakenteella mahdollinen | |||
while true | |||
puts "Anna luettavan tiedoston nimi:" | |||
tiedosto = String(gets.chomp) | |||
if (File.readable?(tiedosto)) | |||
print File.open(tiedosto, "r:UTF-8").read | |||
Process.exit(0) | |||
else | |||
puts "Tiedoston nimi ei kelpaa." | |||
end | |||
end | |||
``` | |||
Tiedosto 8-1_tiedosto2.txt: | |||
``` | |||
Terve! | |||
Testii | |||
``` |
@ -0,0 +1,125 @@ | |||
## 2 Nelilaskin | |||
**Tehtävä:** | |||
Luvun toisessa tehtävässä tehdään yksinkertainen nelilaskin, mutta tällä kertaa siten, että ohjelma toipuu erilaisista virhesyötteistä. | |||
Toteuta ohjelmasi siten, että laskinmessa voi perusnelilaskintoimintojen lisäksi vaihtaa lukuja sekä lopettaa vasta sitten kun näin halutaan tehdä. Tee ohjelmaan luvun pyytämistä varten metodi, joka tarkastaa että käyttäjä oikeasti syötti jonkin liukuluvuksi muuntuvan arvon, eli jotain muuta kuin pelkästään painoi enteriä. Syötettä pyydetään niin kauan että jotain, vaikka kirjaimia jotka tyyppimuuntuu arvoon 0, syötetään. Lisäksi nollalla jaon yrittäminen tulee päättyä virheilnoitukseen "Taisit yrittää nollalla jakoa?". | |||
Muuten ohjelma tulostaa aina valintaa pyytäessään "Arvot luku1 = [arvo] ; luku2 = [Arvo}] \n 1: + 2: - 3: * 4: / 5: Vaihda luvut 6: Lopeta", ja laskutoimitus valittaessa "Tulos on [vastaus].". Jos valinta on virheellinen, tulostetaan "Virheellinen valinta" tai viallisen syötteen yhtyeydessä "Virheellinen syöte." | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Anna luku: 60 | |||
Anna luku: 3 | |||
Arvot luku1 = 60.0 ; luku2 = 3.0 | |||
1: + 2: - 3: * 4: / 5: Vaihda luvut 6: Lopeta | |||
Valitse toiminto: 1 | |||
Tulos on 63.0. | |||
Arvot luku1 = 60.0 ; luku2 = 3.0 | |||
1: + 2: - 3: * 4: / 5: Vaihda luvut 6: Lopeta | |||
Valitse toiminto: 2 | |||
Tulos on 57.0. | |||
Arvot luku1 = 60.0 ; luku2 = 3.0 | |||
1: + 2: - 3: * 4: / 5: Vaihda luvut 6: Lopeta | |||
Valitse toiminto: 3 | |||
Tulos on 180.0. | |||
Arvot luku1 = 60.0 ; luku2 = 3.0 | |||
1: + 2: - 3: * 4: / 5: Vaihda luvut 6: Lopeta | |||
Valitse toiminto: 4 | |||
Tulos on 20.0. | |||
Arvot luku1 = 60.0 ; luku2 = 3.0 | |||
1: + 2: - 3: * 4: / 5: Vaihda luvut 6: Lopeta | |||
Valitse toiminto: 6 | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
def lukuLukija | |||
# Alkuperäisessä implementaatiossa lukujen määrä oli valittavissa | |||
# Tehtävänannossa lukujen määrä on kuitenkin rajattu kahteen, | |||
# joten kovakoodaamme sen. | |||
lukujenMaara = 2 | |||
luvut = {} | |||
i = 0 | |||
while i < lukujenMaara | |||
print "Anna luku: " | |||
begin | |||
luvut.merge!(Hash["luku" + (i+1).to_s, Integer(gets.chomp).to_f]) | |||
i += 1 | |||
rescue ArgumentError | |||
# Kirjaimien tulee tehtävänannon mukaan muuntua arvoon 0 | |||
luvut.merge!(Hash["luku" + (i+1).to_s, 0.to_f]) | |||
i += 1 | |||
puts "Virheellinen syöte." | |||
end | |||
end | |||
return luvut | |||
end | |||
def lukuLaskin | |||
luvut = lukuLukija | |||
while true | |||
vastaus = 0 | |||
printf("\nArvot %s\n", luvut.map { |avain,arvo| avain + " = " + arvo.to_s }.join(" ; ") ) | |||
print "1: + 2: - 3: * 4: / 5: Vaihda luvut 6: Lopeta\nValitse toiminto: " | |||
begin | |||
toiminto = Integer(gets.chomp) | |||
case toiminto | |||
when 1 | |||
vastaus = luvut["luku1"] + luvut["luku2"] | |||
when 2 | |||
vastaus = luvut["luku1"] - luvut["luku2"] | |||
when 3 | |||
vastaus = luvut["luku1"] * luvut["luku2"] | |||
when 4 | |||
# Tuottaa Infinity, jos jaetaan 0.0. | |||
# Nollalla jako testataan alhaalla. | |||
vastaus = luvut["luku1"] / luvut["luku2"] | |||
# Vain Integer-tyyppinen muuttuja voi antaa ZeroDivisionError-virheen | |||
# https://ruby-doc.org/core-2.7.0/ZeroDivisionError.html | |||
begin | |||
luvut["luku1"].to_i / luvut["luku2"].to_i | |||
rescue ZeroDivisionError | |||
puts "Taisit yrittää nollalla jakoa?" | |||
next | |||
end | |||
when 5 | |||
luvut = lukuLukija() | |||
next | |||
when 6 | |||
Process.exit(0) | |||
else | |||
warn "Virheellinen valinta" | |||
return | |||
end | |||
puts "Tulos on #{vastaus}." | |||
rescue ArgumentError | |||
warn "Virheellinen valinta" | |||
end | |||
end | |||
end | |||
lukuLaskin | |||
``` |
@ -0,0 +1,110 @@ | |||
## 4 Morse-koodaaja | |||
**Tehtävä:** | |||
Luvun neljännessä tehtävässä tehdään jälleen ainakin jollain tapaa hyödyllinen ohjelma. Tällä kertaa ohjelman tehtävänä on lukea käyttäjän antama tekstisyöte ja muuttaa se Morse-koodiksi. | |||
Ohjelmaa varten on luotu tiedosto 8-4_tiedosto.txt, joka sisältää kaikki englanninkielen aakkosten Morse-aakkoset muodossa [kirjain]:[morsekoodi] \n [kirjain]:[morsekoodi]\n jne... | |||
Tiedosto sisältää kaikki aakkoset väliltä A-Z. Tehtävänäsi on siis luoda ohjelma, joka pyytää käyttäjältä syötteen muodossa "Kirjoita muutettava lause: " ja tämän jälkeen taulukoiden ja merkkijonojen metodeja apuna käyttäen muuttaa käyttäjän syötteen merkki merkiltä kirjainta vastaavaksi morsekoodiksi, erotellen morsekoodimerkit toisistaa "/"-merkillä. | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Kirjoita muutettava lause: | |||
ohjelmointi | |||
Morse-koodina vastaava on seuraavaa: | |||
/---/..../.---/./.-../--/---/../-./-/.. | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
morseTiedosto = "8-4_tiedosto.txt" | |||
$_jakajaMerkki = ":" | |||
def morseKaantaja(aakkoset) | |||
morseTeksti = "" | |||
puts "Kirjoita muutettava lause: " | |||
syote = String(gets.chomp).gsub(/[^a-zA-Z]/,"").upcase.split("") | |||
for i in syote | |||
morseTeksti += "/" + aakkoset[i] | |||
end | |||
puts "Morse-koodina vastaava on seuraavaa:\n#{morseTeksti}" | |||
end | |||
def aakkosetMap(tiedosto) | |||
taulukko = {} | |||
if File.readable?(tiedosto) | |||
linenum = 1 | |||
File.foreach(tiedosto) do |line| | |||
# On hyvä tarkistaa, että sisäänluettavan tiedoston tämänhetkinen | |||
# rivi on oikean pituinen. Muussa tapauksessa rivi ohitetaan. | |||
if line.split($_jakajaMerkki).length == 2 | |||
aakkonen = line.split($_jakajaMerkki)[0] | |||
morse = line.split($_jakajaMerkki)[1].chomp | |||
if aakkonen.length != 1 | |||
warn "Merkki '#{aakkonen}' ei ole kelvollinen aakkonen" | |||
next | |||
end | |||
taulukko.merge!(Hash[aakkonen, morse]) | |||
else | |||
warn "Havaittiin viallinen syntaksi rivillä #{linenum}. Ohitetaan rivi." | |||
end | |||
linenum += 1 | |||
end | |||
end | |||
return taulukko | |||
end | |||
morseKaantaja(aakkosetMap(morseTiedosto)) | |||
``` | |||
Tiedosto 8-4_tiedosto.txt: | |||
``` | |||
A:.- | |||
B:-... | |||
C:-.-. | |||
D:-.. | |||
E:. | |||
F:..-. | |||
G:--. | |||
H:.... | |||
I:.. | |||
J:.--- | |||
K:-.- | |||
L:.-.. | |||
M:-- | |||
N:-. | |||
O:--- | |||
P:.--. | |||
Q:--.- | |||
R:.-. | |||
S:... | |||
T:- | |||
U:..- | |||
V:...- | |||
W:.-- | |||
X:-..- | |||
Y:-.-- | |||
Z:--.. | |||
``` |
@ -0,0 +1,78 @@ | |||
## 5 Numeronarvauspeli | |||
**Tehtävä:** | |||
Luvun viimeinen tehtävä on kertaustehtävä, jossa rakennetaan numeronarvauspeli. Tee ohjelma, joka arpoo luvun väliltä 0-99 ja pyytää käyttäjää arvaamaan annettu luku. | |||
Mikäli käyttäjä arvaa yläkanttiin, tulostetaan "Haettu luku on pienempi", jos alakanttiin niin "Haettu luku on suurempi". Jos pelaaja arvaa oikein, tulostetaan "Arvasit oikein!" ja kysytään "Pelataanko uudestaan? (k/e): ". Alussa ohjelma antaa yleiset ohjeet muodossa "Arvaa luku väliltä 0-99". | |||
Toteuta ohjelmasi siten, että käyttäjän antamat virhesyötteet kuten kirjaimet tai erikoismerkit eivät aiheuta ohjelman kaatumista. | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Arvaa luku väliltä 0-99. | |||
Arvaus: 10 | |||
Haettu luku on suurempi. | |||
Arvaus: 30 | |||
Haettu luku on pienempi. | |||
Arvaus: 20 | |||
Arvasit oikein! | |||
Pelataanko uudestaan? (k/e): e | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
$_lukuVali = [0, 99] | |||
def arvaaLuku | |||
arvottuLuku = rand($_lukuVali[0]...$_lukuVali[1]) | |||
puts "Arvaa luku väliltä #{$_lukuVali[0]}-#{$_lukuVali[1]}." | |||
while true | |||
print "Arvaus: " | |||
begin | |||
arvaus = Integer(gets.chomp) | |||
rescue ArgumentError | |||
warn "Anna kokonaisluku" | |||
retry | |||
end | |||
case | |||
when arvaus < arvottuLuku | |||
puts "Haettu luku on suurempi." | |||
when arvaus > arvottuLuku | |||
puts "Haettu luku on pienempi." | |||
else | |||
puts "Arvasit oikein!" | |||
begin | |||
print "Pelataanko uudestaan? (k/e): " | |||
vastaus = String(gets.strip.chomp) | |||
case vastaus | |||
when "k" | |||
arvottuLuku = rand($_lukuVali[0]...$_lukuVali[1]) | |||
next | |||
when "e" | |||
Process.exit(0) | |||
else | |||
throw ArgumentError | |||
end | |||
rescue ArgumentError | |||
warn "Anna joko 'k' (kyllä) tai 'e' (ei)" | |||
retry | |||
end | |||
end | |||
end | |||
end | |||
arvaaLuku | |||
``` |
@ -0,0 +1,35 @@ | |||
## 1 Yksinkertainen luokka | |||
**Tehtävä:** | |||
Luvun ensimmäisessä tehtävässä harjoitellaan yksinkertaisesti luokan määrittelemistä. Tee ohjelmakoodi, joka määrittelee luokan Pelastaja, joka alustusvaiheessa tulostaa tekstin "Pelastaja on paikalla!". | |||
Tämän jälkeen kopioi seuraava ohjelmakoodi lähdekoodiisi; koodilla kokeillaan luokkamäärittelyn toimintaa: | |||
``` | |||
uusi = Pelastaja.new() | |||
``` | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Pelastaja on paikalla! | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
class Pelastaja | |||
def initialize | |||
puts "Pelastaja on paikalla!" | |||
end | |||
end | |||
uusi = Pelastaja.new() | |||
``` |
@ -0,0 +1,60 @@ | |||
## 2 Luokka joka tekee jotain | |||
**Tehtävä:** | |||
Toisessa tehtävässä jatketaan luokkien kanssa työskentelyä. Tällä kertaa tehtävänäsi on määritellä luokka Laatikko, jolle alustuksen yhteydessä luodaan jäsenmuuttuja sisus. | |||
Määrittele tälle jäsenmuuttujalle asettaja- ja palauttajametodit, sekä tee alustuksen yhteyteen mahdollisuus määritellä muuttujan arvo, asettaen oletusarvoksi "nil". | |||
Tämän jälkeen kopioi seuraava ohjelmakoodi lähdekoodiisi; koodilla kokeillaan luokkamäärittelyn toimintaa: | |||
``` | |||
Varasto = Laatikko.new() | |||
Varasto.sisus = "puuhapakki" | |||
puts "Varastossa on sisällä #{Varasto.sisus}." | |||
``` | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Varastossa on sisällä puuhapakki. | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
class Laatikko | |||
# alustaja | |||
def initialize(sisalto=nil) | |||
@sisus = sisalto | |||
end | |||
# Perinteinen tapa määrittää setter/getter-metodit jäsenmuuttujalle | |||
# | |||
# set-metodi | |||
# def sisus=(sisalto) | |||
# @sisus = sisalto | |||
# end | |||
# get-metodi | |||
# def sisus | |||
# @sisus | |||
# end | |||
# Tai yksinkertaisemmin Rubyn omia määritteitä käyttäen | |||
attr_accessor :sisus | |||
end | |||
Varasto = Laatikko.new() | |||
Varasto.sisus = "puuhapakki" | |||
puts "Varastossa on sisällä #{Varasto.sisus}." | |||
``` |
@ -0,0 +1,87 @@ | |||
## 3 Luokka, varaston laajentaminen | |||
**Tehtävä:** | |||
Tässä tehtävässä jatkamme toisessa tehtävässä luodun Laatikko-luokan kanssa työskentelyä. Lisää siis Laatikko-luokkaan seuraavat ominaisuudet: | |||
(1) Metodi nollaa, joka tyhjentää jäsenmuuttujan sisus asettamalla sen arvoksi tyhjän merkkijonon, sekä (2) lisää jäsenmuuttuja koko, joka saa alustuksessa arvokseen jäsenmuuttujan sisus pituuden, tai jos sitä ei määritellä, arvon 0. Lopuksi tee vielä (3) metodi suuri?, joka palauttaa arvon true jos koko on suurempi kuin 25 ja false jos pienempi kuin 25. | |||
Tämän jälkeen kopioi seuraava ohjelmakoodi lähdekoodiisi; koodilla kokeillaan luokkamäärittelyn toimintaa: | |||
``` | |||
Varasto = Laatikko.new() | |||
Varasto.sisus = "hirviömeikkilaukkutelinetukijalka" | |||
tulos = Varasto.suuri? | |||
puts "Kokotestin tulos oli: #{tulos}." | |||
Varasto.nollaa | |||
tulos = Varasto.suuri? | |||
puts "Kokotestin tulos oli: #{tulos}." | |||
``` | |||
Toimiessaan oikein ohjelma tulostaa seuraavaa: | |||
Example output: | |||
``` | |||
Kokotestin tulos oli: true. | |||
Kokotestin tulos oli: false. | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
class Laatikko | |||
# alustaja | |||
def initialize(sisalto=nil, koko=0) | |||
@sisus = sisalto | |||
if not @sisus.nil? then @koko = @sisus.length end | |||
end | |||
# set-metodi | |||
def sisus=(sisalto) | |||
@sisus = sisalto | |||
@koko = @sisus.length | |||
end | |||
# get-metodi | |||
def sisus | |||
@sisus | |||
end | |||
def nollaa | |||
@sisus = nil | |||
@koko = 0 | |||
end | |||
def suuri? | |||
# Tehtävänannossa on sanottu: | |||
# "palauttaa arvon true jos koko on suurempi | |||
# kuin 25 ja false jos pienempi kuin 25." | |||
# | |||
# Mitä tämän luokkametodin pitäisi palauttaa, | |||
# jos arvo on tasan 25? | |||
# Alla oleva implementaatio ei vastaa | |||
# tehtävänannon kuvausta kyseisin osin. | |||
#return @koko > 25 ? true : false | |||
# Tämä vastaa tehtävänannon määrittelyyn, | |||
# mutta ei ota kantaa, jos @koko == 25 | |||
# | |||
return true if @koko > 25 | |||
return false if @koko < 25 | |||
end | |||
end | |||
Varasto = Laatikko.new() | |||
Varasto.sisus = "hirviömeikkilaukkutelinetukijalka" | |||
tulos = Varasto.suuri? | |||
puts "Kokotestin tulos oli: #{tulos}." | |||
Varasto.nollaa | |||
tulos = Varasto.suuri? | |||
puts "Kokotestin tulos oli: #{tulos}." | |||
``` |
@ -0,0 +1,101 @@ | |||
## 4 Luokan perintä | |||
**Tehtävä:** | |||
Tässä tehtävässä harjoitellaan olemassaolevan luokan hyödyntämistä ohjelman tekemisessä ja luokan perinnässä. | |||
Ohjelmaa varten on määritelty tiedostoon "9-4b.rb" seuraava tiedonhallintaluokka: | |||
``` | |||
class Tietopankki | |||
def initialize(aseta = "ei tietoja") | |||
@tiedot = aseta | |||
end | |||
def muutatietoja(uusi) | |||
if uusi.length > 5 | |||
@tiedot = uusi | |||
else | |||
puts "Virheellinen syöte" | |||
end | |||
end | |||
def kerrotiedot | |||
print @tiedot | |||
end | |||
def poistatiedot | |||
@tiedot = "poistettu" | |||
end | |||
end | |||
``` | |||
Tehtävänäsi on tätä luokkaa apunakäyttäen luoda uusi luokka, jossa on metodi "tallennatiedot", joka kirjoittaa luokan tiedot-jäsenmuuttujan arvon tiedostoon 9-4_tiedosto.txt sekä metodi lataatiedot, joka lukee samannimisen tiedoston sisällön ja tallentaa sen muuttujaan. | |||
Anna luokalle nimeksi "LataavaTietopankki", ja toteuta metodit siten, että esimerkiksi tietojen lataamisyritys ilman tiedostoa ei aiheuta virhetilannetta, ja jos luettu tieto on alle 5 merkkiä, niin muuttujan arvoa ei vaihdeta. | |||
Tämän jälkeen kopioi seuraava ohjelmakoodi lähdekoodiisi; koodilla kokeillaan luokkamäärittelyn toimintaa: | |||
testi = LataavaTietopankki.new() | |||
testi.muutatietoja("Tietopankki on paras pankki.\nJa Lataava vielä parempi.\n") | |||
testi.kerrotiedot | |||
testi.lataatiedot | |||
testi.tallennatiedot | |||
Toimiessaan oikein ohjelma tulostaa seuraavan tekstin ja tallentaa sen tiedostoon 9-4_tiedosto.txt: | |||
Example output: | |||
``` | |||
Tietopankki on paras pankki. | |||
Ja Lataava vielä parempi. | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
require "./9-4b.rb" | |||
$_tiedosto = "9-4_tiedosto.txt" | |||
class LataavaTietopankki < Tietopankki | |||
def initialize(tiedosto = $_tiedosto) | |||
@tiedosto = tiedosto | |||
end | |||
def tallennatiedot | |||
if (!File.exists?(@tiedosto)) | |||
begin | |||
File.open(@tiedosto, File::RDWR|File::CREAT, 0644) | |||
rescue | |||
puts "Tiedostoon #{@tiedosto} ei voida kirjoittaa" | |||
Process.exit(1) | |||
end | |||
end | |||
if File.writable?(@tiedosto) | |||
File.write(@tiedosto, @tiedot) | |||
end | |||
end | |||
def lataatiedot | |||
if File.readable?(@tiedosto) | |||
@tiedot = File.read(@tiedosto) | |||
end | |||
end | |||
end | |||
testi = LataavaTietopankki.new() | |||
testi.muutatietoja("Tietopankki on paras pankki.\nJa Lataava vielä parempi.\n") | |||
testi.kerrotiedot | |||
testi.lataatiedot | |||
testi.tallennatiedot | |||
``` |
@ -0,0 +1,98 @@ | |||
## 5 Luokan muuttujat | |||
**Tehtävä:** | |||
Luvun viimeisessä tehtävässä harjoitellaan luokkamuuttujien käyttämistä. Tehtävänäsi on luoda luokka Elain, johon tallennettaan jotain perustietoja eri eläimistä. | |||
Määrittele luokkaan kaksi luokkamuuttujaa edellinen ja maara, jotka alustetaan arvoon "" ja 0. Tämän jälkeen tee luokkaan rakentaja, joka ottaa argumentteina kaksi merkkijonoa, rotu ja nimi. Oliota luotaessa edellisen luodun olion rotu tallenetaan luokkamuuttujaan edellinen. Luonnin yhteydessä maara-muuttuja kasvaa yhdellä. | |||
Luokkaan tulee myös kolme metodia, tiedot, poista ja tilanne. Tiedot-metodi tulostaa "Olen [olion rotu] ja nimeni on [olion nimi]". Poista tulostaa "[olion nimi] poistettu!" ja vähentää luokkamuuttujaa maara yhdellä. Tilanne tulostaa "Eläimiä on tällä hetkellä [maara] kappaletta. Viimeisin rekisteröity eläin oli [viimeisimmän luodun olion rotu].". | |||
Tämän jälkeen kopioi seuraava ohjelmakoodi lähdekoodiisi; koodilla kokeillaan luokkamäärittelyn toimintaa: | |||
``` | |||
koira = Elain.new("koira","Rekku") | |||
kissa = Elain.new("kissa","Raatelija") | |||
lintu = Elain.new("kanarialintu","Tirppa") | |||
koira.tiedot() | |||
kissa.poista() | |||
lintu.tilanne() | |||
``` | |||
Toimiessaan oikein ohjelma tulostaa seuraavan tekstin ja tallentaa sen tiedostoon 9-4_tiedosto.txt | |||
Example output: | |||
``` | |||
Olen koira ja nimeni on Rekku! | |||
Raatelija poistettu! | |||
Eläimiä on tällä hetkellä 2 kappaletta. | |||
Viimeisin rekisteröity eläin oli kanarialintu. | |||
``` | |||
**Vastaus** | |||
``` | |||
#!/usr/bin/env ruby | |||
# coding: utf-8 | |||
$_tiedosto = "9-4_tiedosto.txt" | |||
if (!File.exists?($_tiedosto)) | |||
begin | |||
File.open($_tiedosto, File::RDWR|File::CREAT, 0644) | |||
rescue | |||
puts "Tiedostoon #{$_tiedosto} ei voida kirjoittaa" | |||
Process.exit(1) | |||
end | |||
else | |||
File.open($_tiedosto, "w+") | |||
end | |||
########## | |||
class Elain | |||
@@edellinen = "" | |||
@@maara = 0 | |||
def initialize(rotu, nimi) | |||
@nimi = nimi | |||
@rotu = rotu | |||
@@edellinen = rotu | |||
@@maara += 1 | |||
end | |||
def tiedot | |||
lause = "Olen #{@rotu} ja nimeni on #{@nimi}!" | |||
puts lause; File.open($_tiedosto, "a").write(lause + "\n") | |||
end | |||
def poista | |||
lause = "#{@nimi} poistettu!" | |||
@@maara -= 1 | |||
puts lause; File.open($_tiedosto, "a").write(lause + "\n") | |||
# Ei välttämättä tarpeellinen... | |||
ObjectSpace.define_finalizer(self, self.class.method(:finalize)) | |||
end | |||
def tilanne | |||
lause = "Eläimiä on tällä hetkellä #{@@maara} kappaletta.\nViimeisin rekisteröity eläin oli #{@@edellinen}." | |||
puts lause; File.open($_tiedosto, "a").write(lause + "\n") | |||
end | |||
# Ei välttämättä tarpeellinen... | |||
def self.finalize(object_id) | |||
end | |||
end | |||
koira = Elain.new("koira","Rekku") | |||
kissa = Elain.new("kissa","Raatelija") | |||
lintu = Elain.new("kanarialintu","Tirppa") | |||
koira.tiedot() | |||
kissa.poista() | |||
lintu.tilanne() | |||
``` |
@ -1,3 +1,45 @@ | |||
# ruby-basics | |||
# Ruby basics | |||
Ruby fundamentals through coding exercises | |||
Ruby fundamentals through coding exercises. | |||
Contents of this repository are based on [Ruby programming course material](https://campusonline.fi/course/ruby-ohjelmointi) provided by Metropolia University of Applied Sciences. | |||
**NOTE**: Assignments and their descriptions are in Finnish for meanwhile. I have a plan to translate them to English. | |||
## Contents | |||
- [Fundamentals](src/branch/master/1_fundamentals) | |||
- Description: Ruby syntax and basic methods | |||
- [Data types](src/branch/master/2_datatypes) | |||
- Description: Different datatypes in Ruby | |||
- [Logical operators and conditions](src/branch/master/3_logical-operators-and-conditions) | |||
- Description: `if/else` statements & `case` structure in Ruby | |||
- [Loops](src/branch/master/4_loops) | |||
- Description: `for`, `while` and `until` loops in Ruby | |||
- [External files](src/branch/master/5_external-files) | |||
- Description: File operations in Ruby | |||
- [Methods](src/branch/master/6_methods) | |||
- Description: Custom methods in Ruby | |||
- [Modules](src/branch/master/7_modules) | |||
- Description: Custom modules in Ruby | |||
- [Errors and exceptions](src/branch/master/8_errors) | |||
- Description: Error and exception handling in Ruby | |||
- [Classes and objects](src/branch/master/9_classes-and-objects) | |||
- Description: Custom classes and objects in Ruby |