Archive for the ‘For sjov’ Category

Resultatet af kodegolfkonkurrencen

Friday, July 30th, 2010

Konkurrence er slut, og vinderen er fundet, men inden vi kommer så langt, skal jeg først og fremmest sige tak til alle jer, der har indsendt bidrag. Sommervarme og ferie til trods har jeg modtaget ikke mindre end 30 løsninger på udfordringen denne gang og flere af dem har tilmed været igennem adskillige revisioner. Jeg er imponeret! Tusind tak fordi I ville være med.

Gennemsnittet for løsningerne ligger på 185 anslag, og der er ikke mindre end syv løsninger på under 140 anslag! 29 ud af 30 løsninger klarer alle mine test cases, så vinderen er altså fundet blandt de 29.

Der er rigtig mange gode og kreative ideer. Flere har været forbi den nye Zip-metode, og LINQ er i det hele taget pænt repræsenteret i løsningerne. Der er brugt mange forskellige datastrukturer så som arrays, List, Stack og sågar string. Vinderen benytter LINQ og string.

Nok snak, lad os se vinderen. Med blot 132 anslag:

public static int[] MadsOgPeterSandbergBrun_Add(int[] a,int[] b){
   var c="";
   for(int o=a.Length,p=b.Length,s=0;-o-p<(s=s/10+(0<o?a[--o]:0)+(0<p?b[--p]:0));)
      c=s%10+c;
   return c.Select(i=>i-48).ToArray();
}

Tillykke til Mads og Peter Sandberg Brun! Der er et stk. Visual Studio 2010 Ultimate + MSDN på vej til jer.

Resten af feltet ser ud som følger:

Mads og Peter Sandberg Brun            132
Jacob Korsgaard                        135
Jørgen Ulrik B. Krag (Jubk)            135
Asger Hallas  og Lars Udengaard        135
Fredrik Olsson                         138
Mogens Heller Grabe (Mookid8000)       138
Ole Tolshave                           139
Jan Jensen (JanJ)                      141
Niels Rasmussen (NTR)                  151
Steffen Holmslykke (SNH)               153
Asger Hallas                           157
Mads Mau Pedersen (MMP)                158
Jesper Harder (JHD)                    158
Daniel Brixen                          169
Anders Uhl Pedersen (Aup)              170
Jonathan Jørgensen (Jonathan)          170
Jesper Alf Dam (Jalf)                  176
Christian Rysgaard (CER)               183
Morten Gejl (MGE)                      193
Mads Hedegaard                         195
Carsten Hess                           196
Brian Vestergaard Andersen             208
Anders Reimer                          218
Dennis Riis                            226
Martin Faartoft                        227
Allan Tech                             248
Martin Larsen                          287
Simon Kristensen (Imonsei)             289
Claus Jensen                           296
Daniel Mellgaard Frost (Danielovich)   229 (fejler)

Jeg har lavet en fil med alle bidragene, så I kan få ideer til fremtidige kodegolfturneringer.

Endnu en gang tak til jer alle!

Kodegolf: Vind Visual Studio 2010 Ultimate

Wednesday, July 14th, 2010

Det er sommer, det er varmt, og det er tid til en gang golf. Her på siden foregår den slags jo ikke ude i det fri men derimod foran computeren, hvilket sikkert ikke er det værste sted at opholde sig i disse høj-UV-tider.

Denne gang går opgaven ud på at implementere nedenstående metode, der kan lægge potentielt meget store, ikke-negative heltal sammen. Koden skal skrives i C#.

public static int[] Add(int[] a, int[] b) { }

Som det fremgår, tager Add() to int[]. Hvert int i de to arrays repræsenterer et ciffer, så hvis a repræsenterer værdien 1000, indeholder den { 1, 0, 0, 0 }, og hvis b rummer værdien på Decimal.MaxValue indeholder den { 7, 9, 2, 2, 8, 1, 6, 2, 5, 1, 4, 2, 6, 4, 3, 3, 7, 5, 9, 3, 5, 4, 3, 9, 5, 0, 3, 3, 5 }. Den øvre grænse for tallenes størrelse er kun begrænset af størrelsen på int[]. De to værdier skal lægges sammen og returneres som int[].

