python zufall

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Franzigrf
User
Beiträge: 3
Registriert: Freitag 3. März 2017, 17:35

Huhu :)
Ich habe heute von meinem Lehrer diese Aufgabe bekommen:
34 Damen sind auf 8 Zimmer zu verteilen. 7 x 4-Bettzimmer und ein 6-Bettzimmer.
Schreibe ein Programm. das per Zufallsprinzip die Damen auf die Zimmer verteilt.

Mein Programm sieht leider noch sehr mager aus :
from random import randint
mädchen = [(randint(1, 35))]

print(mädchen)

liste = []
mädchen.append(liste)

Ich danke für jede Hilfe!
BlackJack

@Franzigrf: Was ist eine ”Dame” und was ist ein ”Zimmer”? Also wie sollen diese ”Dinge” im Programm repräsentiert werden? Warum 35 bei 34 Personen?
Franzigrf
User
Beiträge: 3
Registriert: Freitag 3. März 2017, 17:35

@BlackJack:

Also jede Dame/Mädchen bekommt eine Nummer von 1 - 34 zugeteilt und diese sollen mittels zufall in vierer zimmer verteilt werden. 1 - 35, das sind bei python ja dann 34 zahlen :)
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

Vorschlag für einen Ansatz: beschreib' das Vorgehen, was du wählen würdest, in normaler Sprache, unterteilt in sinnvolle Teilprobleme. Und dann fängst du an, dass Schritt-für-Schritt auszuprogrammieren.

Wie viel Python habt ihr in dem Kurs denn schon gelernt?

Gruß, noisefloor
BlackJack

@Franzigrf: 1 bis 35 sind auch in Python 35 Zahlen und nicht 34. Die Frage wie ein Zimmer im Programm repräsentiert werden soll, hast Du jetzt nicht beantwortet. Ich habe da schon eine Ahnung, aber das ist ja *Deine* Aufgabe. :-)
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

`random.shuffle` is your friend.

Genug gespoilert ;)
BlackJack

Eine Lösung in C. :-)
[codebox=c file=Unbenannt.c]#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define PERSON_COUNT 34
#define ROOM_COUNT 8

typedef struct
{
uint8_t capacity;
uint8_t *persons;
} Room;


int main(void) {
uint8_t persons[PERSON_COUNT];
uint8_t i, j, tmp;
Room rooms[ROOM_COUNT];
Room *room;

srand(clock());

/* Initialise person numbers. */
for (i = 0; i < PERSON_COUNT; ++i) persons = i + 1;

/* Initialise room capacities. */
for (i = 0; i < ROOM_COUNT; ++i) rooms.capacity = 4;
rooms[ROOM_COUNT - 1].capacity = 6;

/* Shuffle the persons. */
for (i = 0; i < PERSON_COUNT - 1; ++i) {
j = i + rand() % (PERSON_COUNT - i);
tmp = persons;
persons = persons[j];
persons[j] = tmp;
}

/* Assign the persons to the rooms. */
for (i = j = 0, room = rooms; i < ROOM_COUNT; ++i, ++room) {
room->persons = &persons[j];
j += room->capacity;
}
assert(j == PERSON_COUNT);

/* Print the rooms with the assigned persons. */
for (i = 1, room = rooms; i <= ROOM_COUNT; ++i, ++room) {
printf("Room %d: ", i);
for (j = 0; j < room->capacity; ++j) {
printf(
"%2d%s",
room->persons[j],
(j == room->capacity - 1) ? ".\n" : ", "
);
}
}

return 0;
}
[/code]
Franzigrf
User
Beiträge: 3
Registriert: Freitag 3. März 2017, 17:35

@BlackJack
Danke :)
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@Franzigrf: Hausaufgaben sollt ihr ja selbst lösen, damit ihr etwas lernt. Dennoch: da die Aufgabe so schön ist, hier eine Lösung von der ich annehme, dass einige Konstrukte vorkommen, die ihr im Unterricht (noch) nicht gehabt habt. Es wäre daher vermutlich keine gute Idee, dies dem Lehrer als eigene Lösung zu präsentieren. Das lesen anderer Lösungen kann zum Lernen aber durchaus hilfreich sein, um eigene zu finden und umzusetzen. BlackJack hat dafür in C bereits vorweg genommen, was dein Lehrer als Lösung vermutlich erwartet.

