Klassen Algorithmus für das folgende Problem entwickeln?

Diskutiere Algorithmus für das folgende Problem entwickeln? im Allgemeine Java-Themen Bereich.
L

lam_tr

Hallo zusammen,

ich stehe mal wieder vor ein Problem womit ich es nicht programmieren kann, oder zumindest nicht schön.

Im folgenden Bild habe ich 12 Kacheln, jede Kachelhat eine bestimmte Bezeichnung, das kommt vom chinesischen und steht jeweils für ein Tier. An sich fange ich bei Ty mit der Id und im Uhrzeigersinn wird immer um1 incrementiert. Weiter hat jede Kachel ein Monat mit sich.
12314
Ich will über ein Algorithmus eine bestimmte Kachel finden mit folgende Angaben:
1. Geburtsmonat
2. Geburtsuhrzeit, wobei hier nur die Stunden eine Rolle spielen.

Die Kacheln habe ich jeweils in ein Enum Chi mit den Monaten gespeichert wie folgt (hellgraue Wert steht für Monate):
12316

Beispiel: August hat den Kachel Dau.

Jetzt müsste ich noch die Geburtstuhrzeit einbeziehen und die Kacheln rückwärtslaufen

Beispiel August 14 Uhr, wenn ich auf die erste Abbildung schaue, bin ich bei Kachel Dau mit Monat August, 14 Uhr entspricht die untere Tabelle 7 Schritte zurücklaufen gegen Uhrzeigersinn, d.h. wir sind jetzt bei Mau.

Ergebnis: August 14 Uhr entsprich 1. Dau, 2. Mau

12317

Wie würdet ihr diesen Algo entwickeln?
Code:
public class Algo {

    public static void main(String[] args) {
        int birthmonth = 8;
        int birthtime = 14;
        
        for (Chi chi : Chi.values()) {
            if (chi.getValue()==birthmonth) {
                // an der Stelle ist es Dau               
            }
        }
    }
}
Ich hänge gerade bei dem zurücklaufen der Kacheln, was ist wenn das Zurücklaufen bis Ty (im Enum) geht, dann geht es mit Hoi, Tuat, Dau, etc. Ich denke Modulo ist an der Stelle richtig oder? Aber wie gehe ich da am Besten vor?
 

Anhänge

M

mrBrown

Spontan:

Dem enum eine statische Methode getForMonth(int month) geben, der kann dann entweder über iterieren oder über ne Map oder über den ordinal das passende für den Chi(?) zurückgeben. Zusätzlich ne Methode, die für gegebenes Chi(?) und Uhrzeit das passende zurückliefert, für das Berechnen ist %(*) dabei richtige, man muss nur negative Werte passend beachten, am einfachsten in dem man grundsätzlich vorher um 12 erhöht.



(* in Java btw Remainder und nicht Modulo, auch wenns hier keinen Unterschied macht)
 
Thallius

Thallius

Irgendwie erschließt sich mir dein Beispiel nicht. Wenn 14 Uhr NGO entspricht und das 7 Schritte gegen den Uhrzeigersinn von DAU bedeutete, dann komme ich auf DAN und nicht MAU?

Weiterhin ist mir nicht Kar, warum du dann nicht einfach die IDs entsprechend den Monaten vergibst. Wenn DAU dann 8 wäre, wäre DAN dann 8 - Uhrzeit / 2 = 1. Also wäre der erste einfach der mit der id = monat und der zweite = das Ergebnis der ersten Rechnung minus der Uhrzeit / 2.

Da fügt sich dann alles automatisch

Gruß

Claus
 
L

lam_tr

Spontan:

Dem enum eine statische Methode getForMonth(int month) geben, der kann dann entweder über iterieren oder über ne Map oder über den ordinal das passende für den Chi(?) zurückgeben. Zusätzlich ne Methode, die für gegebenes Chi(?) und Uhrzeit das passende zurückliefert, für das Berechnen ist %(*) dabei richtige, man muss nur negative Werte passend beachten, am einfachsten in dem man grundsätzlich vorher um 12 erhöht.



