Frage bezüglich eines "Sprung's"

  • VB.NET

Es gibt 9 Antworten in diesem Thema. Der letzte Beitrag () ist von picoflop.

    Frage bezüglich eines "Sprung's"

    Hallo,

    ich soll in meinen Programmen die ich schreibe ab heute Arrays benutzen. Entsprechend habe ich eine Aufgabe rausgesucht um ein wenig damit dem umgang zu üben. Die Aufgabe sieht vor, das ich einen Automaten habe, der Kleingeld ausgibt je nach Einwurf des Betrags (Fahrkarte kostet 2 Euro, 10 Euro wurden bezahlt --> Restgeld 8 Euro) allerdings soll der Betrag nur in Münzen und mit möglichst wenig Münzen rausgeben. Das Grundgerüst mit den Arrays hat soweit schon gut funktioniert, allrdings wollte ich noch einen draufsetzen und sagen, das der Automat nur eine bestimmte Kapazität an Münzen zur Verfügung hat und wenn diese aufgebraucht sind, an den nächst größten Speicher zu gehen. Ich habe das ganze bisher wiefolgt aufgebaut:

    VB.NET-Quellcode

    1. Dim wechselgeld() As Decimal = {2, 1, 0.5, 0.2, 0.1, 0.05, 0.02, 0.01}
    2. Dim anzahl() As Decimal = {0, 0, 0, 0, 0, 0, 0, 0}
    3. Dim maximum() As Integer = {20, 20, 20, 20, 20, 20, 20, 20}
    4. Dim zuzahlen As Decimal
    5. Dim bezahltmit As Decimal
    6. Dim rückgeld As Decimal
    7. 'übergabe
    8. zuzahlen = Convert.ToDecimal(txtzubezahlen.Text)
    9. bezahltmit = Convert.ToDecimal(txtbezahltmit.Text)
    10. rückgeld = bezahltmit - zuzahlen
    11. txtrückgeld.Text = rückgeld
    12. Do Until rückgeld = 0
    13. Select Case rückgeld
    14. Case Is >= 2
    15. If maximum(0) = 0 Then
    16. rückgeld = rückgeld - wechselgeld(1)
    17. anzahl(1) = anzahl(1) + 1
    18. maximum(1) = maximum(1) - 1
    19. Else
    20. rückgeld = rückgeld - wechselgeld(0)
    21. anzahl(0) = anzahl(0) + 1
    22. maximum(0) = maximum(0) - 1
    23. End If
    24. Case Is >= 1
    25. If maximum(1) = 0 Then
    26. rückgeld = rückgeld - wechselgeld(2)
    27. anzahl(2) = anzahl(2) + 1
    28. maximum(2) = maximum(2) - 1
    29. Else
    30. rückgeld = rückgeld - wechselgeld(1)
    31. anzahl(1) = anzahl(1) + 1
    32. maximum(1) = maximum(1) - 1
    33. End If
    34. Case Is >= 0.5
    35. If maximum(2) = 0 Then
    36. rückgeld = rückgeld - wechselgeld(3)
    37. anzahl(3) = anzahl(3) + 1
    38. maximum(3) = maximum(3) - 1
    39. Else
    40. rückgeld = rückgeld - wechselgeld(2)
    41. anzahl(2) = anzahl(2) + 1
    42. maximum(2) = maximum(2) - 1
    43. End If
    44. Case Is >= 0.2
    45. If maximum(3) = 0 Then
    46. rückgeld = rückgeld - wechselgeld(4)
    47. anzahl(4) = anzahl(4) + 1
    48. maximum(4) = maximum(4) - 1
    49. Else
    50. rückgeld = rückgeld - wechselgeld(3)
    51. anzahl(3) = anzahl(3) + 1
    52. maximum(3) = maximum(3) - 1
    53. End If
    54. Case Is >= 0.1
    55. If maximum(4) = 0 Then
    56. rückgeld = rückgeld - wechselgeld(5)
    57. anzahl(5) = anzahl(5) + 1
    58. maximum(5) = maximum(5) - 1
    59. Else
    60. rückgeld = rückgeld - wechselgeld(4)
    61. anzahl(4) = anzahl(4) + 1
    62. maximum(4) = maximum(4) - 1
    63. End If
    64. Case Is >= 0.05
    65. If maximum(6) = 0 Then
    66. rückgeld = rückgeld - wechselgeld(6)
    67. anzahl(6) = anzahl(6) + 1
    68. maximum(6) = maximum(6) - 1
    69. Else
    70. rückgeld = rückgeld - wechselgeld(5)
    71. anzahl(5) = anzahl(5) + 1
    72. maximum(5) = maximum(5) - 1
    73. End If
    74. Case Is >= 0.02
    75. If maximum(7) = 0 Then
    76. rückgeld = rückgeld - wechselgeld(7)
    77. anzahl(7) = anzahl(7) + 1
    78. maximum(7) = maximum(7) - 1
    79. Else
    80. rückgeld = rückgeld - wechselgeld(6)
    81. anzahl(6) = anzahl(6) + 1
    82. maximum(6) = maximum(6) - 1
    83. End If
    84. Case Is >= 0.01
    85. rückgeld = rückgeld - wechselgeld(7)
    86. anzahl(7) = anzahl(7) + 1
    87. maximum(7) = maximum(7) - 1
    88. End Select
    89. Loop
    90. For i = 0 To 7
    91. lstausgabe.Items.Add(wechselgeld(i) & " Euro: " & anzahl(i))
    92. Next


    Den Fehler warum das Programm nicht geht kenne ich schon, da er bei der 2 Euromünze immer und immer wieder in die Ifschleife geht und somit bei einer Ausgabe von Fahrkosten 3,10 und Bezahlt 100 sagt, das ich 20x 2 Euro bekomme aber über 50x die 1 Euro Münze.
    Ich könnte das vielleicht über eine relativ große Ifabfrage abfangen aber das sieht irgendwie "doof" aus. Besteht nicht die möglichkeit, das ich von einem Case in den nächsten "springen kann? Nach dem Motto:

    VB.NET-Quellcode

    1. If maximum(0) = 0 Then
    2. rückgeld = rückgeld - wechselgeld(1)
    3. anzahl(1) = anzahl(1) + 1
    4. maximum(1) = maximum(1) - 1

    Führe dies 1 mal aus und gehe dann nicht mehr in diesen Fall? Das man das ganze quasi "sperren" würde oder denke ich hier einfach zu durcheinander?
    Die innere Abfrage würde ich auch in ne Schleife packen:

    VB.NET-Quellcode

    1. Private Sub Rückgeld(ByVal r As Integer)
    2. Dim Muenzen() As Integer = {200, 100, 50, 20, 10, 5, 2, 1}
    3. Dim Inhalt() As Integer = {20, 20, 20, 20, 20, 20, 20, 20}
    4. Dim gesamt As Integer
    5. For i = 0 To Muenzen.Count - 1
    6. gesamt += Muenzen(i) * Inhalt(i)
    7. Next
    8. If gesamt < r Then Throw New Exception("Geld alle")
    9. While r > 0
    10. For i = 0 To Muenzen.Count - 1
    11. If r >= Muenzen(i) AndAlso Inhalt(i) > 0 Then
    12. Debug.Print(Muenzen(i))
    13. Inhalt(i) -= 1
    14. r -= Muenzen(i)
    15. Exit For
    16. End If
    17. Next
    18. End While
    19. End Sub
    Vielen Dank schonmal für die Antwort! Leider habe ich etwas Probleme deinen Code zu verstehen =) daher ratter ich einfach mal runter wie ich es verstehe, korrigiere mich bitte wenn ich es falsch verstehe!

    Da du den Code in einem Private Sub geschrieben hast, müsste es neben dem normalen Programm laufen oder?

    VB.NET-Quellcode

    1. For i = 0 To Muenzen.Count - 1
    2. gesamt += Muenzen(i) * Inhalt(i)
    3. Next
    4. If gesamt < r Then Throw New Exception("Geld alle")

    Sofern ich das richtig verstehe zählst du hier alle Münzen zusammen um zu bestimmen wie viele es insgesamt gibt um ein Limit zu setzen und eine Warnung auszugeben falls es keine mehr gibt oder? Leider würde mir (sofern ich das richtig verstanden habe) das nicht sehr viel weiterhelfen, oder es liegt daran, das ich ebenfalls Probleme besitze den kern aus dem letzten "Block" zu verstehen :( Wenn ich mich nicht irre prüfst du ob der rest größer ist als die im Automaten vorhandenen Münzen aber zu welchen zweck :)?

    Ich setze mich auch nochmal vor das programm und versuche die Abfragen etwas zu kompremieren vielleicht stoße ich dabei auch noch auf einen Lösungsvorsatz =)
    r ist die Geldsumme (in Cent), die der Kunde erhalten soll. Wenn die Gesamtsumme aller Münzen im Gerät KLEINER als die zu zahlende Summe ist, dann gibts nen Fehler - im realen Automaten würde dann wohl der 500 Euro Schein so wieder ausgespuckt werden ;)

    Erst wenn klar ist, DASS der automat auch bezahlen kann, geht das eigentliche Münzenauswerfen los.

    Im zweiten block, der Rückgabe, ist es eigentlich simpel.
    solange noch Geld zu zahlen ist:
    Schleife über alle Münzen:
    Ist die Münze kleinergleich Restgeld und sind davon noch Münzen vorhanden?
    Ja - Münze nehmen, Anzahl im Reservefach erniedrigen und innere Schleife beenden
    Nein - Schleife weiter, so dass die nächstkleinere Münze geprüft wird.
    Ahh jetzt geht mir ein Licht auf! :)
    Die Idee mit der Ausgabe der Nachricht das nicht genug Münzen vorhanden sind, ist super! Und vielen Dank für die Erklärung jetzt erscheint es mir klarer als vorher =) Gleich nachher mal ausprobieren und schauen ob es klappt ;)
    Man kann den inneren Teil natürlich auch noch vereinfachen:

    VB.NET-Quellcode

    1. Dim m As Integer
    2. For i = 0 To Muenzen.Count - 1
    3. If r >= Muenzen(i) AndAlso Inhalt(i) > 0 Then
    4. m = Math.Min(r \ Muenzen(i), Inhalt(i))
    5. Debug.Print(Muenzen(i) & " * " & m)
    6. Inhalt(i) -= m
    7. r -= m * Muenzen(i)
    8. End If
    9. Next


    Kannst ja mal schauen, ob du selbst den Sinn DIESES Codes rausfindest ...
    @picoflop: Ist es beabsichtigt, dass der Automat Kleingeld zurückgibt, auch wenn es nicht passend ist? Unser Automat wäre mit Fußspuren übersät, wenn er das machen würde ;) Bei nicht passendem Retourgeld sollte IMHO dem Kunden sein Geld wieder retour gegeben werden (Transaktion verweigert).


    Beispiel etwas erweitert

    Enum für den Status hinzugefügt, Array für die Anzahl an Münzen, die ausgezahlt werden

    VB.NET-Quellcode

    1. Enum retourstatus
    2. inArbeit
    3. erledigt
    4. keinGeld
    5. nichtpassend
    6. End Enum
    7. Private Sub Rückgeld(ByVal r As Integer)
    8. Dim status As retourstatus = retourstatus.inArbeit
    9. Dim Muenzen() As Integer = {200, 100, 50, 20, 10, 5, 2, 1}
    10. Dim Inhalt() As Integer = {1, 0, 0, 0, 0, 0, 0, 0}
    11. Dim Auszahlung() As Integer = {0, 0, 0, 0, 0, 0, 0, 0}
    12. 'Alternativ: Dim Auszahlung = Enumerable.Repeat(0, 8).ToArray()
    13. Dim gesamt As Integer
    14. For i = 0 To Muenzen.Count - 1
    15. gesamt += Muenzen(i) * Inhalt(i)
    16. Next
    17. If gesamt < r Then
    18. status = retourstatus.keinGeld
    19. Throw New Exception("Geld alle")
    20. End If
    21. Dim m As Integer
    22. Dim sum As Integer
    23. For i = 0 To Muenzen.Count - 1
    24. If r >= Muenzen(i) AndAlso Inhalt(i) > 0 Then
    25. m = Math.Min(r \ Muenzen(i), Inhalt(i))
    26. Auszahlung(i) = m
    27. ' Debug.Print(Muenzen(i) & "€ * " & m)
    28. r -= m * Muenzen(i)
    29. sum += Muenzen(i) * m
    30. End If
    31. Next
    32. If r > sum Then
    33. status = retourstatus.nichtpassend
    34. 'Auszahlung wieder zurücksetzen
    35. Auszahlung = Enumerable.Repeat(0, 8).ToArray()
    36. Throw New Exception("Geld nicht passend")
    37. End If
    38. 'Bericht: so schauts aus...
    39. For q = 0 To Auszahlung.Count - 1
    40. Debug.Print(Muenzen(q) & "€ x " & Auszahlung(q))
    41. Next
    42. status = retourstatus.erledigt
    43. End Sub
    Obiger Code ist ja nur ein TEIL des vorherigen

    ...schon klar.

    Ist schon richtig. Wenn das Geld "summenmäßig" nicht reicht, gibt's die Ex.
    Ich meinte: wenn der Betrag höher ist, aber die Anzahl der Münzen nicht reicht, das Geld passend rauszugeben...
    Beispiel: Ein Zwanziger und ein Einer in der Kassa. Retour auf 14 EUR.
    Macht 21 EUR in der Kassa, aber passend isses nicht. Hier müsste ein Abbruch erfolgen.

    VB.NET-Quellcode

    1. 'Aufruf: Rückgeld (14)
    2. Private Sub Rückgeld(ByVal r As Integer)
    3. Dim Muenzen() As Integer = {200, 100, 50, 20, 10, 5, 2, 1}
    4. Dim Inhalt() As Integer = {0, 0, 0, 1, 0, 0, 0, 1}
    5. Dim gesamt As Integer
    6. For i = 0 To Muenzen.Count - 1
    7. gesamt += Muenzen(i) * Inhalt(i)
    8. Next
    9. If gesamt < r Then Throw New Exception("Geld alle")
    10. Debug.Print("Neuer Versuch: ")
    11. Debug.Print("Rückgeld: " & r.ToString & " EUR")
    12. Dim m As Integer
    13. For i = 0 To Muenzen.Count - 1
    14. If r >= Muenzen(i) AndAlso Inhalt(i) > 0 Then
    15. m = Math.Min(r \ Muenzen(i), Inhalt(i))
    16. Debug.Print(Muenzen(i) & " * " & m)
    17. Inhalt(i) -= m
    18. r -= m * Muenzen(i)
    19. End If
    20. Next
    21. End Sub


    Neuer Versuch:
    Rückgeld: 14 EUR
    1 * 1

    der_Kurt schrieb:

    Macht 21 EUR in der Kassa, aber passend isses nicht. Hier müsste ein Abbruch erfolgen.

    Das ist korrekt. Offensichtlich muss man das auch prüfen bzw abfangen.
    Dazu reicht es aber, nach der For-Next Schleife zu prüfen, ob r>0 ist. Wenn ja -> Fehler

    Nachtrach:
    eigentlich ne schöne "Übungsaufgabe", um objektorientiert zu programmieren - und wenn möglich ohne "Arrays" sondern mit Listen, Dictionarys etc.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „picoflop“ ()