Følgende regler gælder:

  • Alle anslag mellem metodedefinitionens start- og slut-curlies tælles med – white space, der ikke har betydning for metodens virke er dog undtaget.
  • a og b kan ikke være tomme, men de har ikke nødvendigvis samme længde.
  • Alle regneoperationer skal foregå på datatypen int.
  • Det er ikke tilladt at bruge BigInteger.
  • Alle udregninger skal foregå i Add().
  • Ingen hjemmelavede hjælpemetoder eller erklæringer uden for Add().
  • Navngiv metoden så den hedder DitNavnEllerAlias_Add, f.eks. kunne min version hedde Kodehoved_Add. Navnets længde påvirker ikke optællingen med mindre metoden benytter rekursion (så lad være med det).
  • Det er ikke tilladt at bruge using-aliaser, da alle bidrag bliver testet af samme program.
  • Resultatet må ikke indeholde foranstillede nuller.
  • Send løsningsforslag til brian@kodehoved.dk.
  • Deadline: 30. juli kl. 20.00.

Jeg har et stk. Microsoft Visual Studio 2010 Ultimate with MSDN som præmie. Vinderen er den, der leverer en korrekt løsning på ovenstående med færrest mulige anslag. I tilfælde af flere løsninger med lige få anslag trækker jeg lod blandt disse.

Skulle der være uklarheder så skriv en kommentar, så skal jeg uddybe snarest. Følg med i kommentarerne og husk at tjekke for opdateringer til dette indlæg. God fornøjelse!

Kodegolf: Resultater og vinderne

Monday, November 23rd, 2009

Jeg er imponeret! Ikke alene modtog jeg hele 24 bidrag i konkurrencen, men flere af jer sendte også adskillige forsøg, og der var rigtig mange gode forslag imellem de indkomne svar. Tak for det.

Jeg har modtaget bidrag fra: Jacob Eisenberg, Kristian Vinther, Mark Seemann, Jan Jensen, Janus Egholm, Claus Christensen, Christian Rysgaard, Morten Gejl, Mads Mau Pedersen, ”lajensen”, Dennis Riis, Søren Larsen, Troels Thomsen, Jakob Gade, Carsten Hess, Hakon Baunsgaard, Jacob Tjørnholm, Rune Juhl-Petersen, David Thomas, Allan Thraen, Jesper Harder, Mads Hedegaard, Mads Lützhøft og Niels Rasmussen.

Tusind tak fordi I ville være med.

Ifølge mit optællingsscript ser resultaterne ud som følger.

129 : Hakon Baunsgaard
129 : Jesper Harder
129 : ”lajensen”
129 : Mads Mau Pedersen
129 : Troels Thomsen
132 : Kristian Vinther
137 : Mads Hedegaard
138 : Christian Rysgaard
139 : Niels Rasmussen
141 : Morten Gejl
144 : Jacob Tjørnholm
149 : Jan Jensen
149 : Rune Juhl-Petersen
150 : Søren Larsen
151 : Dennis Riis
152 : Carsten Hess
152 : Jacob Eisenberg
164 : Claus Christensen
168 : Mads Lützhøft
177 : David Thomas
196 : Janus Egholm
228 : Jakob Gade
281 : Allan Thraen
348 : Mark Seemann

Det vil sige, at der ikke er en, men ikke mindre end fem vindere! Tillykke til Hakon Baunsgaard, Jesper Harder, ”lajensen”, Mads Mau Pedersen og Troels Thomsen.

129 tegn er altså godt gået.

Jeg har talt med Microsoft, og jeg har fået lov at indløse min trøstepræmie for fire yderligere præmier, så det betyder, at alle vinderne får en præmie. Stort tillykke til vinderne!

Jeg har lavet en zip-fil med alle besvarelserne, så I kan nyde de andres påfund, men her kommer lige en tilfældig udvalgt blandt de fem vindere.

namespace Kodegolf {
    class MMP {
        public static void MAIN() {
            for (int t = 0; ++t < 66; )
                System.Console.WriteLine(t < 65 ? t + ":" + (1ul << t - 1) : "=" + ~0ul);
        }
    }
}

