INF1010 våren 2006 Uke 19: 9. mai 2006 Et større eksempel: Solitaire (kabal)

Like dokumenter
INF1010 Grafisk brukergrensesni3 med Swing og awt del 1 INF1010

INF1010 våren mai 2005 Et større eksempel: kabal (solitaire)

UNIVERSITETET I OSLO

import javax.swing.*; import java.awt.*;

Grafisk Brukergrensesnitt

INF1010. Grafisk brukergrensesni. med Swing og awt del 2. INF Grafisk brukergrensesni4 II

LO191D/LC191D Videregående programmering

HØGSKOLEN I SØR-TRØNDELAG Avdeling for informatikk og e-læring AITeL

Gjennomgang av eksamen H99

6108 Programmering i Java. Leksjon 8. GUI: Grafisk brukergrensesnitt. Del 2: Roy M. Istad 2015

INF Våren Li' repe$sjon om Tråder og GUI. Stein Gjessing, Ins$tu' for informa$kk, Universitetet i Oslo. Ins$tu' for informa$kk

Uke mars 2005 GUI - del 2. GUI (Graphical User Interface)-programmering

Inf 1010 GUI - del 2

Vi lærte sist å lage vinduer. Om å lage et vindu. GUI (Graphical User Interface)-programmering. Inf GUI - del 2

Grafiske brukergrensesnitt med Swing og AWT

4. mars 2008 Grafisk brukergrensesnitt med Swing og awt Litt Modell Utsyn - Kontroll Del I. Stein Gjessing Inst for Informatikk Univ.

Om Grafiske Bruker-Grensesnitt (GUI) Hvordan gjør vi det: To måter. GUI (Graphical User Interface)-programmering

JPanel. Komponent hieraki. Window/JWindow. Applet/JApplet. JDialog. JFrame

Om Grafiske Bruker-Grensesnitt (GUI) Hvordan gjør vi det: To måter. GUI (Graphical User Interface)-programmering. del 1. Litt Modell Utsyn - Kontroll

GUI - del 2. Stein Gjessing Inst for Informatikk Univ. i Oslo

INF1010. Grafisk brukergrensesni. med Swing og awt del 2

Inf mars 2010 GUI del 2

INF1010 Grafisk brukergrensesni3 (GUI) med Swing/awt. del 1

INF1010 MVC i tekstbaserte programmer

INF1010 våren 2008 Uke 4, 22. januar Arv og subklasser

INF Notater. Veronika Heimsbakk 10. juni 2012

UNIVERSITETET I OSLO Det matematisk-naturvitenskapelige fakultet

Vi lærte sist å lage vinduer. Om å lage et vindu. GUI (Graphical User Interface)-programmering. GUI - del 2

1- og 2-veis Innkapsling Java Stabel Kø Prio-kø Iterator. Enveis- og toveislister Innkapsling («boxing») (Big Java 6.8.5)

Lenkelister. Lister og køer. Kopi av utvalgte sider fra forelesningen.

En implementasjon av binærtre. Dagens tema. Klassestruktur hovedstruktur abstract class BTnode {}

Dagens tema INF1010 INF1010 INF1010 INF1010

1- og 2-veis Innkapsling Java Stabel Kø Prio-kø Iterator. Enveis- og toveislister Innkapsling («boxing») (Big Java 6.8.5)

Repitisjonskurs. Arv, Subklasser og Grensesnitt

INF1010 LISTER. Listeelementer og listeoperasjoner. Foran. Bak

EKSAMEN. TILLATTE HJELPEMIDLER: Alle trykte og skrevne. INNFØRING MED PENN, evt. trykkblyant som gir gjennomslag

AVDELING FOR INGENIØRUTDANNING EKSAMENSOPPGAVE

INF1010. Grensesnittet Comparable<T>

AVDELING FOR INGENIØRUTDANNING EKSAMENSOPPGAVE

UNIVERSITETET I BERGEN Det matematisk-naturvitenskapelige fakultet

UNIVERSITETET I OSLO

Kapittel 15: Grafiske brukergrensesnitt. Del II

ANTDAGER = 358; I Ifra nyttår 08 til 08 1ed julaften

INF100 Institutt for informatikk Universitetet i Bergen Øving 5

Hva er verdien til variabelen j etter at følgende kode er utført? int i, j; i = 5; j = 10; while ( i < j ) { i = i + 2; j = j - 1; }

INF 1010, vår 2005 Løsningsforslag uke 10

