Ich finde Python in der Schule ja nicht so toll. Die Schüler verweichlichen dabei zu sehr. Das muss ordentlich mit Klassen, Interfaces, abstrakten Klassen, Zugriffsschutz und dem ganzen Gedöns gelehrt werden. Also in Java!
(Ich geb's ja zu, das `IHasNumber`-Interface musste einfach wegen dem Namen sein.

)
[codebox=java5 file=Unbenannt.java]public interface IHasNumber {
int getNumber();
}[/code]
[codebox=java5 file=Unbenannt.java]import java.util.Collection;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Person implements IHasNumber {
private final int number;
private Person(int number) {
this.number = number;
}
@Override
public int getNumber() {
return number;
}
public static Collection<Person> createMany(int count) {
if (count < 0) {
throw new IllegalArgumentException("count must be positive");
}
return IntStream.rangeClosed(1, count)
.mapToObj(Person::new)
.collect(Collectors.toList());
}
}[/code]
[codebox=java5 file=Unbenannt.java]import java.util.List;
public interface IPersonContainer {
int getCapacity();
int getPersonCount();
int getFreeSpace();
void addPersons(List<IHasNumber> persons);
}[/code]
[codebox=java5 file=Unbenannt.java]import java.util.Collection;
public abstract class AbstractPersonContainer implements IPersonContainer {
@Override
public int getFreeSpace() {
return getCapacity() - getPersonCount();
}
protected void checkSize(Collection persons) {
if (persons.size() > getFreeSpace()) {
throw new IllegalArgumentException("too many persons");
}
}
}[/code]
[codebox=java5 file=Unbenannt.java]import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class Room extends AbstractPersonContainer implements IHasNumber {
private final int roomNumber;
private final int capacity;
private final List<IHasNumber> persons;
public Room(int roomNumber, int capacity) {
if (roomNumber < 0) {
throw new IllegalArgumentException("room number must be positive");
}
if (capacity < 0) {
throw new IllegalArgumentException("capacity must be positive");
}
this.roomNumber = roomNumber;
this.capacity = capacity;
persons = new ArrayList<>(capacity);
}
public int getNumber() {
return roomNumber;
}
@Override
public int getCapacity() {
return capacity;
}
@Override
public int getPersonCount() {
return persons.size();
}
@Override
public void addPersons(List<IHasNumber> persons) {
checkSize(persons);
this.persons.addAll(persons);
}
@Override
public String toString() {
return String.format(
"Room %d (%d/%d): %s",
getNumber(),
getPersonCount(),
getCapacity(),
(getPersonCount() == 0)
? "-/-"
: persons.stream()
.map(p -> String.format("%2d", p.getNumber()))
.collect(Collectors.joining(", ", "", ".")));
}
}[/code]
[codebox=java5 file=Unbenannt.java]import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.ToIntFunction;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Building extends AbstractPersonContainer {
final private List<IPersonContainer> rooms;
public Building(List<Integer> roomCapacities) {
rooms = IntStream.range(0, roomCapacities.size())
.mapToObj(i -> new Room(i + 1, roomCapacities.get(i)))
.collect(Collectors.toList());
}
public int getRoomCount() {
return rooms.size();
}
private int getSum(ToIntFunction<IPersonContainer> getter) {
return rooms.stream().mapToInt(getter).sum();
}
public int getCapacity() {
return getSum(IPersonContainer::getCapacity);
}
@Override
public int getPersonCount() {
return getSum(IPersonContainer::getPersonCount);
}
@Override
public void addPersons(List<IHasNumber> persons) {
checkSize(persons);
int start = 0;
for (IPersonContainer room : rooms) {
final int space = room.getFreeSpace();
room.addPersons(persons.subList(start, start + space));
start += space;
}
}
public void distributeRandomly(Collection<? extends IHasNumber> persons) {
checkSize(persons);
final List<IHasNumber> tmp = new ArrayList<>(persons);
Collections.shuffle(tmp);
addPersons(tmp);
}
@Override
public String toString() {
final int capacity = getCapacity();
final int space = getFreeSpace();
String spaceDescription;
if (space == 0) {
spaceDescription = "full";
} else if (space == capacity) {
spaceDescription = "empty";
} else {
spaceDescription = String.format("%d places free", space);
}
return String.format("Building with %d rooms for %d persons (%s).\n%s",
getRoomCount(),
capacity,
spaceDescription,
rooms.stream()
.map(Object::toString)
.collect(Collectors.joining("\n")));
}
}[/code]
[codebox=java5 file=Unbenannt.java]import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public final class Main {
private static final int PERSON_COUNT = 34;
private Main() {}
public static void main(String... args) {
final List<Integer> roomCapacities = new ArrayList<>(8);
roomCapacities.addAll(Collections.nCopies(7, 4));
roomCapacities.add(6);
final Building building = new Building(roomCapacities);
System.out.println(building);
final Collection<Person> persons = Person.createMany(PERSON_COUNT);
if (building.getFreeSpace() <= persons.size()) {
building.distributeRandomly(persons);
System.out.println(building);
} else {
System.out.println("Too many persons to fit into building.");
}
}
}[/code]
Testlauf:
[codebox=text file=Unbenannt.txt]Building with 8 rooms for 34 persons (empty).
Room 1 (0/4): -/-
Room 2 (0/4): -/-
Room 3 (0/4): -/-
Room 4 (0/4): -/-
Room 5 (0/4): -/-
Room 6 (0/4): -/-
Room 7 (0/4): -/-
Room 8 (0/6): -/-
Building with 8 rooms for 34 persons (full).
Room 1 (4/4): 11, 12, 26, 4.
Room 2 (4/4): 30, 5, 20, 22.
Room 3 (4/4): 2, 27, 17, 31.
Room 4 (4/4): 18, 29, 10, 34.
Room 5 (4/4): 9, 1, 16, 8.
Room 6 (4/4): 14, 6, 3, 19.
Room 7 (4/4): 15, 25, 21, 7.
Room 8 (6/6): 28, 23, 13, 24, 33, 32.[/code]
Man hätte das mit Generics noch ein bisschen generischer (ach nee) machen können, aber dann fing es an schwer lesbar zu werden, weil eben zu generisch wurde, mit nicht wirklich aussagekräftigen Namen.