Browse Source

Initial commit

master
Pekka Helenius 4 years ago
parent
commit
ecbcedc6e6
45 changed files with 2944 additions and 2 deletions
  1. +23
    -0
      1_fundamentals/1_hello-world.md
  2. +30
    -0
      1_fundamentals/2_variables-and-printing.md
  3. +37
    -0
      1_fundamentals/3_string-to-binary.md
  4. +33
    -0
      1_fundamentals/4_rounding.md
  5. +26
    -0
      1_fundamentals/5_random-integers.md
  6. +26
    -0
      2_datatypes/1_string-merging.md
  7. +23
    -0
      2_datatypes/2_string-editing.md
  8. +40
    -0
      2_datatypes/3_splitting.md
  9. +39
    -0
      2_datatypes/4_array-editing.md
  10. +35
    -0
      2_datatypes/5_array-and-strings.md
  11. +77
    -0
      3_logical-operators-and-conditions/1_input-calculator.md
  12. +83
    -0
      3_logical-operators-and-conditions/2_selections.md
  13. +52
    -0
      3_logical-operators-and-conditions/3_string-generation.md
  14. +61
    -0
      3_logical-operators-and-conditions/4_random-string.md
  15. +89
    -0
      3_logical-operators-and-conditions/5_minigame.md
  16. +47
    -0
      4_loops/1_exponents.md
  17. +75
    -0
      4_loops/2_input-calculator.md
  18. +65
    -0
      4_loops/3_number-seeking.md
  19. +51
    -0
      4_loops/4_fibonacci.md
  20. +66
    -0
      4_loops/5_item-listing.md
  21. +47
    -0
      5_external-files/1_reading-file.md
  22. +66
    -0
      5_external-files/2_writing-file.md
  23. +101
    -0
      5_external-files/3_charcounter.md
  24. +65
    -0
      5_external-files/4_string-matches.md
  25. +92
    -0
      5_external-files/5_string-gen-to-file.md
  26. +52
    -0
      6_methods/1_simple-method.md
  27. +48
    -0
      6_methods/2_arguments-return.md
  28. +125
    -0
      6_methods/3_replacer.md
  29. +66
    -0
      6_methods/4_palindrome.md
  30. +57
    -0
      6_methods/5_default-values.md
  31. +77
    -0
      7_modules/1_prime-numbers.md
  32. +120
    -0
      7_modules/2_content-organizer.md
  33. +104
    -0
      7_modules/3_passwd-gen.md
  34. +75
    -0
      7_modules/4_custom-module.md
  35. +85
    -0
      7_modules/5_filter-regex.md
  36. +48
    -0
      8_errors/1_filereader.md
  37. +125
    -0
      8_errors/2_calculator.md
  38. +110
    -0
      8_errors/3_morse-translator.md
  39. +78
    -0
      8_errors/4_number-guessing-game.md
  40. +35
    -0
      9_classes-and-objects/1_simple-class.md
  41. +60
    -0
      9_classes-and-objects/2_another-class.md
  42. +87
    -0
      9_classes-and-objects/3_object-behavior.md
  43. +101
    -0
      9_classes-and-objects/4_class-inheritance.md
  44. +98
    -0
      9_classes-and-objects/5_class-and-instance-vars.md
  45. +44
    -2
      README.md

+ 23
- 0
1_fundamentals/1_hello-world.md View File

@ -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!"
```

+ 30
- 0
1_fundamentals/2_variables-and-printing.md View File

@ -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
```

+ 37
- 0
1_fundamentals/3_string-to-binary.md View File

@ -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)
```

+ 33
- 0
1_fundamentals/4_rounding.md View File

@ -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)
```

+ 26
- 0
1_fundamentals/5_random-integers.md View File

@ -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)
```

+ 26
- 0
2_datatypes/1_string-merging.md View File

@ -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()
```

+ 23
- 0
2_datatypes/2_string-editing.md View File

@ -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
```

+ 40
- 0
2_datatypes/3_splitting.md View File

@ -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]
)
```

+ 39
- 0
2_datatypes/4_array-editing.md View File

@ -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
```

+ 35
- 0
2_datatypes/5_array-and-strings.md View File

@ -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
```

+ 77
- 0
3_logical-operators-and-conditions/1_input-calculator.md View File

@ -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))
```

+ 83
- 0
3_logical-operators-and-conditions/2_selections.md View File

@ -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
```

+ 52
- 0
3_logical-operators-and-conditions/3_string-generation.md View File

@ -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
```

+ 61
- 0
3_logical-operators-and-conditions/4_random-string.md View File

@ -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}"
```

+ 89
- 0
3_logical-operators-and-conditions/5_minigame.md View File

@ -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
```

+ 47
- 0
4_loops/1_exponents.md View File

@ -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
```

+ 75
- 0
4_loops/2_input-calculator.md View File

@ -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
```

+ 65
- 0
4_loops/3_number-seeking.md View File

@ -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
```

+ 51
- 0
4_loops/4_fibonacci.md View File

@ -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
```

+ 66
- 0
4_loops/5_item-listing.md View File

@ -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
```

+ 47
- 0
5_external-files/1_reading-file.md View File

@ -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.
```

+ 66
- 0
5_external-files/2_writing-file.md View File

@ -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ä.
```

+ 101
- 0
5_external-files/3_charcounter.md View File

@ -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", "ää"])
```

+ 65
- 0
5_external-files/4_string-matches.md View File

@ -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")
```

+ 92
- 0
5_external-files/5_string-gen-to-file.md View File

@ -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])
)
```

+ 52
- 0
6_methods/1_simple-method.md View File

@ -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)
```

+ 48
- 0
6_methods/2_arguments-return.md View File

@ -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"] ))
```

+ 125
- 0
6_methods/3_replacer.md View File

@ -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))
```

+ 66
- 0
6_methods/4_palindrome.md View File

@ -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
```

+ 57
- 0
6_methods/5_default-values.md View File

@ -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
```

+ 77
- 0
7_modules/1_prime-numbers.md View File

@ -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
```

+ 120
- 0
7_modules/2_content-organizer.md View File

@ -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)
```

+ 104
- 0
7_modules/3_passwd-gen.md View File

@ -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])
```

+ 75
- 0
7_modules/4_custom-module.md View File

@ -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
```

+ 85
- 0
7_modules/5_filter-regex.md View File

@ -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
```

+ 48
- 0
8_errors/1_filereader.md View File

@ -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
```

+ 125
- 0
8_errors/2_calculator.md View File

@ -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
```

+ 110
- 0
8_errors/3_morse-translator.md View File

@ -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:--..
```

+ 78
- 0
8_errors/4_number-guessing-game.md View File

@ -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
```

+ 35
- 0
9_classes-and-objects/1_simple-class.md View File

@ -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()
```

+ 60
- 0
9_classes-and-objects/2_another-class.md View File

@ -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}."
```

+ 87
- 0
9_classes-and-objects/3_object-behavior.md View File

@ -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}."
```

+ 101
- 0
9_classes-and-objects/4_class-inheritance.md View File

@ -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
```

+ 98
- 0
9_classes-and-objects/5_class-and-instance-vars.md View File

@ -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()
```

+ 44
- 2
README.md View File

@ -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

Loading…
Cancel
Save