Læg desuden mærke til hvordan flere af vinderne for alle praktiske formål er nået frem til den samme løsning. Det er åbenbart måden at løse denne opgave.

Jeg er imponeret over, at fem personer kom frem til en løsning med så få anslag, og jeg er ligeledes imponeret over det meget tætte løb mellem deltagerne. Hatten af for jer, tak til jer alle sammen fordi I ville være med og endnu en gang tillykke til vinderne!

Kodegolf og rigtig mange ris

Wednesday, November 18th, 2009

Første gang, jeg hørte om eksponentielle funktioner, var i min folkeskoletid. Jeg vil tro, at det var omkring fjerde eller femte klasse. Begrebet blev naturligvis ikke omtalt som sådan, og mine klassekammerater og jeg havde ikke den fjerneste anelse om den underliggende matematik, men jeg husker tydelig, hvordan vores lærer berettede en variant af fortællingen om en kejser, et stakbræt og en masse ris.

Der er en glimrende oversigt over anekdoten på Wikipedia, men i korte træk går historien ud på, at en kejser vil belønne opfinderen af skak, så han spørger ham, hvad han vil have som tak. Manden svarer, at han vil have et riskorn på første felt, to på andet, fire på tredje og så fremdeles indtil han har fået ris svarende til alle felterne på brættet.

Det bliver til ganske mange ris, og jeg husker stadig fascinationen over, hvordan denne lille konstruktion kunne resulterer i et tal, der var langt større, end hvad lærerens lommeregner kunne håndtere. I den alder er det let at blive imponeret over, at teknologi har sine begrænsninger.

Så som en hyldest til ris, skak og matematik holder jeg endnu en gang kodegolf, og Microsoft har venligst stillet et par præmier til rådighed. Det er naturligvis en glimrende lejlighed til at få leget lidt med Visual Studio 2010 beta2, så jeg håber, I vil være med.

Opgaven

Lav et program, der udskriver antal riskorn per felt samt summen for alle 64 felter.
Feltlinjerne skal se ud som følger F:R, hvor F er nummeret på feltet, og R er antal ris på feltet.

Summen skal udskrives på en linje som =S, hvor S er summen. Altså:

1:1
2:2
3:4
4:8

64:xx
=yy

Reglerne

  • Programmet skal som en console application og implementeres i managed C#.
    Alle assemblies fra VS2010 eller tidligere må bruges.
  • Nedenstående skabelon, der skal bruges. Koden i den må ikke ændres. Den sikrer, at default namespace skal hedde ”kodegolf”, og applikationsklassen skal navngives med tre bogstaver baseret på dit navn, så hvis du hedder Ole Hansen kunne den f.eks. hedde OHA. Med samme namespace og klasser med på tre bogstaver bliver optællingen lettere.
namespace Kodegolf {
    class XXX { // Ret XXX til dine initialer (tre bogstaver) og slet denne kommentar
        public static void Main() {

        }
    }
}
  • White space der ikke har betydning for oversættelsen tæller ikke med. Så tomme linjer, indrykninger af koden og så videre tæller ikke med, men mellemrum i tekster gør.
  • Det er ikke tilladt at læse data eller kode fra filer, nettet eller andre steder. Al koden til programmet skal være indeholdt i ovennævnte klasse.
  • Update: Alle tal udskrives som heltal.

Deadline

Deadline er mandag den 23. november klokken 6 (som i om morgenen). Send løsningen til brian@kodehoved.dk.

Vinderen er den korrekte besvarelse med færrest anslag. Vinderen får en eller anden lækker præmie fra Microsoft. Jeg trækker desuden lod om en trøstepræmie blandt alle besvarelserne.

Er der spørgsmål til konkurrencen, så smid en kommentar.

Optælling

Optælling foregår som følger:

  • Først sikrer jeg mig, at Main() er public. Er den ikke det, indsætter jeg public.
  • Jeg fjerner string[] args fra Main(), hvis den del er der.
  • Da jeg har alle løsningerne i samme solution, omdøber jeg Main() til MAIN().
  • Hvis der er mellemrum, der har betydning for korrektheden af løsningen, ændrer jeg disse til underscore i kildeteksten.
  • Derefter kører jeg nedenstående kode for at tælle og det tal, den spytter ud, er resultatet for den pågældende fil.