(* in Java btw Remainder und nicht Modulo, auch wenns hier keinen Unterschied macht)
Ist echt toll das du mein Problem verstanden hast, ich dachte schon das es zu kompliziert beschrieben ist.

Ich habe das mal so gemacht, aber irgendwas stört mich da noch, hast du da einen Vorschlag?

Code:
public class Algo {

    public static void main(String[] args) {
        Algo algo = new Algo();
        Chi chi1 = algo.findBy(8, 14);
        System.out.println(chi1);
        
        Chi chi2 = algo.findBy(8, 20);
        System.out.println(chi2);
    }

    private Chi findBy(int birthMonth, int birthTime){
        int steps =    getStepBacks(birthTime);
        if (steps > birthMonth) {
            steps = steps - birthMonth;
            steps = Chi.values().length-steps;
            return getChiByMonth(steps);
        }else {
            return getChiByMonth(birthMonth-steps);
        }
    }

    private Chi getChiByMonth(int month) {
        for (Chi chi : Chi.values()) {
            if (chi.getValue()==month) {
                return chi;
            }
        }
        return null;
    }
    
    private Integer getStepBacks(int birthtime) {
        if (0 < birthtime && birthtime <= 2)
            return 0;
        else if (2 < birthtime && birthtime <= 4)
            return 1;
        else if (4 < birthtime && birthtime <= 6)
            return 2;
        else if (6 < birthtime && birthtime <= 8)
            return 3;
        else if (8 < birthtime && birthtime <= 10)
            return 4;
        else if (10 < birthtime && birthtime <= 12)
            return 5;
        else if (12 < birthtime && birthtime <= 14)
            return 6;
        else if (14 < birthtime && birthtime <= 16)
            return 7;
        else if (16 < birthtime && birthtime <= 18)
            return 8;
        else if (18 < birthtime && birthtime <= 20)
            return 9;
        else if (20 < birthtime && birthtime <= 22)
            return 10;
        else if (22 < birthtime && birthtime <= 24)
            return 11;
        return null;
    }
}
 
M

mrBrown

getStepBacks kürzen auf return birthtime/2

in findBy(int birthMonth, int birthTime) kannst du das if ersetzen mit (birthMonth+12 - steps) & 12 (wenn ich mich nicht verrechnet hab, ab besten einmal testen...)

Und dann alles direkt in die Chi-Klasse :)

getChiByMonth kann man dann lösen mit Map oder Ordinal, ist kürzer und schneller.
 
L

lam_tr

getStepBacks kürzen auf return birthtime/2

in findBy(int birthMonth, int birthTime) kannst du das if ersetzen mit (birthMonth+12 - steps) & 12 (wenn ich mich nicht verrechnet hab, ab besten einmal testen...)

Und dann alles direkt in die Chi-Klasse :)

getChiByMonth kann man dann lösen mit Map oder Ordinal, ist kürzer und schneller.
Ich habe für beide Anpassungen komplett andere Ergebnisse raus.

Was meinst du den mit Ordinal?
 
M

mrBrown

Ich habe für beide Anpassungen komplett andere Ergebnisse raus.
Oh, bei ersten muss es (birthtime-1)/2 sein, hab übersehen das bei deinen if's die untere Grenze exklusiv und die obere inklusive ist...

Oh, und in der Rechnung sollte es ein % und kein & sein, damit kommt da natürlich Unsinn raus -.-

Was meinst du den mit Ordinal?
https://docs.oracle.com/javase/7/docs/api/java/lang/Enum.html#ordinal(), entspricht der Position der Deklaration und im values-Array.
 
L

lam_tr

Oh, bei ersten muss es (birthtime-1)/2 sein, hab übersehen das bei deinen if's die untere Grenze exklusiv und die obere inklusive ist...

