Poker algoritmen færdig

Alle lærerene på skolen er taget til USA i denne uge til noget konference halløj. Hvilke betyder at hele denne uge skal vi ikke i skole (vi får også en hel uge om 2 uger, pga påskeferien :) )

Jeg har indtil videre brugt tiden på at lave en algoritme til at udregne vinderen at et omgang Poker. Jeg har flere gange forsøgt mig med at lave det, men nu føler jeg at jeg ved nok om programmering til at lave den slags og det lykkedes også at lave noget fornuftigt.

Grunden til det blev en Poker “udregner”, er at reglerne er forholdsvist komplicerede og dermed en lidt større udfordring end de simple opgaver der stilles i skolen. Samt at jeg efterhånden er expert i Poker, af al den viden jeg har indsamlet mig fra Stian gennem de seneste år.

Jeg sprang let henover design og analysefasen og sprang direkte til at kode. Det er ikke altid det mest spændende at skulle lave klassediagrammer og den slags, når man bare vil igang med at kode selve algoritmen. Det betød også at når GUIen kom på, så blev koden hurtig ret uoverskuelig.

Algoritmen er udformet så der er en metode til hver type af hænder i Poker som returnere en boolean, hvor sand hvis hånden er af den type. Hvis den er det, så gemmes værdierne af kortene i en array, i stigende orden efter hvor vigtige de er. Dette bruges hvis 2 eller flere hænder er af samme type, så vil en sammenligning af disse arrays til hver hånd kunne afgøre den bedste hånd. Fx hvis der er 2 hånder med tre ens:
Bord: d9, s9, c6, h5, d3
1: h9, h12
2: c9, h11
Så vil hånd 1 vinde da, han har højere kort ud end hånd 2.
De 2 arrays vil således se sådan ud:
1: [6, 12, 9]
2: [6, 11, 9]
Så når man gennemgår dem bagfra, så er vinderen den hvor den er højst første gang.

Det var måske en temmelig rodet forklaring, men ellers kan man selv afprøve programmet:

www.auzzie.dk/poker.jar (kræver Java 1.6)

Garfield multithreaded

Som et brugbart eksempel på multithreading, så besluttede jeg at lave et Java program der henter samtlige afsnit af Garfield fra 1978 frem til i dag (ideen er inspireret af Niels Christian).

Multithreading er ret smart til denne opgave. Uden multithreading, så skal hvert download først oprette en connection til en URL, så skal en InputStream, en FileOutputStream og en BufferedOutputStream oprettes, før billedet kan hentes, hvorefter de skal lukkes igen. Med multithreading kan fx 20 connections oprettes samtidig, og 20 indlæsninger og skrivinger forgå samtidig.

Dette kunne også tydeligt ses i download hastighederne. Hvor ved kun én tråd, så hentede den ved en 40KB/s (Et billede fylder ca. 40KB), mens ved 20 tråde, så var den oppe på 600KB/s (ud af en mulig 1MB/s).

Hvis man ser på hvornår billederne blev oprettet, så tog det en 22 min med multithreading at hente alle billederne. Uden, så tog det ca. 7 min at hente bare en enkel mappe. Det ville have taget 7 min * 31 mapper = 3,5 timer. Da jeg hentede, så gjorde jeg det over 2 omgange, da jeg ikke ville belaste siden alt for meget, så det kunne måske kunne hentes på under 10min (512MB / 1MBps = 8,5min).

Koden kan ses her: http://paste2.org/p/161995
(Jeg har fjernet url adressen, og lavet nogle små fejl, for ikke gøre det for nemt).

Første stribe fra 1978:

Seneste stribe fra i dag 2009:

Der er en ret stor forskel på tegnestilen :)

Zip fil med alle billederne: Garfield.zip (512MB)


Java multithreading

Java kan godt multithreade, men desværre skal man selv designe sit program til at Java udnytter de kerner de fleste moderne CPUer har i dag.

Hvis man vil udnytte det, skal man til at oprette tråde. Her er noget kode der opretter 10 tråde og udskriver et nummer jeg har givet det enkelte tråd. Det interessante er at de ikke udføres lige hurtige og det er ikke til at vide i hvilke rækkefølge trådene køres. Derfor skal det man deler ud i trådene ikke være afhængige af rækkefølgende de udføres i.

Derfor er det heller ikke nemt at lav programmer der udnytter alle ens kerner, fordi det skal være noget der kan køres uafhængig af de andre tråde og hvis tendensen fortsætter med flere og flere kerner, så bliver det svært at finde opgaver til disse kerner. Det kunne være så dejligt, hvis det på en eller anden måde kunne håndteres af Windows eller Java JVM, så man slipper for at skulle holde styr på alle disse tråde.

Herunder har jeg nogle skærmbilleder af en MergeSort algoritme jeg lavede i skolen. Den første er med 1 tråd, hvor man kan se at den kun udnytter halvdelen af CPUens processor kraft. Den anden er så med 2 tråde og udnytter derfor begge kerner.

Én kerne

To kerner

image


Ram sjov

Her er en sjov leg:

1. Lav et java program med følgende kode:


public class RamEater {
     public static void main(String[] args) {
          List list = new ArrayList();
          while (true) {
               list.add((int)(Math.random() * 1000));
          }
     }
}

2. Compile og kør programmer med følgende JVM argumenter:

javac RamEater.java
java -Xmx4096m RamEater

3. Åben Joblisten (hvis du kører Windows) og se hvordan java.exe bare æder og æder ramene.

4. Når al din ram er brugt op, så afslut processen java.exe og prøv at bruge computeren normalt igen. Så begynder computeren at køre rigtig langsomt, indtil dine andre programmer får deres hukommelse lagt ind i rammene fra harddisken.

Her er et skærmbillede fra joblisten på min stationær. Selvom den har 4GB ram og bruger 64bit Windows, så får jeg ikke så meget højere end de 3.000 MB. Enten er det grafikkortet der bruger den sidste ca 800MB, eller så mangler jeg at indstille noget så Windows kan bruge mere end de 3,2GB.