using System;
using System.IO;
using System.Text.RegularExpressions;

namespace Count {
    class Program {
        static void Main(string[] args) {
            if (args.Length < 1) {
                Console.WriteLine("Syntax: Count.exe sourcefile");
                return;
            }

            var file = args[0];
            if (!File.Exists(file)) {
                Console.WriteLine("{0} not found", file);
                return;
            }

            var code = File.ReadAllText(file);
            Console.WriteLine(Regex.Replace(code, @"\s", "").Length);
        }
    }
}

Mit tal vil derfor muligvis være forskellig fra det, I får, men det sikrer, at alles bidrag bliver talt på den samme måde.

Tips og tricks til bedre kode

Wednesday, August 26th, 2009

Jeg er i skrivende stund i gang med en større gennemgang af en masse kode, og derfor er mine kodesensorer efterhånden helt oppe i omdrejninger. Når man sådan læser kode i dagevis, ser man både en masse godt og en masse skidt. I dette indlæg vil jeg se på nogle af de rigtig gode ideer, jeg er faldet over.

Eksplicitte Booleans

Vi er sikkert alle klar over, at sammenligning altid involverer to størrelser. En på hver side af sammenligningsoperatoren så at sige. Derfor kan jeg kun undre mig over, at folk skriver kode som f.eks.

if (OkToProceed) {
   // do something
}

Her er det underforstået, at variablen OkToProceed skal være sand, før vi fortsætter med do something. Compileren kan jo ikke læse vores variabelnavn, så hvordan kan vi være helt sikre på, at vi kun vil få udført vores kode når OkToProceed er sand? Er det ikke bedst at være sikre, helt sikre? Hvad hvis compileren tager fejl?

Jeg kan bedst lide, at intet er overladt til tilfældighederne, når det kommer til kode, og derfor gælder det om, at udtrykke præcis det, vi mener, i enhver sammenhæng. Ergo, hvis vi vil undersøge om OkToProceed er sand, skal vi skrive:

if (OkToProceed == true) {
   // do something
}

Derved er den ingen, der er i tvivl om, hvad vi mener, og vi garderer os effektivt mod de tilfælde, hvor compileren tager fejl.

I forbindelse med tildeling af bools, er det bestemt også en god ide, at være eksplicit, og her kommer ?: konstruktionen til sin ret. En bool kan let tildeles den korrekte værdi på følgende måde:

bool OkToProceed = IsEverythingOk ? true : false;

Så er det helt klart, hvad der foregår. Hver gang.

Lange metoder

Når vi fra en metode kalder en anden metode, er afviklingsmiljøet nødt til at gemme information om dette. Alle argumenterne til den kaldte metode samt en reference til den kaldende metode skal opbevares. Det sker på stakken, og det sker for hvert eneste kald! Som standard er stakstørrelsen i .NET 1 MB, hvilket jo ikke er meget. Tænk på, at den mindste iPod Nano har langt mere hukommelse, og den skal blot kunne spille lidt musik. Det siger således sig selv, at stakken er en meget begrænset ressource, og derfor er vi nødt til at udvise stor omtanke i brugen af denne. Bruger vi hele stakken, får vi en StackOverflowException, og som jeg har beskrevet andetsteds, hiver det hele processen ned. Det hele bliver kun værre af, at garbage collection ikke udføres for værdier allokeret på stakken. Her er vi selv nødt til at være på vagt.

Overfører vi mange argumenter, tager det plads, men det er der ikke rigtig nogen vej udenom. Vi skal jo bruge argumenterne. Derfor er vores eneste mulighed for at begrænse stakforbruget, at reducere antallet af metodekald. Den letteste måde at gøre dette, er ved at samle så meget logik i hver metode som mulig. Det betyder selvfølgelig, at vi skal kunne håndtere mange forskellige situationer i en og samme metode, men det er jo ikke for sjov, at vi har if, switch og så videre. Via den rette mængde flag, er det let at få en metode til at håndtere et væld af situationer, og derved kan vi undgå at fråse med den begrænsede stakplads.