Oh, und in der Rechnung sollte es ein % und kein & sein, damit kommt da natürlich Unsinn raus -.-


https://docs.oracle.com/javase/7/docs/api/java/lang/Enum.html#ordinal(), entspricht der Position der Deklaration und im values-Array.
So jetzt sind wir ein Schritt weiter. Die erste Anpassung klappt, die zweite nicht.

Code:
    private Chi findBy(int birthMonth, int birthTime){
        int steps =    getStepBacks(birthTime);
//        if (steps > birthMonth) {
//            steps = steps - birthMonth;
//            steps = Chi.values().length-steps;
//            return getChiByMonth(steps);
//        }else {
//            return getChiByMonth(birthMonth-steps);
//        }
        int result = (birthMonth+12 - steps) & 12;
        return Chi.values()[result];
    }
Hiermit bekomme ich diese Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 12
Also bei der zweiten Anpassung gibt der allgemein ein anderer Wert an wie ich erwarte.

Und wegen dem Ordinal, soll ich das so machen

Code:
    private Chi getChiByMonth(int month) {
        for (Chi chi : Chi.values()) {
            if (chi.ordinal()==month) {
                return chi;
            }
        }
        return null;
    }
Hast du Tipps für mich wie ich solche Optimiereungen sehen kann?
 
M

mrBrown

Hiermit bekomme ich diese Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 12
Das & ersetzen mit % :)

Und wegen dem Ordinal, soll ich das so machen

private Chi getChiByMonth(int month) {
for (Chi chi : Chi.values()) {
if (chi.ordinal()==month) {
return chi;
}
}

return null;
}
Ne, wenn man eine Schleife nutzt, war deine Variante passend, wenn man ordinal nutzen will, würde man das direkt als Index für das Array nutzen, dafür müsste an aber ein eindeutiges Mapping von ordinal<=>month haben. Dann wäre das etwa Chi.values()[month]. In deinem Fall müsste man aber vermutlich noch Monat auf Ordinal Mappen, wenn ich das oben richtig sehe entspricht Monat 11 =>Ordinal 0, Monat 12=>1, 0=>2, usw ...
 
L

lam_tr

Das & ersetzen mit % :)



Ne, wenn man eine Schleife nutzt, war deine Variante passend, wenn man ordinal nutzen will, würde man das direkt als Index für das Array nutzen, dafür müsste an aber ein eindeutiges Mapping von ordinal<=>month haben. Dann wäre das etwa Chi.values()[month]. In deinem Fall müsste man aber vermutlich noch Monat auf Ordinal Mappen, wenn ich das oben richtig sehe entspricht Monat 11 =>Ordinal 0, Monat 12=>1, 0=>2, usw ...
Ok jetzt gehts, ist zwar um ein Index versetz, ich habe zu dem Steps einfach 1 addiert.

Code:
private Chi findBy(int birthMonth, int birthTime){
        int steps =    getStepBacks(birthTime);
        int result = (birthMonth+12 - steps+1) % 12;
        return Chi.values()[result];
    }
Und ja Monat 11 wird zum ordinal 0 hinzugefügt,etc.
 
M

mrBrown

Ich würde getChiByMonth schon da lassen, dann bleiben die Methoden auf einer Abstraktionsebene.


findBy rechnet dann nur mit Monaten und Verschiebung (=fachliches Detail), getChiByMonth sorgt für das Mapping Month<=>ordinal (=technisches Detail).
 
L

lam_tr

Hi Mr Brown,

ich habe noch eine weitere Herausforderung und zwar will ich immer Paare zusammen haben.

12318

Zum Beispiel:
Id 1 kennt Id5 (grün)
Id 2 kennt Id4
Id 4 kennt Id2 (schwarz)
Id 5 kennt Id1 (schwarz)

An sich sollen alle schwarzen und grünen Pfeile abgebildet werden.

