diff --git a/code/roman-numerals/src/main/java/fr/istic/vv/RomanNumeraUtils.java b/code/roman-numerals/src/main/java/fr/istic/vv/RomanNumeraUtils.java index a37e18a..857046c 100644 --- a/code/roman-numerals/src/main/java/fr/istic/vv/RomanNumeraUtils.java +++ b/code/roman-numerals/src/main/java/fr/istic/vv/RomanNumeraUtils.java @@ -1,11 +1,154 @@ package fr.istic.vv; +import java.util.HashMap; +import java.util.Map; + public class RomanNumeraUtils { + + final static Map mapToNum = new HashMap<>(); + static { + mapToNum.put('M', 1000); + mapToNum.put('D', 500); + mapToNum.put('C', 100); + mapToNum.put('L', 50); + mapToNum.put('X', 10); + mapToNum.put('V', 5); + mapToNum.put('I', 1); + } + + public static boolean isValidRomanNumeral(String value) { + boolean isValid = true; + + char lastChar = ' '; + int nbLastChar = 0; + int valMax = 1001; + + for(int i = 0; imapToNum.get(lastChar)){ + //seul I X C peuvent soustraire un symbole (ex : IX XC CM) + if(lastChar == 'I' || lastChar == 'X' || lastChar == 'C'){ + valMax = mapToNum.get(lastChar)-1; + //si plus de 1 soustraction (ex IIX) ou que la soustraction est ni 1/10 ni 1/5 du chiffre le plus grand + if(nbLastChar>1 || !(mapToNum.get(val)/10==mapToNum.get(lastChar) || mapToNum.get(val)/5==mapToNum.get(lastChar))){ + isValid = false; + } + } + else isValid = false; + } + + } + switch (val){ + case 'M': + case 'C': + case 'X': + case 'I': + if(lastChar==value.charAt(i)){ + nbLastChar++; + if(nbLastChar>3) isValid = false; + } + else{ + lastChar = value.charAt(i); + nbLastChar = 1; + } + break; + case 'D': + case 'L': + case 'V': + if(lastChar==value.charAt(i)){ + nbLastChar++; + if(nbLastChar>1) isValid = false; + } + else{ + lastChar = value.charAt(i); + nbLastChar = 1; + } + break; + default: + isValid = false; + } + } + else isValid = false; + } + + return isValid; + } + + public static int parseRomanNumeral(String numeral) { + if(isValidRomanNumeral(numeral)){ + + int res = 0; + char lastChar = ' '; + + for(int i = 0; ivalue){ //XIX + res += 0; + } // - + else if(lastChar!=' ' && value>mapToNum.get(lastChar)){ //IX + res += value-mapToNum.get(lastChar); + } + else{ + res +=mapToNum.get(val); + } + lastChar = val; + } + return res; + } + else throw new IllegalArgumentException("Invalid date"); + + } + + public static String toRomanNumeral(int number) { + System.out.println(number); + String res = ""; + char[] order = {'M','D','C','L','X','V','I'}; + char[] sub = {'I','X','C'}; + if(number<4000){ + while(number>0){ + boolean notFound = true; + for(int i = 0; i=val){ + number -= val; + res = res + symb; + System.out.println(res); + notFound = false; + } + else{ + boolean notFoundSub = true; + for(int j = 0; j=val-valSub){ + number -= val-valSub; + res = res + symbSub + symb; + System.out.println(res); + notFoundSub = false; + notFound = false; + } + } + + } + } + + } + } + System.out.println("Return : " + res); + return res; + } + else throw new IllegalArgumentException("max 4000"); - public static boolean isValidRomanNumeral(String value) { return false; } - - public static int parseRomanNumeral(String numeral) { return 0; } - - public static String toRomanNumeral(int number) { return ""; } - + } + } diff --git a/code/roman-numerals/src/test/java/fr/istic/vv/RomanNumeralTest.java b/code/roman-numerals/src/test/java/fr/istic/vv/RomanNumeralTest.java index ded8e7a..c3b9972 100644 --- a/code/roman-numerals/src/test/java/fr/istic/vv/RomanNumeralTest.java +++ b/code/roman-numerals/src/test/java/fr/istic/vv/RomanNumeralTest.java @@ -1,8 +1,120 @@ package fr.istic.vv; import net.jqwik.api.*; import net.jqwik.api.constraints.IntRange; +import static fr.istic.vv.RomanNumeraUtils.*; public class RomanNumeralTest { + + + + @Example + void simpleValidRomanNumerals() { + assert isValidRomanNumeral("I"); + assert isValidRomanNumeral("II"); + assert isValidRomanNumeral("III"); + assert isValidRomanNumeral("IV"); + assert isValidRomanNumeral("VI"); + assert isValidRomanNumeral("VIII"); + assert isValidRomanNumeral("IX"); + assert isValidRomanNumeral("X"); + assert isValidRomanNumeral("XI"); + assert isValidRomanNumeral("MI"); + assert isValidRomanNumeral("XIII"); + } + + @Example + void nonValidRomanNumeralsBadLetter() { + assert !isValidRomanNumeral("IIIA"); + assert !isValidRomanNumeral("A"); + assert !isValidRomanNumeral("CAI"); + } + + @Example + void nonValidRomanNumeralsRepeated() { + assert !isValidRomanNumeral("IIII"); + assert !isValidRomanNumeral("XXXX"); + assert !isValidRomanNumeral("CCCC"); + assert !isValidRomanNumeral("MMMM"); + assert !isValidRomanNumeral("DD"); + assert !isValidRomanNumeral("LL"); + assert !isValidRomanNumeral("VV"); + } + + @Example + void validRomanNumeralsLeftSub() { + assert isValidRomanNumeral("IV"); + assert isValidRomanNumeral("IX"); + assert isValidRomanNumeral("XL"); + assert isValidRomanNumeral("XC"); + assert isValidRomanNumeral("CD"); + assert isValidRomanNumeral("CM"); + + } + + @Example + void nonValidRomanNumeralsLeftSub() { + assert !isValidRomanNumeral("VX"); + assert !isValidRomanNumeral("VL"); + assert !isValidRomanNumeral("IL"); + assert !isValidRomanNumeral("IC"); + assert !isValidRomanNumeral("VC"); + assert !isValidRomanNumeral("LC"); + assert !isValidRomanNumeral("ID"); + assert !isValidRomanNumeral("VD"); + assert !isValidRomanNumeral("XD"); + assert !isValidRomanNumeral("LD"); + assert !isValidRomanNumeral("IM"); + assert !isValidRomanNumeral("VM"); + assert !isValidRomanNumeral("XM"); + assert !isValidRomanNumeral("LM"); + assert !isValidRomanNumeral("DM"); + } + + @Example + void completValidRomanNumerals() { + assert isValidRomanNumeral("MCDXXXIV"); + assert isValidRomanNumeral("DCCLXXXIX"); + assert isValidRomanNumeral("LXIX"); + assert isValidRomanNumeral("MCCXXXIV"); + + } + + @Example + void completNonValidRomanNumerals() { + assert !isValidRomanNumeral("IXX"); + assert !isValidRomanNumeral("IXIXIX"); + assert !isValidRomanNumeral("MMMDCCCLIXXXVIII"); + assert !isValidRomanNumeral("XIXV"); + + } + + + @Example + void testParseRomanNumeral() { + assert parseRomanNumeral("XX")==20; + assert parseRomanNumeral("XIX")==19; + assert parseRomanNumeral("XXI")==21; + assert parseRomanNumeral("IX")==9; + assert parseRomanNumeral("MCCXXXIV")==1234; + } + + + + + @Example + void testToRomanNumeral() { + assert toRomanNumeral(20).compareTo("XX")==0; + assert toRomanNumeral(19).compareTo("XIX")==0; + assert toRomanNumeral(21).compareTo("XXI")==0; + assert toRomanNumeral(9).compareTo("IX")==0; + assert toRomanNumeral(1234).compareTo("MCCXXXIV")==0; + assert toRomanNumeral(3999).compareTo("MMMCMXCIX")==0; + } + + + + + @Property boolean absoluteValueOfAllNumbersIsPositive(@ForAll @IntRange(min=Integer.MIN_VALUE +1) int anInteger) { return Math.abs(anInteger) >= 0; diff --git a/code/roman-numerals/target/classes/fr/istic/vv/RomanNumeraUtils.class b/code/roman-numerals/target/classes/fr/istic/vv/RomanNumeraUtils.class index 9cae7b4..72c1d5f 100644 Binary files a/code/roman-numerals/target/classes/fr/istic/vv/RomanNumeraUtils.class and b/code/roman-numerals/target/classes/fr/istic/vv/RomanNumeraUtils.class differ diff --git a/code/roman-numerals/target/test-classes/fr/istic/vv/RomanNumeralTest.class b/code/roman-numerals/target/test-classes/fr/istic/vv/RomanNumeralTest.class index 6884cff..6e32f2f 100644 Binary files a/code/roman-numerals/target/test-classes/fr/istic/vv/RomanNumeralTest.class and b/code/roman-numerals/target/test-classes/fr/istic/vv/RomanNumeralTest.class differ