TDT4100 Objektorientert programmering

INF1010 våren januar. Objektorientering i Java

INF1010, 22. mai Prøveeksamen (Eksamen 12. juni 2012) Stein Gjessing Inst. for Informatikk Universitetet i Oslo

UNIVERSITETET I OSLO

INF Seminaroppgaver til uke 3

INF1010 Sortering. Marit Nybakken 1. mars 2004

INF1010 våren Arv og subklasser del 1

INF1010 våren Arv og subklasser del 1

Eks 1: Binærtre Binærtretraversering Eks 2: Binærtre og stakk

Inf1010 oppgavesamling

Eksekveringsrekkefølgen (del 1) Oppgave 1. Eksekveringsrekkefølgen (del 2) Kommentar til oppgave 1. } // class Bolighus

Gjøre noe i hele treet = kalle på samme metode i alle objekten. Java datastruktur Klassestruktur

IN1010 våren januar. Objektorientering i Java

Algoritmer og datastrukturer Kapittel 3 - Delkapittel 3.1

UNIVERSITETET I OSLO

Mål med kurset. Java i INF Dagens tema. GUI med Swing. Dokumentasjon

. Ved sensur vl1 ahe bokstaverte deloppgaver (a, b, c,...) telle like mye.

UNIVERSITETET I OSLO

INF1010, 21. februar Om å gå gjennom egne beholdere (iteratorer) Stein Gjessing Inst. for Informatikk Universitetet i Oslo

Inf1010 oppgavesamling

(MVC - Model, View, Control)

Konstruktører. Bruk av konstruktører når vi opererer med "enkle" klasser er ganske ukomplisert. Når vi skriver. skjer følgende:

INF januar 2015 Stein Michael Storleer (michael) Lenkelister

Introduksjon til objektorientert. programmering. Hva skjedde ~1967? Lokale (og globale) helter. Grunnkurs i objektorientert.

EKSAMEN I FAG TDT4100 Objekt-orientert programmering. Fredag 3. juni 2005 KL

LC191D/LO191D Videregående programmering mai 2010

class Book { String title; } class Dictionary extends Book { int wordcount; } class CartoonAlbum extends Book { int stripcount; }

Dagens forelesning. Java 13. Rollefordeling (variant 1) Rollefordeling (variant 2) Design av større programmer : fordeling av roller.

Sortering med tråder - Quicksort

Forkurs INF1010. Dag 1. Andreas Færøvig Olsen Tuva Kristine Thoresen