Ich habe eine direkte Abbildung über switch case oder if else gemacht.
Code:
switch(chi){
            case MUI: return Chi.DAU
            case NGO: return Chi.TUAT
            case TI: return Chi.HOI
            case THIN: return Chi.TY
            case MAO: return Chi.SUU
            case THAN: return Chi.DAN
            case DAN: return Chi.THAN
            case DAU: return Chi.MUI
            case TUAT: return Chi.NGO
            case HOI: return Chi.TI
            case TY: return Chi.THIN
            case SUU: return Chi.MAO
            default: return null
        }
Hast du eine Idee wie man das anders schön machen kann? Vorallem gefällt mir der default case mit return null nicht.
 
L

lam_tr

Man könnte auch da ne Map<Chi,Chi> nutzen, dann wäre es nur ein return get(chi)


throw new AssertionError(...) :)
Guten morgen MrBrown,

beim weiterentwickeln habe ich erst gemerkt, dass der Januar nicht in dem Kacheln fest ist, ich muss ess eher dynamisch machen, da es sich oftmals ändert.

Ist es besser in eine Map zu machen und mit Remainder vorzugehen oder?
 
L

lam_tr

Also Initial ist der Januar auf Id 3, aber später wechselt es zu Id 12 und andere. Aber jedes mal wenn es sich ändert weiss ich das. An sich brauche ich eher ein Zeiger, der die Monaten mitverschiebt.

Wie kann man das berechnen lassen, wenn ich es nicht in eine Map mache?
Aber selbst mit der Map hätte ich je nach Id immer durchiteriert und die Monate neugesetzt.

Was ist dein Vorschlag?
 
M

mrBrown

Einfach die "Verschiebung" bei der Berechnung, die du ja schon hast, zusätzlich abziehen/addieren
 
L

lam_tr

Einfach die "Verschiebung" bei der Berechnung, die du ja schon hast, zusätzlich abziehen/addieren
@mrBrown , Stimmt :)

Was ist wenn ich nicht weiß um wieviele Schritte ich vor oder zurückbewegen, ich weiss nur auf welchen Kachelnamen ich es setzten
Code:
    public Chi resetJanuaryToChi(int steps) {
        int index = (Chi.DAN.getValue()+12+steps)%12;
        return Chi.values()[index];
    }

    public Chi resetJanuaryToChi(Chi newChi) {
        int index = (Chi.DAN.getValue()+12-3)%12;
        return Chi.values()[index];
    }
soll?

Die erste Methode ist klar, aber ich benötige die zweite Methode. Ich habe immer fix bei Chi.DAN den Januar und will anhand von dem neu gewählten Chi den Januar setzen. Wie bekomme ich den Abstand her?
 
Zuletzt bearbeitet:
L

lam_tr

Die Reihenfolge der Kacheln ist fix?
Die Reihenfolge der Kacheln ist fix?
Hallo mihe7,

ja die Reihenfolge der Kacheln mit den Chi-Namen sind fix. Nur die Monate sind dynamisch

Code:
    public Chi resetJanuaryToChi(Chi newChi) {
        int steps = Math.abs(Chi.DAN.ordinal()-newChi.ordinal());
        return resetJanuaryToChi(steps);
    }

    public Chi resetJanuaryToChi(int steps) {
        int index = (Chi.DAN.ordinal()+12+steps)%12;
        return Chi.values()[index];
    }
So würde es gehen oder?
 
mihe7

mihe7

Das funktioniert im Allgemeinen nicht, da Deine Berechnung von steps nur den Abstand aber nicht die Richtung liefert.

Wenn Chi.DAN.ordinal() == 2 und Chi.SUU.ordinal() == 1 und Chi.MAO.ordinal() == 3, dann haben SUU und MAO den selben Abstand von DAN, nämlich 1.
 
L

lam_tr

Ja ich war zu sehr fixiert auf vorwärts gewesen, aber dann führe ich noch eine weitere variable für vor oder rückwärts ein.
 
L

lam_tr

Wozu? Die Richtung gibt Dir ja schon das Vorzeichen an :)