En anden fordel ved de meget lange metoder er, at vi ikke skal huske så mange forskellige metodenavne, men det er selvfølgelig bare en lille bonus. Den egentlige gevinst består i, at vi med lidt rettidig omhug minimerer risikoen for StackOverflowExceptions.

Klargøring af variable

Apropos lange metoder, så er det sidste tip også særdeles relevant i den sammenhæng. Skønt store, omfattende metoder har sine fordele, som vi lige har set på, er der desværre en mindre ulempe ved dem. De mange linjer kode skal jo JIT-oversættes, og selvom compileren er ret effektiv, kan det tage sin tid. Derfor er det en god ide, at erklære alle variable i toppen af metoden, for det sikrer, at de bliver oversat først. Dermed kan vi være helt sikre på, at de er klar, når vi får brug for dem. Der er jo ikke noget værre end at få en NullReferenceException, bare fordi en given variabel ikke er blevet oversat, inden den skal bruges.

Det er ligeledes en god ide, at sørge for at genbruge de samme variable i videst mulig omfang, så vi derved får reduceret stakforbruget yderligere.

Konklusion

Jeg håber, du kan bruge ovenstående tips til at forbedre din kode, og jeg kan kun opfordre dig til at læse andres kode, da det er en glimrende kilde til inspiration. Har du selv gode tips, må du meget gerne skrive kommentarer til dette indlæg. God fornøjelse!

Resultat af julekonkurrencen om den subtile fejl

Sunday, December 21st, 2008

Så er vi nået til vejs ende for denne gang. Ugens konkurrence tog lidt længere tid for mig at komme igennem, da jeg jo ikke bare kunne nøjes med at tælle anslag. Jeg har læst kode, kørt test, debugget en smule og har tilmed været en tur i Reflector.

Ni bidrag blev det til denne gang, og det var interessant at se de meget forskellige løsninger. Jeg har lavet en zip-fil med alle bidragene, så I selv kan studere dem, men for at give et lille indtryk, kommer her et par kommentarer om hvert bidrag (i vilkårlig rækkefølge).

Hvis der er noget, jeg har overset i de enkelte bidrag eller har taget fejl omkring et eller andet, må I endelig sige til. 

Anders Uhl Pedersen
Løsningen følger en indlysende struktur, og de hjælpemetoder, der er, giver ligeledes god mening. Koden checker ikke for null password, og der er desværre også sneget sig en utilsigtet fejl ind, der gør, at vi skal helt op på fire gentagede tegn, før et password erklæres ugyldigt. Det ændrer dog ikke ved, at den subtile fejl er ganske fin. Opgaven definerede ikke, hvad bogstaver dækker over, og Anders’ kode regner derfor danske bogstaver som specielle tegn, hvilket naturligvis ændrer optællingen en smule. Det ugyldige password, der godkendes, er således:

kunmedsmå0gtal

Claus Christiansen
Nogenlunde ligetil struktur i IsPasswordValid, men noget mere ugennemskuelig kode i hjælpemetoden  checkIndividualCharacters().  Koden checker ikke for null password. Fejlen er en klassiker: Off by one. Nærmere bestemt: En off by one i løkken gør, at member variable aldrig opdateres med den korrekte længde, hvis gentagelse er i enden af password. Det ugyldige password er:

___SubstringAtStartIsAccepted

Morten Gejl
Koden er pæn og ligetil, og der bliver checket for null password. Det er også den eneste løsning, der indeholder exception håndtering. Det havde jeg bestemt ikke regnet med at se i kode til check af et password, så her slog mine code review-alarmer til, og eftersom fejlen ganske rigtig var relateret til håndtering af exceptions, synes jeg ikke, at den er subtil nok. Når det er sagt, er jeg dog glad for Mortens bidrag, for det belyser et område, hvor der meget let kan snige sig fejl ind.  Det ugyldige password udnytter et overflow i en byte counter og er således længere, end jeg vil vise det her, men se i koden for det fulde eksempel. 

