Pakolliset tehtävät on merkitty harmalla taustavärillä. Pakollisuus tarkoittaa oikeastaan hyvin voimakasta suositusta tehtävän tekemiseen. Jos pakollisia jää tekemättä, on suuri riski, että seuraavalla viikolla esitellään asioita jotka oletetetaan jo osatuiksi ja pakollisten tehtävien kautta harjoitelluiksi.
Tässä tehtäväsäsarjassa tehdään luokka LyyraKortti
,
jonka tarkoituksena on jäljitellä Lyyra-kortin käyttämistä Unicafessa.
Projektiin tulee kuulumaan kaksi kooditiedostoa:
Main.java
: pääohjelmaLyyraKortti.java
: luokka LyyraKortti
Kun luot projektin NetBeansissa,
anna projektin nimeksi (Project Name) LyyraKortti
ja pääluokan nimeksi (Main Class) Main
.
Lisää sitten projektiin uusi luokka painamalla
projektin nimestä hiiren oikealla napilla
vasemmalla olevasta projektilistasta ja
valitsemalla New->Java Class.
Anna luokan nimeksi (Class Name) LyyraKortti
.
Tee ensin LyyraKortti
-olion konstruktori,
jolle annetaan kortin alkusaldo ja
joka tallentaa sen olion sisäiseen muuttujaan.
Tee sitten toString
-metodi,
joka palauttaa kortin saldon muodossa "Kortilla on rahaa X euroa".
Seuraavassa on luokan LyyraKortti
runko:
public class LyyraKortti { private double saldo; public LyyraKortti(double alkusaldo) { // kirjoita koodia tähän } public String toString() { // kirjoita koodia tähän } }
Seuraava pääohjelma testaa luokkaa:
public class Main { public static void main(String[] args) { LyyraKortti kortti = new LyyraKortti(50); System.out.println(kortti); } }
Ohjelman tulisi tuottaa seuraava tulostus:
Kortilla on rahaa 50.0 euroa
Täydennä LyyraKortti
-luokkaa seuraavilla metodeilla:
public void syoEdullisesti() { // kirjoita koodia tähän } public void syoMaukkaasti() { // kirjoita koodia tähän }
Metodin syoEdullisesti
tulisi vähentää kortin saldoa 2,40 eurolla ja
metodin syoMaukkaasti
tulisi vähentää kortin saldoa 4,00 eurolla.
Seuraava pääohjelma testaa luokkaa:
public class Main { public static void main(String[] args) { LyyraKortti kortti = new LyyraKortti(50); System.out.println(kortti); kortti.syoEdullisesti(); System.out.println(kortti); kortti.syoMaukkaasti(); kortti.syoEdullisesti(); System.out.println(kortti); } }
Ohjelman tulisi tuottaa seuraava tulostus:
Kortilla on rahaa 50.0 euroa Kortilla on rahaa 47.6 euroa Kortilla on rahaa 41.2 euroa
Mitä tapahtuu, jos kortilta loppuu raha kesken?
Ei ole järkevää, että saldo muuttuu negatiiviseksi.
Muuta metodeita syoEdullisesti
ja syoMaukkaasti
niin,
että ne eivät vähennä saldoa, jos saldo menisi negatiiviseksi.
Seuraava pääohjelma testaa luokkaa:
public class Main { public static void main(String[] args) { LyyraKortti kortti = new LyyraKortti(5); System.out.println(kortti); kortti.syoMaukkaasti(); System.out.println(kortti); kortti.syoMaukkaasti(); System.out.println(kortti); } }
Ohjelman tulisi tuottaa seuraava tulostus:
Kortilla on rahaa 5.0 euroa Kortilla on rahaa 1.0 euroa Kortilla on rahaa 1.0 euroa
Siis toinen metodin syoMaukkaasti
kutsu ei
vaikuttanut saldoon, koska saldo olisi mennyt negatiiviseksi.
Lisää LyyraKortti
-luokkaan seuraava metodi:
public void lataaRahaa(double rahamaara) { // kirjoita koodia tähän }
Metodin tarkoituksena on kasvattaa kortin saldoa parametrina annetulla rahamäärällä. Kuitenkin kortin saldo saa olla korkeintaan 150 euroa, joten jos ladattava rahamäärä ylittäisi sen, saldoksi tulisi tulla silti tasan 150 euroa.
Seuraava pääohjelma testaa luokkaa:
public class Main { public static void main(String[] args) { LyyraKortti kortti = new LyyraKortti(10); System.out.println(kortti); kortti.lataaRahaa(15); System.out.println(kortti); kortti.lataaRahaa(10); System.out.println(kortti); kortti.lataaRahaa(200); System.out.println(kortti); } }
Ohjelman tulisi tuottaa seuraava tulostus:
Kortilla on rahaa 10.0 euroa Kortilla on rahaa 25.0 euroa Kortilla on rahaa 35.0 euroa Kortilla on rahaa 150.0 euroa
Tee pääohjelma, jossa luodaan kaksi LyyraKortti
-oliota:
yksi Pekalle (alkusaldo 20 euroa)
ja toinen Matille (alkusaldo 30 euroa).
Tee ohjelmassa seuraavat asiat:
Pääohjelman runko on seuraava:
public class Main { public static void main(String[] args) { LyyraKortti pekanKortti = new LyyraKortti(20); LyyraKortti matinKortti = new LyyraKortti(30); // kirjoita koodia tähän } }
Ohjelman tulisi tuottaa seuraava tulostus:
Pekka: Kortilla on rahaa 16.0 euroa Matti: Kortilla on rahaa 27.6 euroa Pekka: Kortilla on rahaa 36.0 euroa Matti: Kortilla on rahaa 23.6 euroa Pekka: Kortilla on rahaa 31.200000000000003 euroa Matti: Kortilla on rahaa 73.6 euroa
Tosielämässä kortin saldon tallennus
double
-muuttujaan ei olisi hyvä idea,
koska double
-arvoissa esiintyy
pyöristysvirheitä.
Sellainen esiintyy jopa yllä olevassa esimerkissä:
Pekan kortilla kuuluisi olla lopuksi 31,2 euroa,
mutta siellä onkin muka 31,200000000000003 euroa.
Yksi ratkaisu ongelmaan on käyttää
double
-muuttujan sijasta
int
-muuttujaa ja tallentaa
rahamäärä sentteinä.
Tee tarvittavat muutokset luokkaan.
Tässä tehtävässä tehdään luokka YlhaaltaRajoitettuLaskuri
ja sovelletaan sitä kellon tekemiseen.
Tehdään luokka YlhaaltaRajoitettuLaskuri
.
Luokan olioilla on seuraava toiminnallisuus:
seuraava
kasvattaa laskurin arvoa.
Mutta jos laskurin arvo ylittää ylärajan, sen arvoksi tulee 0.toString
palauttaa laskurin arvon merkkijonona.Tee projektiin luokat Main
ja
YlhaaltaRajoitettuLaskuri
vastaavasti kuin tehtävässä 1.1.
Näin tehdään myös tulevissa tehtäväsarjoissa.
Luokan runko on siis seuraava:
public class YlhaaltaRajoitettuLaskuri { private int laskuri; private int ylaraja; public YlhaaltaRajoitettuLaskuri(int ylarajanAlkuarvo) { // kirjoita koodia tähän } public void seuraava() { // kirjoita koodia tähän } public String toString() { // kirjoita koodia tähän } }
Vihje: et voi palauttaa toStringissä suoraan kokonaislukutyyppisen oliomuuttujan laskuri
arvoa. Kokonaislukumuuttujasta x
saa merkkijonomuodon esim. lisäämällä sen eteen tyhjän merkkijonon eli kirjoittamalla ""+x
.
Seuraavassa on pääohjelma, joka käyttää laskuria:
public class Main { public static void main(String[] args) { YlhaaltaRajoitettuLaskuri laskuri = new YlhaaltaRajoitettuLaskuri(4); System.out.println("arvo alussa: " + laskuri ); for ( int i=0; i < 10; i++ ){ laskuri.seuraava(); System.out.println("arvo: " + laskuri ); } } }
Laskurille asetetaan ylärajaksi konstruktorissa 4,
joten laskurin arvo on luku 0:n ja 4:n väliltä.
Huomaa, miten metodi seuraava
vie laskurin arvoa eteenpäin,
kunnes se pyörähtää 4:n jälkeen 0:aan:
Ohjelman tulostuksen tulisi olla seuraava:
arvo alussa: 0 arvo: 1 arvo: 2 arvo: 3 arvo: 4 arvo: 0 arvo: 1 arvo: 2 arvo: 3 arvo: 4 arvo: 0
Tee toString
-metodista sellainen,
että se lisää arvon merkkijonoesitykseen etunollan,
jos laskurin arvo on vähemmän kuin 10.
Eli jos laskurin arvo on esim. 3,
palautetaan merkkijono "03",
jos arvo taas on esim. 12,
palautetaan normaaliin tapaan merkkijono "12".
Muuta pääohjelma seuraavaan muotoon ja varmista, että tulos on haluttu.
public class Main { public static void main(String[] args) { YlhaaltaRajoitettuLaskuri laskuri = new YlhaaltaRajoitettuLaskuri(14); System.out.println("arvo alussa: " + laskuri ); for ( int i=0; i < 16; i++ ){ laskuri.seuraava(); System.out.println("arvo: " + laskuri ); } } }
arvo alussa: 00 arvo: 01 arvo: 02 arvo: 03 arvo: 04 arvo: 05 arvo: 06 arvo: 07 arvo: 08 arvo: 09 arvo: 10 arvo: 11 arvo: 12 arvo: 13 arvo: 14 arvo: 00 arvo: 01
Käyttämällä kahta laskuria voimme muodostaa kellon. Tuntimäärä on laskuri, jonka yläraja on 23, ja minuuttimäärä on laskuri jonka yläraja on 59. Kuten kaikki tietävät, kello toimii siten, että aina kun minuuttimäärä pyörähtää nollaan, tuntimäärä kasvaa yhdellä.
Tee ensin laskurille metodi arvo
,
joka palauttaa laskurin arvon:
public int arvo() { // kirjoita koodia tähän }
Tee sitten kello täydentämällä seuraava pääohjelmarunko:
public class Main { public static void main(String[] args) { YlhaaltaRajoitettuLaskuri minuutit = new YlhaaltaRajoitettuLaskuri(59); YlhaaltaRajoitettuLaskuri tunnit = new YlhaaltaRajoitettuLaskuri(23); for ( int i=0; i < 121; i++) { System.out.println( tunnit + ":" + minuutit); // tulostetaan nykyinen aika // minuuttimäärä kasvaa // jos minuuttimäärä menee nollaan, tuntimäärä kasvaa } } }
Jos kellosi toimii oikein, sen tulostus näyttää suunnilleen seuraavalta:
00:00 00:01 ... 00:59 01:00 01:01 01:02 ... 01:59 02:00
Varmista, että kellosi siirtyy näyttämään keskiyöllä aikaa 00:00.
Laajenna kelloasi myös sekuntiviisarilla.
Tee myös laskurille metodi asetaArvo
,
jolla laskurille pystyy asettamaan halutun arvon.
Tämän metodin avulla voit muuttaa kellon ajan
heti ohjelman alussa haluamaksesi.
Laita kellosi alkamaan ajasta 23:59:50 ja varmista, että vuorokauden vaihteessa kello toimii odotetusti.
Voit testata kellon toimintaa seuraavalla ohjelmalla
public class Main { public static void main(String[] args) throws Exception { YlhaaltaRajoitettuLaskuri sekunnit = new YlhaaltaRajoitettuLaskuri(59); YlhaaltaRajoitettuLaskuri minuutit = new YlhaaltaRajoitettuLaskuri(59); YlhaaltaRajoitettuLaskuri tunnit = new YlhaaltaRajoitettuLaskuri(23); sekunnit.asetaArvo(50); minuutit.asetaArvo(59); tunnit.asetaArvo(23); while ( true) { System.out.println( tunnit + ":" + minuutit + ":" + sekunnit); Thread.sleep(1000); // lisää kellon aikaa sekunnilla eteenpäin } } }
Nyt kello käy ikuisesti ja kasvattaa arvoaan sekunnin välein.
Sekunnin odotus tapahtuu komennolla Thread.sleep(1000);
.
Jotta komento toimisi, pitää main:in esittelyriville tehdä pieni lisäys:
public static void main(String[] args) throws Exception {
,
eli tummennettuna oleva throws Exception
.
Tärkeitä kommentteja liittyen olioiden käyttöön. Lue nämä ehdottomasti.
Olio-ohjelmoinnissa on kyse pitkälti käsitteiden eristämisestä omaksi kokonaisuudekseen tai toisin ajatellen
abstraktioiden muodostamisesta. Voisi ajatella, että on turha luoda oliota jonka sisällä on ainoastaan luku,
eli että saman voisi tehdä suoraan int-muuttujilla. Asia ei kuitenkaan ole näin. Jos kello koostuu pelkästään
kolmesta int-muuttujasta joita kasvatellaan, muuttuu ohjelma lukijan kannalta epäselvemmäksi,
koodista on vaikea "nähdä" mistä on kysymys. Aiemmin materiaalissa mainitsimme jo kokeneen ja kuuluisan
ohjelmoijan Kent Beckin neuvon
"Any fool can write code that a computer can understand. Good programmers write code that humans can understand",
eli koska viisari on oikeastaan oma selkeä käsitteensä, on siitä ohjelman ymmärrettävyyden parantamiseksi hyvä tehdä oma
luokka, eli YlhaaltaRajoitettuLaskuri
.
Käsitteen erottaminen omaksi luokaksi on monellakin tapaa hyvä idea. Ensinnäkin tiettyjä yksityiskohtia
(esim. laskurin pyörähtäminen) saadaan piilotettua luokan sisään (eli abstrahoitua). Sen sijaan että
kirjoitetaan if-lause ja sijoitusoperaatio, riittää, että laskurin käyttäjä kutsuu selkeästi nimettyä
metodia seuraava()
. Aikaansaatu laskuri sopii kellon lisäksi ehkä muidenkin ohjelmien
rakennuspalikaksi, eli selkeästä käsitteestä tehty luokka voi olla monikäyttöinen. Suuri etu saavutetaan
myös sillä, että koska laskurin toteutuksen yksityiskohdat eivät näy laskurin käyttäjille, voidaan yksityiskohtia tarvittaessa muuttaa.
Totesimme että kello sisältää kolme viisaria, eli koostuu kolmesta käsitteestä. Oikeastaan kello on itsekin käsite ja teemme ensi viikolla luokan Kello, jotta voimme luoda selkeitä Kello-olioita. Kello tulee siis olemaan olio jonka toiminta perustuu "yksinkertaisimpiin" olioihin eli viisareihin. Tämä on juuri olio-ohjelmoinnin suuri idea: ohjelma rakennetaan pienistä selkeistä yhteistoiminnassa olevista olioista.
Nyt otamme varovaisia ensiaskelia oliomaailmassa. Huhtikuun lopussa oliot alkavat kuitenkin olla jo selkärangassa ja nyt ehkä käsittämättömältä tuntuva lausahdus, ohjelma rakennetaan pienistä selkeistä yhteistoiminnassa olevista olioista alkaa tuntua meistä ehkä järkeenkäyvältä ja itsestäänselvältä.
Lisää luokkaan LyyraKortti
uusi konstruktori,
jolla ei ole parametreja. Tässä tapauksessa
kortin aloitussaldon tulisi olla 20 euroa.
Kutsu uudessa konstruktorissa alkuperäistä konstruktoria
sopivalla tavalla.
Seuraava pääohjelma testaa luokkaa:
public class Main { public static void main(String[] args) { LyyraKortti kortti1 = new LyyraKortti(); System.out.println(kortti1); LyyraKortti kortti2 = new LyyraKortti(30); System.out.println(kortti2); } }
Ohjelman tulisi tuottaa seuraava tulostus:
Kortilla on rahaa 20.0 euroa Kortilla on rahaa 30.0 euroa
Metodien syoEdullisesti
ja syoMaukkaasti
ongelmana on, että niissä on samantapainen tarkistus sen varalta,
että kortin saldo uhkaa mennä negatiiviseksi.
Olisi hauskempaa, jos tarkistus olisi vain yhdessä paikassa.
Tee uusi metodi vahennaSaldoa
,
jonka tehtävänä on vähentää kortin saldoa annetulla rahamäärällä.
Metodin runko on seuraava:
private void vahennaSaldoa(double rahamaara) { // kirjoita koodia tähän }
Tee tämäkin metodi niin, että metodi ei muuta saldoa, jos saldo menisi negatiiviseksi.
Toteuta nyt metodit syoEdullisesti
ja
syoMaukkaasti
niin, että ne kutsuvat metodia
vahennaSaldoa
. Nyt negatiivisen saldon
tarkistus on vain yhdessä paikassa luokassa.
Muista myös testata, että metodit toimivat tämän muutoksen jälkeen.
Tee luokka Lukutilasto
, joka tuntee seuraavat toiminnot:
lisaaLuku
lisää uuden luvun tilastoon
haeMaara
kertoo lisättyjen lukujen määrän
Luokan ei tarvitse tallentaa mihinkään lisättyjä lukuja,
vaan riittää muistaa niiden määrä.
Metodin lisaaLuku
ei tässä vaiheessa
tarvitse edes ottaa huomioon,
mikä luku lisätään tilastoon,
koska ainoa tallennettava asia on lukujen määrä.
Luokan runko on seuraava:
public class Lukutilasto { private int maara; public Lukutilasto() { // alusta tässä muuttuja maara } public void lisaaLuku(int luku) { // kirjoita koodia tähän } public int haeMaara() { // kirjoita koodia tähän } }
Seuraava ohjelma esittelee luokan käyttöä:
public class Main { public static void main(String[] args) { Lukutilasto tilasto = new Lukutilasto(); tilasto.lisaaLuku(3); tilasto.lisaaLuku(5); tilasto.lisaaLuku(1); tilasto.lisaaLuku(2); System.out.println("Määrä: " + tilasto.haeMaara()); } }
Ohjelman tulostus on seuraava:
Määrä: 4
Laajenna luokkaa seuraavilla toiminnoilla:
haeSumma
kertoo lisättyjen lukujen summan
haeKeskiarvo
kertoo lisättyjen lukujen keskiarvon
Luokan runko on seuraava:
public class Lukutilasto { private int maara; private int summa; public Lukutilasto() { // alusta tässä muuttujat maara ja summa } public void lisaaLuku(int luku) { // kirjoita koodia tähän } public int haeMaara() { // kirjoita koodia tähän } public int haeSumma() { // kirjoita koodia tähän } public double haeKeskiarvo() { // kirjoita koodia tähän } }
Seuraava ohjelma esittelee luokan käyttöä:
public class Main { public static void main(String[] args) { Lukutilasto tilasto = new Lukutilasto(); tilasto.lisaaLuku(3); tilasto.lisaaLuku(5); tilasto.lisaaLuku(1); tilasto.lisaaLuku(2); System.out.println("Määrä: " + tilasto.haeMaara()); System.out.println("Summa: " + tilasto.haeSumma()); System.out.println("Keskiarvo: " + tilasto.haeKeskiarvo()); } }
Ohjelman tulostus on seuraava:
Määrä: 4 Summa: 11 Keskiarvo: 2.75
Tee ohjelma, joka kysyy lukuja käyttäjältä, kunnes käyttäjä antaa luvun -1. Sitten ohjelma ilmoittaa lukujen summan.
Käytä ohjelmassa luokkaa Lukutilasto
summan laskemiseen.
Anna lukuja: 4 2 5 4 -1 Summa: 15
Muuta edellistä ohjelmaa niin, että ohjelma laskee erikseen parillisten ja parittomien lukujen summaa.
Määrittele ohjelmassa kaksi
oliota luokasta Lukutilasto
:
toinen laskee parillisten lukujen summan ja
toinen laskee parittomien lukujen summan.
Anna lukuja: 4 2 5 2 -1 Parillisten summa: 8 Parittomien summa: 5
Tee ohjelma, joka kysyy käyttäjältä alarajan ja ylärajan. Tämän jälkeen ohjelma arpoo luvun alarajan ja ylärajan välillä.
Ohjelmassa kannattaa käyttää Random
-luokan
metodia nextInt(n)
, joka arpoo
luvun väliltä 0...n - 1. Mieti, miten voit arpoa
tämän metodin avulla luvun väliltä a...b.
Esimerkiksi seuraavassa esimerkissä ohjelma arpoo luvun väliltä 81...85.
Anna alaraja: 81 Anna yläraja: 85 Satunnaisluku: 82
Tee luokka Arpoja
, josta luodun olion avulla
voi arpoa lukuja tietyltä lukuväliltä.
Luokan runko on seuraava:
import java.util.*; public class Arpoja { private int alaraja; private int ylaraja; private Random arpoja = new Random(); public Arpoja(int alaraja, int ylaraja) { // kirjoita koodia tähän } public int arvoLuku() { // kirjoita koodia tähän } }
Luokkaa käytetään seuraavasti pääohjelmassa:
public class Main { public static void main(String[] args) { Arpoja noppa = new Arpoja(1, 6); System.out.println("Kolme nopanheittoa:"); System.out.println(noppa.arvoLuku()); System.out.println(noppa.arvoLuku()); System.out.println(noppa.arvoLuku()); } }
Ohjelman tulostus voi olla seuraava:
Kolme nopanheittoa: 5 2 6
Tee ohjelma, joka heittää noppaa miljoona kertaa ja
tulostaa eri tulosten lukumäärät.
Käytä ohjelmassa äsken tehtyä Arpoja
-luokkaa.
Tämän ohjelman avulla voi tarkistaa, että arvonta toimii halutulla tavalla (nopan kaikkia silmälukuja tulee suunnilleen yhtä paljon).
Ohjelman tulostus voi olla seuraava:
1: 166410 kpl 2: 166565 kpl 3: 166700 kpl 4: 166870 kpl 5: 166894 kpl 6: 166561 kpl
Tässä tehtäväsarjassa tehdään tekoäly kivi, paperi, sakset -peliin.
Tee luokka KPSTekoaly
,
josta tulee tekoäly kivi, paperi, sakset -peliin.
Luokkaan tulee metodi teeSiirto
,
joka palauttaa tekoälyn tekemän siirron.
Merkkijonot "k"
, "p"
ja "s"
vastaavat siirtoja kivi, paperi ja sakset.
Tee tekoälystä ensin sellainen, että sen siirto on aina kivi.
Luokan runko on seuraava:
import java.util.*; public class KPSTekoaly { public String teeSiirto() { // kirjoita koodia tähän } }
Pääluokka näyttää seuraavalta:
import java.util.Scanner; public class Main { private static Scanner lukija = new Scanner(System.in); public static void main(String[] args) { KPSTekoaly tekoaly = new KPSTekoaly(); System.out.print("Kuinka monta kierrosta? "); int kierrokset = Integer.parseInt(lukija.nextLine()); for (int i = 0; i < kierrokset; i++) { System.out.print("Anna siirto (k, p tai s): "); String pelaajanSiirto = lukija.nextLine(); String tekoalynSiirto = tekoaly.teeSiirto(); System.out.println("Pelaajan siirto: " + pelaajanSiirto); System.out.println("Tekoälyn siirto: " + tekoalynSiirto); } } }
Peli voi edetä esimerkiksi seuraavasti:
Kuinka monta kierrosta? 3 Anna siirto (k, p tai s): s Pelaajan siirto: s Tekoälyn siirto: k Anna siirto (k, p tai s): p Pelaajan siirto: p Tekoälyn siirto: k Anna siirto (k, p tai s): k Pelaajan siirto: k Tekoälyn siirto: k
Lisää projektiin vielä yksi luokka KPSTuomari
,
jonka runko on seuraava:
public class KPSTuomari { public void maaritaVoittaja(String pelaajanSiirto, String tekoalynSiirto) { // kirjoita koodia tähän } }
Metodin maaritaVoittaja
tarkoituksena
on selvittää pelaajan ja tekoälyn siirtojen perusteella,
kumpi on voittaja vai tuliko tasapeli.
Toteuta metodi niin, että se tulostaa tiedon voittajasta.
Kivi, paperi, sakset -pelissä kivi voittaa sakset, sakset voittavat paperin ja paperi voittaa kiven.
Pääluokka on nyt seuraava:
import java.util.Scanner; public class Main { private static Scanner lukija = new Scanner(System.in); public static void main(String[] args) { KPSTekoaly tekoaly = new KPSTekoaly(); KPSTuomari tuomari = new KPSTuomari(); System.out.print("Kuinka monta kierrosta? "); int kierrokset = Integer.parseInt(lukija.nextLine()); for (int i = 0; i < kierrokset; i++) { System.out.print("Anna siirto (k, p tai s): "); String pelaajanSiirto = lukija.nextLine(); String tekoalynSiirto = tekoaly.teeSiirto(); System.out.println("Tekoälyn siirto: " + tekoalynSiirto); tuomari.maaritaVoittaja(pelaajanSiirto, tekoalynSiirto); } } }
Peli voi edetä esimerkiksi seuraavasti:
Kuinka monta kierrosta? 3 Anna siirto (k, p tai s): s Tekoälyn siirto: k Tekoäly voitti! Anna siirto (k, p tai s): p Tekoälyn siirto: k Pelaaja voitti! Anna siirto (k, p tai s): k Tekoälyn siirto: k Tuli tasapeli!
Nyt on aika tehdä tekoälystä parempi, koska ei ole järkevää, että tekoäly valitsee aina kiven.
Tee tekoälystä satunnainen: se valitsee yhtä todennäköisesti kiven, saksen ja paperin.
Laajenna tuomariluokkaa niin,
että se pitää kirjaa pelaajan ja tekoälyn voitoista.
Lisää luokkaan myös metodi tulostaTilasto
,
joka tulostaa tilaston voitoista.
Lisää tämän metodin kutsu pääohjelman loppuun.
Kuinka monta kierrosta? 5 Anna siirto (k, p tai s): s Tekoälyn siirto: s Tuli tasapeli! Anna siirto (k, p tai s): p Tekoälyn siirto: s Tekoäly voitti! Anna siirto (k, p tai s): k Tekoälyn siirto: k Tuli tasapeli! Anna siirto (k, p tai s): s Tekoälyn siirto: p Pelaaja voitti! Anna siirto (k, p tai s): s Tekoälyn siirto: k Tekoäly voitti! Tilasto: Pelaaja: 1 voittoa Tekoäly: 2 voittoa
Lisää tekoälyyn muisti: tekoäly ottaa siirtonsa valinnassa huomioon, mitä käyttäjä on valinnut aiemmin eri tilanteissa. Päätä itse, millä tavoin tarkalleen tekoäly hyödyntää muistia.
Lisää tekoälyyn metodi kirjaaSiirto
,
jota kutsutaan käyttäjän siirron jälkeen.
Sen avulla tekoäly saa tietoonsa,
mitä siirtoja käyttäjä on tehnyt.
Pääluokkaan tehdään seuraava muutos:
... String pelaajanSiirto = lukija.nextLine(); String tekoalynSiirto = tekoaly.teeSiirto(); tekoaly.kirjaaSiirto(pelaajanSiirto); System.out.println("Tekoälyn siirto: " + tekoalynSiirto); ...
Jos tekoäly käyttää muistiaan hyvin, se voi sopeutua esimerkiksi tilanteeseen, jossa käyttäjä valitsee aina saman siirron:
Kuinka monta kierrosta? 5 Anna siirto (k, p tai s): s Tekoälyn siirto: p Pelaaja voitti! Anna siirto (k, p tai s): s Tekoälyn siirto: k Tekoäly voitti! Anna siirto (k, p tai s): s Tekoälyn siirto: k Tekoäly voitti! Anna siirto (k, p tai s): s Tekoälyn siirto: k Tekoäly voitti! Anna siirto (k, p tai s): s Tekoälyn siirto: k Tekoäly voitti! Tilasto Pelaaja: 1 voittoa Tekoäly: 4 voittoa