Arv. Book book1 = new Book(); book1. title = "Sofies verden" class Book { String title; } class Dictiona ry extends Book {

OPPGAVE 5b og 8b Java Kode

HØGSKOLEN I SØR-TRØNDELAG

GUI-programmering, del 3 Vinduslyttere Dialogvinduer GUI-komponenten JTable Egne datamodellklasser. En oversikt over kapittel 19 i boka

IN1010 våren 2018 Tirsdag 15. mai. Repetisjon av subklasser og tråder. Stein Gjessing Institutt for informatikk Universitetet i Oslo

Introduksjon til objektorientert programmering

HØGSKOLEN I SØR-TRØNDELAG

i=0 Repetisjon: arrayer Forelesning inf Java 4 Repetisjon: nesting av løkker Repetisjon: nesting av løkker 0*0 0*2 0*3 0*1 0*4

Forelesning inf Java 4

Kapittel 8: Programutvikling

Eksamen i emnet INF100 Grunnkurs i programmering (Programmering I) og i emnet INF100-F Objektorientert programmering i Java I Løsningsforslag

INF1000 (Uke 15) Eksamen V 04

INF1000 (Uke 15) Eksamen V 04

Stein Gjessing, Ins$tu' for informa$kk, Universitetet i Oslo

1 t:n'v'\ekode LO325E. Alle ~vne og trykte. GOd'"j(jent kalkulator

TOD063 Datastrukturer og algoritmer

Les gjennom hele oppgavesettet før du begynner å besvare deloppgavene.

INF1010 notat: Binærsøking og quicksort

INF1010 våren Grensesnitt

Antall sider (inkl. forsiden): 7. Alle trykte og håndskrevne

UNIVERSITETET I OSLO

Post-it spørsmål fra timen (Arv og subklasser)

GUI («Graphical User Interface») del 2

Transkript:

Det ferdige spillet INF1010 våren 2006 Uke 19: 9. mai 2006 Et større eksempel: Solitaire (kabal) Stein Michael Storleer Institutt for informatikk Dette er kopier av lysark for en forelesning. Sidene er kan være ufullstendige og det kan forekomme feil. Disse sidene er kun egnet til bruk for selvstudium med korreksjoner og notater fra forelesningen 2 Oversikt over forelesningen Klassediagram n UML klassediagram MVC-oppdelingen n Design av grensesnittet n Basis-modellen initialisering av spillet n Selve spillet n Temaer som dekkes: n MVC n Subklasser n GUI + Litt lister og interface n Dekkes ikke: n Rekursjon n Med utgangspunkt i Timothy Budd: Understanding objectoriented programming with Java, updated edition. Addison- Wesley, 2000. 3 Solitaire 1 Solitaire 1 Solitaire 13 13 Bunke 0..* Kort Hovedprogrammet 0..52 Bunke Kort 4

MVC-samspillet Klassen Kort n Definerer de ulike kort-fargene som konstanter: KLØVER, RUTER, HJERTER, SPAR n Private variable: Brukerinput l endret Be om data n private int farge; n private int verdi; n private boolean synlig = false; // Billedside opp? n Konstruktør: Passende metodekall l endret Be om data n public Kort(int farge, int verdi) n Enkle aksess-metoder: n public int getfarge() n public int getverdi() n public boolean ersynlig() 5 n Metodene n public void snu() snur et kort ved å sette synlig =! synlig n public boolean svart() gir true hvis fargen er kløver/spar 6 Klassen Kort Kort vs Kort n Definerer en del konstanter: n final static int KORTBREDDE = 50; n final static int KORTHØYDE = 70; n De ulike kort-fargene: BAKSIDE, KLØVER, RUTER, HJERTER, SPAR n Private variable: n private int farge; n private String verdi; n Konstruktør: n public Kort(int farge, String verdi) n Enkle aksess-metoder: n public int getfarge() n public String getverdi() n Metoden tegnkort(graphics g, int x, int y) for å vise frem ett enkelt kort på skjermen. 7 n Hvorfor to så (i hvert fall tilsynelatende) like klasser? 8

Solitaire extends Jframe (BorderLayout) WEST: Jpanel pp1 (FlowLayout) GUI-design Bunke extends JPanel Jbutton newgame NORTH: Jpanel p1 (FlowLayout) CENTER: Jpanel p2 (BorderLayout) EAST: Jpanel pp2 (FlowLayout) SOUTH: Jpanel p3 (GridLayout(1,7)) 9 Klassen Bunke n Subklasse av JPanel n Private variable: n private Kort[ ] kortene; n private int id; n private boolean vertikal; n Konstruktør: n public Bunke(int id, boolean vertikal) n Aksess-metoden: n public int getid() n Set-metoden n public void setkort(kort[ ] kortene) n Metoden setsize() som beregner hvor stor plass bunken trenger på skjermen, avhengig av antall kort som skal vises frem og om disse skal vises horisontalt eller vertikalt. n Metoden paintcomponent(graphics g) for å vise frem bunken på skjermen (kaller tegnkort for hvert Kort som skal vises). 10 Solitaire import java.awt.*; import java.awt.event.*; import javax.swing.*; Skal lytte etter museklikk på de ulike bunkene (implements MouseListener) class Solitaire extends MouseAdapter implements ActionListener { Solitaire model = new Solitaire(); Solitaire view = new Solitaire(this); public static void main(string[] args) { Solitaire c = new Solitaire(); public void mouseclicked(mouseevent e) { // < Ikke implementert enda > Skal lytte etter trykk på New game Solitaire public class Solitaire extends JFrame { Bunke[] bunker; Solitaire control; Hovedvinduet public Solitaire(Solitaire c) { super("solitaire"); control = c; init(); // Oppretter vinduskomponentene public void actionperformed(actionevent e) { // < Ikke implementert enda > 11 12

public void init() { JButton newgame = new JButton("New game"); newgame.addactionlistener(control); // Oppretter de ulike grafiske bunkene. bunker = new Bunke[13]; bunker[0] = new Bunke(0, false); // håndbunke bunker[1] = new Bunke(1, false); // avkastbunke for (int i = 0; i < 4; i++) { bunker[2+i] = new Bunke(2+i, false); // grunnbunker for (int i = 0; i < 7; i++) { bunker[6+i] = new Bunke(6+i, true); // bordbunker // Kontrollen skal lytte etter museklikk på bunkene for (int i = 0; i < 13; i++) { bunker[i].addmouselistener(control); // < Organiser bunkene: på neste foil > oppdater(); // Oppdaterer bunkenes data og størrelse Container lerret = getcontentpane(); lerret.setlayout(new BorderLayout()); Jpanel p1 = new JPanel(); // Knapp p1.add(newgame); JPanel pp1 = new JPanel(); // håndbunke og avkastbunke pp1.add(bunker[0]); pp1.add(bunker[1]); JPanel pp2 = new JPanel(); // grunnbunker for (int i = 0; i < 4; i++) pp2.add(bunker[2+i]); JPanel p2 = new JPanel(); p2.setlayout(new BorderLayout()); p2.add(pp1, BorderLayout.WEST); p2.add(pp2, BorderLayout.EAST); JPanel p3 = new JPanel(); // bordbunker p3.setlayout(new GridLayout(1,7)); for (int i = 0; i < 7; i++) p3.add(bunker[6+i]); setdefaultcloseoperation(jframe.exit_on_close); setvisible(true); 13 lerret.add(p1, BorderLayout.NORTH); lerret.add(p2, BorderLayout.CENTER); lerret.add(p3, BorderLayout.SOUTH); 14 // I Solitaire public void oppdater() { for (int i = 0; i < bunker.length; i++) { // < Hent bunke-data fra modellen (via kontrollen) > bunker[i].setsize(); // Setter grafisk størrelse på bunken pack(); repaint(); Status: Tomt grensesnitt // I Bunke public void paintcomponent(graphics g) { super.paintcomponent(g); if (kortene == null) { // Tom bunke g.drawrect(0, 0, Kort.KORTBREDDE, Kort.KORTHØYDE); else { // < Kommer senere... > 15 16

Avkastbunke De ulike bunkene len Håndbunke Grunnbunker Bordbunker n Vi ser av vi har ulike typer bunker, der fellesnevneren er at hver bunke har en liste med kortene i bunken. n Siden kort alltid legges til/fjernes fra toppen av en bunke, er dette en LIFO-liste. n De nøyaktige reglene for å legge til/fjerne kort vil derimot variere med typen bunke. n De ulike bunkene kan naturlig modelleres som subklasser av en generell Bunke-klasse: Bunke 17 HandBunke AvkastBunke GrunnBunke BordBunke 18 En generell Bunke Klassen HandBunke import java.util.*; n Selve kortstokken public class Bunke { protected LinkedList bunken = new LinkedList(); public boolean ertom() { return bunken.isempty(); public void leggtil(kort kortet) { bunken.addlast(kortet); public Kort fjern() { if (ertom()) return null; return (Kort) bunken.removelast(); public boolean kanta(kort kortet) { return false; Brukes som en FIFO-liste, LIFO-liste, med innsetting/fjerning sist 19 import java.util.random; public class HandBunke extends Bunke { public HandBunke() { // Oppretter en bunke med 52 kort for (int i = 0; i < 4; i++) { for (int j = 1; j <= 13; j++) { leggtil(new Kort(i, j)); // Stokker kortene ved hjelp av en random-generator. Random generator = new Random(); for (int i = 0; i < 52; i++) { int j = Math.abs(generator.nextInt() % 52); Object tmp = bunken.get(i); bunken.set(i, bunken.get(j)); bunken.set(j, tmp); 20

Klassen AvkastBunke Klassen GrunnBunke n Metoden kanta: Ingen begrensninger på hvilke kort som kan ligge i bunken. n Metoden leggtil: Alle kortene i bunken skal være synlige. public class AvkastBunke extends Bunke { public boolean kanta(kort kortet) { return true; public void leggtil(kort kortet) { if (!kortet.ersynlig()) { kortet.snu(); super.leggtil(kortet); 21 n Metoden kanta: Må følge farge, i stigende verdi fra essene og oppover. public class GrunnBunke extends Bunke { public boolean kanta(kort kortet) { if (ertom()) { return kortet.getverdi() == 1; Kort toppkort = øverste(); return (kortet.getfarge() == toppkort.getfarge() && kortet.getverdi() == toppkort.getverdi() + 1); 22 Klassen BordBunke n Metoden kanta: Kun konger kan flyttes til en ledig bunke. Ellers bygges bunkene i avtagende verdi, med alternerende rød/svart farge. public class BordBunke extends Bunke { public boolean kanta(kort kortet) { if (ertom()) { return kortet.getverdi() == 13; else { Kort toppkort = øverste(); if (!toppkort.ersynlig()) return false; return (kortet.svart()!= toppkort.svart() && kortet.getverdi() == toppkort.getverdi() - 1); 23 public class Solitaire { private Bunke[] bunker; public Solitaire() { init(); public void init() { bunker = new Bunke[13]; bunker[0] = new HandBunke(); bunker[1] = new AvkastBunke(); for (int i = 0; i < 4; i++) bunker[2+i] = new GrunnBunke(); for (int i = 0; i < 7; i++) bunker[6+i] = new BordBunke(); Kort kortet = null; for (int i = 0; i < 7; i++) { // Legger ut kortene i én bunke. Bunke i skal ha i+1 kort. for (int j = 0; j <= i; j++) { kortet = bunker[0].fjern(); bunker[6+i].leggtil(kortet); kortet.snu(); // Nederste kort skal være synlig. 24

Fra modell til view Hvordan hente data fra modellen inn i viewet? 1. Metoden oppdater i Solitaire kaller control.getkort(id) for hver enkelt bunke (med identifikator id) i viewet. 2. Kort[ ] getkort(int id) i Solitaire: 1. Finner identifikatoren til den tilsvarende bunken i modellen (her: samme id). 2. Kaller model.getkort(id). 3. Svaret fra modellen er en array med Kort-objekter (de kortene i bunken som skal vises frem). Denne oversettes til en array med Kort-objekter, som så returneres til viewet. 3. Metoden oppdater i Solitaire tilordner så Kort-arrayen til bunken ved hjelp av dennes set-metode setkort(). 4. Til slutt kaller viewet repaint() for å tegne vinduet på nytt. Solitaire: getkort public Kort[] getkort(int id) { if (bunker[id].ertom()) { return null; else if (id >= 6) { // bordbunke, returner alle kortene return bunker[id].getkort(); else { // annen type bunke, returner bare øverste kort Kort[] returkort = new Kort[1]; returkort[0] = bunker[id].øverste(); return returkort; 25 26 Bunke: getkort // I Solitaire public Kort[] getkort(int id) { Kort[] kortene; Kort[] retur; kortene = model.getkort(id); // Hent kortene fra modellen if (kortene == null) return null; // Tom bunke public Kort øverste() { if (ertom()) { return null; return (Kort) bunken.getlast(); public Kort[] getkort() { Kort[] kortene = (Kort[]) bunken.toarray(new Kort[0]); return kortene; retur = new Kort[kortene.length]; int farge, nyfarge, verdi; String nyverdi; for (int i = 0; i < kortene.length; i++) { Kort k = kortene[i]; farge = k.getfarge(); verdi = k.getverdi(); if (!k.ersynlig()) nyfarge = Kort.BAKSIDE; else if (farge == Kort.KLØVER) nyfarge = Kort.KLØVER; else < Tilsvarende for de andre fargene > if (verdi == 1) nyverdi = "A"; else if (verdi == 11) nyverdi = "J"; else if (verdi == 12) nyverdi = "D"; else if (verdi == 13) nyverdi = "K"; else nyverdi = Integer.toString(verdi); 27 retur[i] = new Kort(nyfarge, nyverdi); return retur; 28

Bunke: paintcomponent public void paintcomponent(graphics g) { super.paintcomponent(g); if (kortene == null) { // Tom bunke g.drawrect(0, 0, Kort.KORTBREDDE, Kort.KORTHØYDE); else { for (int i = 0; i < kortene.length; i++) { if (vertikal) { kortene[i].tegnkort(g, 0, i*35*2); else { kortene[i].tegnkort(g, i*20, 0); 29 // I Kort public void tegnkort(graphics g, int x, int y) { g.clearrect(x, y, KORTBREDDE, KORTHØYDE); // Tegner bakgrunnen på kortet if (getfarge()!= BAKSIDE) g.setcolor(color.white); else g.setcolor(color.gray); g.fillrect(x, y, KORTBREDDE, KORTHØYDE); // Tegner rammen rundt kortet g.setcolor(color.black); g.drawrect(x, y, KORTBREDDE, KORTHØYDE); // Tegner selve kortet switch(getfarge()) { case RUTER: g.setcolor(color.red); g.drawstring(""+getverdi(), x+3, y+15); g.drawline(x+25, y+20, x+40, y+40); g.drawline(x+40, y+40, x+25, y+60); g.drawline(x+25, y+60, x+10, y+40); g.drawline(x+10, y+40, x+25, y+20); break; < Tilsvarende for de andre fargene, samt baksiden > 30 Status: Ferdig initiert, mangler spilling "New game" // I Solitaire public void actionperformed(actionevent e) { if (e.getactioncommand().equals("new game")) { model.init(); view.oppdater(); 31 32

n n Flytting av ett kort mellom bunker I viewet: 1. Brukeren klikker på bunken det skal flyttes fra. 2. Det øverste kortet her merkes grafisk med en annen farge. 3. Brukeren klikker på bunken det skal flyttes til. I kontrollen: 1. Ved første museklikk huskes hvilken bunke som ble valgt. 2. Ved andre museklikk gjøres et passende kall på metoden boolean flytt(int fra, int til) i modellen. 3. Returen fra modellen angir om flyttingen ble utført (modellen endret) eller om det skal gis feilmelding til brukeren. 33 Solitaire: mouseclicked private int source = -1; public void mouseclicked(mouseevent e) { Bunke bunken = (Bunke) e.getsource(); if (source == -1) { source = bunken.id; view.marker(bunken.id); else { if (bunken.id!= source) flytt(source, bunken.id); view.umarker(source); source = -1; public void flytt(int fra, int til) { boolean ok = model.flytt(fra, til); if (ok) view.oppdater(); else view.feilmelding("ulovlig operasjon"); 34 Solitaire: feilmelding+merking public void feilmelding(string melding) { JOptionPane.showMessageDialog(this, melding); public void marker(int id) { bunker[id].marker(); repaint(); public void umarker(int id) { bunker[id].umarker(); repaint(); Den nøyaktige merkingen av bunkene tas ikke med her. Solitaire: flytt boolean flytt(int fra, int til) { Bunke frabunke = bunker[fra]; Bunke tilbunke = bunker[til]; // Kort som flyttes fra håndbunke må flyttes til avkastbunke if (frabunke instanceof HandBunke &&! (tilbunke instanceof AvkastBunke)) return false; // Kort som flyttes til avkastbunke må komme fra håndbunke if (tilbunke instanceof AvkastBunke &&! (frabunke instanceof HandBunke)) return false; if (frabunke.ertom()) return false; // Tom bunke // Flytt ett kort fra en bunke til en annen hvis mulig Kort kortet = frabunke.øverste(); if (tilbunke.kanta(kortet)) { frabunke.fjern(); tilbunke.leggtil(kortet); return true; 35 // Fortsetter neste foil... 36

Solitaire: flytt (forts.) Bunke: bygg < Fortsettelse fra forrige foil... > // Flytt eventuelt et helt bygg mellom to bordbunker if (frabunke instanceof BordBunke && tilbunke instanceof BordBunke) { Kort[] kortene = frabunke.bygg(); for (int i = 0; i < kortene.length; i++) { // Forsøk å flytte alle kortene i bygget fra og med indeks i if (tilbunke.kanta(kortene[i])) { for (int j = i; j < kortene.length; j++) { frabunke.fjern(); tilbunke.leggtil(kortene[j]); return true; public final Kort[] bygg() { int førstesynlige = -1; for (int i = 0; i < bunken.size(); i++) { Kort kortet = (Kort) bunken.get(i); if (kortet.ersynlig()) { førstesynlige = i; break; List bygg = bunken.sublist(førstesynlige, bunken.size()); Kort[] kortene = (Kort[]) bygg.toarray(new Kort[0]); return kortene; return false; // Ingen flytt mulig 37 38 Annen brukerinput n Ved klikk på håndbunken: n Ta av ett kort til avkastbunken n Ved klikk på bordbunke der det øverste kortet ligger med billedsiden ned: n Snu dette kortet slik at billedsiden ligger opp // I Solitaire public void mouseclicked(mouseevent e) { Bunke bunken = (Bunke) e.getsource(); int id = bunken.getid(); if (source == -1) { if (id == 0) { // håndbunke, flytt kort til avkastbunke flytt(0, 1); else if (id >= 6 && snukort(id)) { // bordbunke, øverste kort skjult // snukort gjør jobben selv... else { source = id; view.marker(id); else { // Som før... 39 public boolean snukort(int id) { boolean svar = model.snukort(id); if (svar) { view.oppdater(); return svar; 40