Begeben wir uns nun ins (Mädchen-)Internat. Die Mädchen stehen schön ordentlich in der Reihe und warten auf ihre Zimmer. Vorne steht die Gouvernante und will ganz phantasielos eins nach dem anderen in das erste Zimmer stecken bis dieses voll ist und dann mit den anderen Zimmern so fortfahren. Nun sollen die Mädchen aber zufällig aufgeteilt werden und so ordnet sie an, dass alle wild durcheinander laufen und sich erneut der Reihe nach aufstellen. Das ist 'shuffle'.

Nun aber kommt die neue flotte Referendarin daher und bringt einen sprechenden Hut mit, der jedem Mädchen sagt, auf welches Zimmer es soll. Sie bleiben also alle schön ordentlich in der Reihe stehen und warten gespannt darauf, welches Zimmer sie erhalten. Das ist 'choice'.

Hier eine Lösung mit Hut:

Code: Alles auswählen

import random


class Room:
    
    def __init__(self, capacity):
        self.capacity = capacity
        self.residents = []
        
    def __str__(self):
        return 'capacity: {}, residents: {}'.format(self.capacity, self.residents)
    
    @property
    def is_full(self):
        return self.capacity <= len(self.residents)
                

def distribute():
    capacities = [4] * 7 + [6]
    rooms = [Room(capacity) for capacity in capacities]
    full_rooms = []

    for resident in range(1, 35):
        # hier spricht der Hut:
        room = random.choice(rooms)
        room.residents.append(resident)
        if room.is_full:
            rooms.remove(room)
            full_rooms.append(room)
    
    for room in full_rooms:
        print(room)
            
            
if __name__ == '__main__':
    distribute()
BlackJack

@kbr: Das ist IMHO ein bisschen fragil mit `full_rooms`. Wenn weniger Damen vorhanden sind als Plätze in den Zimmern, dann werden am Ende nur die voll besetzten Räume ausgegeben und nicht die teilbelegten. Ich würde ja eine `rooms`-Liste anlegen und für den Algorithmus die dann kopieren und daraus dann nur die vollen Räume entfernen bis entweder die Räume mit freien Plätzen alle sind, oder die Damen.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@BlackJack: ja, das ist fragil. Ein Raum zu wenig und es gibt eine Exception, teilbelegte Zimmer werden nicht angezeigt. Es darf bei einer Hausaufgabe aber auch noch Raum für Verbesserungen geben :wink:
BlackJack

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. :-D)
[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.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@BlackJack: sensationell. Bist Du Masochist oder Sadist? 8)
BlackJack

@kbr: Beides‽ Nee, das meiste hat ja die IDE gemacht. Ich habe es erst halbwegs ”vernünftig” mit den drei Klassen gelöst und dann die abstrakte Klasse und die Interfaces per Refactoring heraus gezogen. Als Grafik ist's vielleicht übersichtlicher:
Bild
Wie gesagt, man könnte da noch Generics mit einbauen. Und Dein Beitrag schreit ja fast danach das Strategy-Pattern für das Verteilen der Personen auf die Zimmer zu implementieren. :-D
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@BlackJack: nur zu! :)
BlackJack

@kbr: Och nööö. Lieber was, was dem OP etwas direkter helfen könnte, weil ich gerade mit PlantUML herum spiele, mal der Ablauf der beiden Varianten auf was man beim Verteilen den Zufall anwenden kann:
Bild
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

BlackJack hat geschrieben:@kbr: Och nööö.
@BlackJack: nachdem Du einmal in Fahrt warst, wollte ich Dich nicht bremsen :wink: . Aber obiges Diagramm ist für den OP gewiss viel hilfreicher.
Antworten