Code:
1-2 = -1
3-2 = +1
Dann kommen wir wieder zurück zu deine Frage, an welche Stelle weiß ich ob der nach vorne oder zurückläuft die Schritte.

Im überhaupt zu wissen welches Vorzeichen ich benutzen soll?
 
mihe7

mihe7

Du willst das positive Offset relativ zu DAN berechnen.

Das ggf. negative Offset ist ja einfach newChi.ordinal() - Chi.DAN.ordinal(). Darauf addierst Du 12 und rechnest modulo 12, dann hast Du das positive Offset relativ zu DAN.
 
L

lam_tr

Du willst das positive Offset relativ zu DAN berechnen.

Das ggf. negative Offset ist ja einfach newChi.ordinal() - Chi.DAN.ordinal(). Darauf addierst Du 12 und rechnest modulo 12, dann hast Du das positive Offset relativ zu DAN.
Irgendwie komme ich mit der Berechnung nicht auf das positive relative zu DAN. Wenn ich jetzt HOI als Ziel setze ist das Ordinal 12 und Ordinal von DAN ist 3. Also (((3-12)+12)%12)=3, aber es sollte doch 9 sein oder?

Irgendwie kann ich einfach nicht logisch denken bei sowas, wie kann man sowas den am Besten anlerne, anstatt auswendig lernen?


P.S. Durch Rumprobieren ist das eher die
Code:
int steps = ((newChi.ordinal()-Chi.DAN.ordinal())+12)%12;
 
Zuletzt bearbeitet:
mihe7

mihe7

Du rechnest falsch rum: das ggf. negative Offset ist: 12 - 3 (und nicht 3 - 12). Das ergibt 9 und (9 + 12) % 12 = 9
 
mihe7

mihe7

Irgendwie kann ich einfach nicht logisch denken bei sowas, wie kann man sowas den am Besten anlerne, anstatt auswendig lernen?
Visualisieren hilft fast immer:
Code:
Key   Ordinal
TY       0
SUU      1
DAN      2     *
MAO      3     |
THIN     4     |
TI       5     |
NGO      6     v
MUI      7
THAN     8
DAU      9
TUAT    10
HOI     11

Der Pfeil rechts zeigt vom Ausgangspunkt (DAN) zum Zielpunkt (NGO). Pfeil sollte Dir von Vektoren bekannt sein: Spitze minus Fuß: 6 - 2 = 4 -> Tada.

Code:
Key   Ordinal
TY       0     ^
SUU      1     |
DAN      2     *
MAO      3     
THIN     4     
TI       5     
NGO      6     
MUI      7
THAN     8
DAU      9
TUAT    10
HOI     11
DAN nach TY. Spitze minus Fuß = 0 - 2 = -2, Du musst also von DAN aus, 2 zurück oder eben (12 - 2) = 10 nach vorne.
 
L

lam_tr

Vielen Dank für die Aufzeichnung, ich habe das bestimmt schon 20 mal aufgezeichnet und gerate dabei einfach ins Chaos :)

Da ich so viel rumspringen musste von einen Chi zum anderen, habe ich einfach 3 Methoden dafür erweitert

Code:
    public int getSteps(Chi startChi, Chi endChi) {
        return ((endChi.ordinal()-startChi.ordinal())+12)%12;
    }
    
    public Chi getPreviousChi(Chi chi, int backSteps) {
        int index = ((chi.ordinal()-backSteps)+12)%12;
        return Chi.values()[index];
    }
    
    public Chi getNextChi(Chi chi, int additionalSteps) {
        int index = ((chi.ordinal()+additionalSteps)+12)%12;
        return Chi.values()[index];
    }

Vielen Dank für euren Engangement bis hierhin! *Daumenhoch*
 
Thema: 

Algorithmus für das folgende Problem entwickeln?

Passende Stellenanzeigen aus deiner Region:
Anzeige

Neue Themen

Anzeige

Anzeige
Oben