Schlagwort-Archiv: Kata

Roman Numbers Converter

package de.sambalmueslie.number_convert;

import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class RomanNumberConverter implements NumberConverter {

	private class MappingEntry {

		public MappingEntry(final int number, final char symbol) {
			this(number, symbol, false);
		}

		public MappingEntry(final int number, final char symbol, final boolean subtractable) {
			this.number = number;
			this.symbol = symbol;
			this.subtractable = subtractable;
		}

		private final int number;
		private final boolean subtractable;
		private final char symbol;
	}

	public RomanNumberConverter() {
		mappings.add(new MappingEntry(1, 'I', true));
		mappings.add(new MappingEntry(5, 'V'));
		mappings.add(new MappingEntry(10, 'X', true));
		mappings.add(new MappingEntry(50, 'L'));
		mappings.add(new MappingEntry(100, 'C', true));
		mappings.add(new MappingEntry(500, 'D'));
		mappings.add(new MappingEntry(1000, 'M'));
	}

	@Override
	public String convert(final int value) {
		final StringBuffer result = new StringBuffer();

		int remaining = value;

		final int start = mappings.size() - 1;
		for (int index = start; index >= 0; index--) {
			final MappingEntry current = mappings.get(index);
			final MappingEntry next = index > 0 ? mappings.get(index - 1) : null;
			final MappingEntry doubleNext = index > 1 ? mappings.get(index - 2) : null;

			final int number = current.number;
			final boolean matches = remaining >= number;
			if (matches) {
				final int amount = remaining / number;
				result.append(concat(current.symbol, amount));
				remaining -= number * amount;
			} else if (next != null && next.subtractable && remaining >= number - next.number) {
				result.append(next.symbol + "" + current.symbol);
				remaining -= number - next.number;
			} else if (doubleNext != null && doubleNext.subtractable && remaining >= number - doubleNext.number) {
				result.append(doubleNext.symbol + "" + current.symbol);
				remaining -= number - doubleNext.number;
			}

		}
		return result.toString();
	}

	@Override
	public int convert(final String value) {
		final List<Integer> numbers = value.chars().map(t -> find(t).number).boxed().collect(Collectors.toList());
		for (int i = 0; i < numbers.size() - 1; i++) {
			if (numbers.get(i) < numbers.get(i + 1)) {
				numbers.set(i, numbers.get(i) * -1);
			}
		}
		return numbers.stream().mapToInt(t -> t).sum();
	}

	private String concat(final char c, final int amount) {
		final StringBuffer sb = new StringBuffer();
		Stream.generate(() -> c).limit(amount).forEach(t -> sb.append(t));
		return sb.toString();
	}

	private MappingEntry find(final Integer c) {
		final Optional<MappingEntry> result = mappings.stream().filter(n -> n.symbol == c).findFirst();
		return result.isPresent() ? result.get() : null;
	}

	private final List<MappingEntry> mappings = new LinkedList<>();
}