Martin Faartoft
Koden er meget let at sætte sig ind i, og der bliver også checket for null password. Fejlen er dejlig subtil; to tegn, der er byttet om i et regulært udtryk. Jeg må indrømme, at jeg dog opdagede den ret hurtig – måske fordi jeg har lavet en del af den slags i min tid. Det ændrer dog ikke ved, at den type fejl kan tage lang tid at finde, så jeg vil ikke lade mit held spille ind i bedømmelsen. Martins forslag var min favorit langt hen ad vejen. Det ugyldige password:

abcdABCD

Dennis Riis
Dennis’ forslag adskiller sig meget fra de andre. Han har implementeret alle reglerne som delegates (og tilmed husket at checke for null password ikke mindre end to gange), som han efterfølgende afvikler af via All() og Count()IEnumerable. Fejlen er også ret god: Koden opsætter et fornuftig LINQ-udtryk, men glemmer at udføre det. Det ugyldige password:

aBBB.01to

Brian Holmgård Kristensen
Koden i dette forslag er lige en smule mere kompliceret, end godt er, synes jeg. Der bliver sammenlignet på magic numbers og en negering af en bool er med til at mudre billedet. Der er desværre også en utilsigtet fejl, idet metoden kræver passwords på mere end 8 tegn. På den positive side bliver der checket for null password, og fejlen er også en klassiker: Endnu en off by one. Det ugyldige password er:

AAAe3Bc5Cy7$d$$

“ToyPanther”
Koden er forholdsvis omfattende og en smule kompleks. Der er dog også en masse kommentarer, der i denne sammenhæng kan bruges til at forvirre læseren. Implementeringen checker ikke for null password, men fejlen er god. En simpel “slåfejl” gør, at en tællevariabel initialiseres til to forskellige værdier afhængig af omstændighederne. En gang refactoring ville dog nok komme denne fejl til livs (uanset om man var opmærksom på den eller ej). Det ugyldige password er:

aaaSh0uldFa1l

Mads Mau Pedersen
Mads’ implementering er også meget anderledes end de resterende bidrag. Implementeringen er meget objektorienteret forstået på den måde, at alle valideringerne er implementeret af dedikerede typer. På trods af den store mænge kode er det desværre ikke blevet til null check, og jeg har det personlig svært med kode, der checker en bool for at returnere en bool. Men det er altså detaljer, for fejlen i koden er virkelig god. Jeg har gengivet de nødvendige linjer nedenfor, så brug lige et par minutter og se om du kan spotte, hvad der går galt her.

private CaseValidator(bool isupper) { CheckForUpperCase = isupper; }
private CaseValidator() { }
public static CaseValidator HasUpperCase = new CaseValidator();
public static CaseValidator HasLowerCase = new CaseValidator(false);
private static bool DefaultValue = true;
private bool CheckForUpperCase = DefaultValue;

Jeg skulle tænke en del her, og det var først, da jeg tog Reflector til hjælp, at brikkerne faldt på plads. Mads udnytter, at statics afvikles i den rækkefølge, de erklæres i kildeteksten, så når CaseValidator() oprettes, er DefaultValue ikke blevet initialiseret til true, og derfor har den sin oprindelige default værdi, false. Det er en god fejl!

Det ugyldige password:

mu11pssed

Christian Bjerre Nielsen
Koden i IsPasswordValid() følger en indlysende struktur, men de underliggende metoder er unødig komplekse, synes jeg. Dertil kommer manglende null check, og en lidt ineffektiv løkke, der bliver ved at undersøge for gentagelser efter at det er blevet konstateret, at der ikke er en gentagelse. Optællingen er også lidt spøjs, idet den sammenligner hvert tegn med sig selv og tæller op på grund af gentagelse. Fejlen er dog fin. Passwordet deles op i to i forbindelse med check for gentagelser, men grundet lidt forkerte udregninger af grænseværdier, vil gentagelser i enden af passwordet ikke blive opdaget. Det ugyldige password er således:

1SimCorpppp

Og vinderen er …

Som det sikkert kan læses ud af ovenstående, er jeg mest begejstret for Mads’ bidrag, så et stk. MSDN snowboard går til ham. Andenpladsen var svær, og valget stod mellem Dennis og Martin. Begge fejl er ret gode, synes jeg, og det er svært at fremhæve den ene over den anden. I mangel på bedre har jeg simpelthen trukket lod, så vinderen af et par biografbilletter er: Martin. Stort tillykke til vinderne og mange tak til jer alle for bidragene.

Julekonkurrence: Den subtile fejl

Monday, December 15th, 2008

Med al den positive respons jeg fik på forrige konkurrence, synes jeg, at vi skal blive i kodesporet. Denne uges konkurrence er dog lidt sværere både for jer og for mig, for her er succeskriterierne subjektive. 

I skal implementere en simpel rutine, så det ser ud som om, den virker efter hensigten, men der skal være en subtil fejl, der får den til at fejle i visse situationer. Det er altså meningen, at jeres fejl skal kunne slippe igennem et code review på en god (eller måske nærmere dårlig) dag. Jo mere subtil fejlen er, desto bedre er mulighederne for at vinde. Eller sagt på en anden måde: Hvis koden er simpel og ser ud til at fungere, men ikke gør det, er du på rette spor. Også denne gang står Microsoft for en præmie og en trøstepræmie (som jeg denne gang vil uddele til det næstbedste forslag). Update: Jeg har netop hørt fra Microsoft, at uges præmie bliver et snowboard (bjerg og sne medfølger vist ikke), så det er bare med at komme til tasterne!

Opgaven: Lav en rutine, der checker styrken af et password og returnerer en bool afhængig af om passwordet kan accepteres eller ej. Rutinen skal indeholde en subtil fejl, der gør at et eller flere password, der ikke overholder reglerne, godkendes. Derudover skal passwords, der overholder reglerne resultere i true, mens passwords, der ikke overholder reglerne skal resultere i false. 

Et godkendt password skal som overholde nedenstående regler

  1. Bestå af mindst 8 tegn
  2. Indeholde mindst tre af følgende kategorier: store bogstaver, små bogstaver, tal, specielle tegn
  3. Må ikke indeholde tre identiske tegn i rækkefølge

Koden skal tage udgangspunkt i nedenstående skabelon, men I kan tilføje lige så mange private hjælpemetoder, som I mener, der er brug for. 

public class PasswordValidator {
   public bool IsPasswordValid(string password) {
   }
}

Koden skal skrives i managed C# og I må bruge alle standardbibliotekerne til og med .NET 3.5. 

Ud over selve koden, skal I lave mindst tre test cases, der viser, at koden godkender gyldige passwords, og mindst tre test cases, der viser, at koden afviser ugyldige passwords. Sidst men ikke mindst, skal I lave en test case, der påviser jeres fejl. Brug nedenstående skabelon.

[TestClass]
public class PasswordValidatorTest {

   [TestMethod]
   public void ValidPasswords() {
      var validator = new PasswordValidator();
      Assert.IsTrue(validator.IsPasswordValid("" /* test af gyldig password */));
      Assert.IsTrue(validator.IsPasswordValid(""));
      Assert.IsTrue(validator.IsPasswordValid(""));
   }

   [TestMethod]
   public void InvalidPasswords() {
      var validator = new PasswordValidator();
      Assert.IsFalse(validator.IsPasswordValid("" /* test af ugyldig password */));
      Assert.IsFalse(validator.IsPasswordValid(""));
      Assert.IsFalse(validator.IsPasswordValid(""));
   }

   [TestMethod]
   public void TheBug() {
      var validator = new PasswordValidator();
      Assert.IsTrue(validator.IsPasswordValid("" /* påviser fejl i koden */));
   }
}

Deadline er som sædvanlig fredag kl. 20. Send jeres bidrag i en mail til brian@kodehoved.dk.  Jeg glæder mig til at se, hvad I finder på.

Spørgsmål: Skriv en kommentar.

Update: Jeg havde desværre lavet en fejl i testen TheBug. Der skal naturligvis bruges Assert.IsTrue(). Input er jo et password, der ikke overholder reglerne, men som mod forventning bliver godtkendt. Jeg ved godt, at det ikke er hittet med en subtil fejl her, men det var altså ikke med vilje.