so ganz passt es noch nicht. Ich habe mal folgende Testfälle laufen lassen:
var times = new Dictionary <DayOfWeek, IList <TimeSpan>> ();
times [DayOfWeek.Monday] = new List <TimeSpan> ();
times [DayOfWeek.Monday].Add (new TimeSpan (8, 0, 0));
times [DayOfWeek.Monday].Add (new TimeSpan (16, 0, 0));
times [DayOfWeek.Tuesday] = times [DayOfWeek.Monday];
times [DayOfWeek.Wednesday] = times [DayOfWeek.Monday];
times [DayOfWeek.Thursday] = times [DayOfWeek.Monday];
times [DayOfWeek.Friday] = times [DayOfWeek.Monday];
DateTime start = new DateTime (2012, 10, 2, 9, 0 , 0);
DateTime end = new DateTime (2012, 10, 1, 14, 0 , 0);
for (int i = 0; i ≤ 10; ++i) {
try { Console.WriteLine (SubtractEx (start, end.AddDays (i), times).TotalHours); }
catch { Console.WriteLine ("Exception"); }
}
Console.WriteLine ("---");
start = new DateTime (2012, 10, 2, 14, 0 , 0);
end = new DateTime (2012, 10, 1, 9, 0 , 0);
for (int i = 0; i ≤ 10; ++i) {
try { Console.WriteLine (SubtractEx (start, end.AddDays (i), times).TotalHours); }
catch { Console.WriteLine ("Exception"); }
}
Wenn ich mich nicht vertan habe, müsste das folgende Ausgabe produzieren, jedenfalls tut meine Lösung das:
Dass die Abfrage if ( _totalDaysBetween < 0 ) nicht reicht, um sicherzustellen, dass start ≤ end ist, lässt sich leicht beheben. Aber es muss auch noch an anderen Stellen irgendwelche Abweichungen geben. Vielleicht nur irgendeine Kleinigkeit. Für Zeiträume von mehr als 2 oder 3 Tagen scheint es schonmal zu stimmen.
anbei eine Version mit welcher die geposteten Testfälle erfolgreich durchlaufen werden.
Ansatt einer 0 wird allerdings eine Exception geworfen.
Bei einem speziellen Fall dürfte der Code evtl noch Probleme haben, aber diesen kann ich aktuell aufgrund von Zeitmangel nicht vor heute Abend beheben.
public static TimeSpan SubtractEx(DateTime start, DateTime end, Dictionary<DayOfWeek, IList<TimeSpan>> timelist)
{
TimeSpan _result = new TimeSpan();
// *** Aenderung ***
TimeSpan _totalDaysBetween = end.Date.Subtract(start.Date);
if ( end.Subtract(start) < new TimeSpan())
throw new ArgumentException("Fehler! \n Ungueltige Zeiangabe");
IList<TimeSpan> _firstList = new List<TimeSpan>();
IList<TimeSpan> _secondList = new List<TimeSpan>();
IList<TimeSpan> _tempList = new List<TimeSpan>();
DateTime _firstDate = new DateTime();
DateTime _secondDate = new DateTime();
DateTime _tempDate = new DateTime();
// *** Aenderung ***
switch (_totalDaysBetween.Days)
{
case 0:
//Startdatum == Enddatum
timelist.TryGetValue(start.DayOfWeek, out _firstList);
_result = _result.Add(GetTimeSpanBetween(start, end, _firstList));
break;
//-------------------------------------------------------------------------------------------
case 1:
// Startdatum + 1Tag = Enddatum
_firstDate = new DateTime(start.Year,
start.Month,
start.Day,
23, 59, 59);
_secondDate = new DateTime(end.Year,
end.Month,
end.Day,
00, 00, 00);
timelist.TryGetValue(start.DayOfWeek, out _firstList);
timelist.TryGetValue(end.DayOfWeek, out _secondList);
_result = _result.Add(GetTimeSpanBetween(start, _firstDate, _firstList));
_result = _result.Add(GetTimeSpanBetween(_secondDate, end, _secondList));
break;
//-------------------------------------------------------------------------------------------
case 2:
// Startdatum + 2Tage = Enddatum --> kein "voller" Tag dazwischen
_firstDate = new DateTime(start.Year,
start.Month,
start.Day,
23, 59, 59);
_secondDate = new DateTime(end.Year,
end.Month,
end.Day,
00, 00, 00);
_tempDate = start.AddDays(1);
_tempDate = new DateTime(_tempDate.Year,
_tempDate.Month,
_tempDate.Day,
00, 00, 00);
DateTime _tempDateEnd = new DateTime(_tempDate.Year,
_tempDate.Month,
_tempDate.Day,
23, 59, 59);
timelist.TryGetValue(start.DayOfWeek, out _firstList);
timelist.TryGetValue(end.DayOfWeek, out _secondList);
timelist.TryGetValue(_tempDate.DayOfWeek, out _tempList);
_result = _result.Add(GetTimeSpanBetween(start, _firstDate, _firstList));
_result = _result.Add(GetTimeSpanBetween(_secondDate, end, _secondList));
_result = _result.Add(GetTimeSpanBetween(_tempDate, _tempDateEnd, _tempList));
break;
//-------------------------------------------------------------------------------------------
default:
// Startdatum + 3Tage + X = Enddatum
_firstDate = new DateTime(start.Year,
start.Month,
start.Day,
23, 59, 59);
_secondDate = new DateTime(end.Year,
end.Month,
end.Day,
00, 00, 00);
timelist.TryGetValue(start.DayOfWeek, out _firstList);
timelist.TryGetValue(end.DayOfWeek, out _secondList);
_result = _result.Add(GetTimeSpanBetween(start, _firstDate, _firstList));
_result = _result.Add(GetTimeSpanBetween(_secondDate, end, _secondList));
//Alle Tage zwischen Startdatum+1 und Enddatum-1 ermitteln
DateTime _firstRelevantDay = start.AddDays(1);
DateTime _lastRelevantDay = end.Subtract(new TimeSpan(24, 0, 0));
_firstRelevantDay = new DateTime(_firstRelevantDay.Year,
_firstRelevantDay.Month,
_firstRelevantDay.Day,
00, 00, 00);
_lastRelevantDay = new DateTime(_lastRelevantDay.Year,
_lastRelevantDay.Month,
_lastRelevantDay.Day,
23, 59, 59);
int _fullDays = _lastRelevantDay.Subtract(_firstRelevantDay).Days;
_fullDays++;
// ganze + angebrochene wochen ermittlen
int _weeks = _fullDays / 7;
int _daysOverWeeks = _fullDays % 7;
_tempDate = _firstRelevantDay;
Dictionary<DayOfWeek, int> _dayOrder = new Dictionary<DayOfWeek, int>();
for (int i = 0; i < 7; i++)
{
if (i ≤ _fullDays)
_dayOrder.Add(_tempDate.AddDays(i).DayOfWeek, i);
}
if (_fullDays ≤ 7)
//Keine volle Woche zwishen start(+1) und ende(-1)
{
for (int i = 1; i ≤ _fullDays; i++)
{
timelist.TryGetValue(_firstRelevantDay.AddDays(i - 1).DayOfWeek, out _tempList);
DateTime _currentStart = _firstRelevantDay;
DateTime _currentEnd = new DateTime(_currentStart.Year,
_currentStart.Month,
_currentStart.Day,
23, 59, 59);
_result = _result.Add(GetTimeSpanBetween(_currentStart, _currentEnd, _tempList));
}
}
//mindestens 1tag ist dopplet vorhanden (excl start und ende)
else
{
for (int i = 0; i < 7; i++)
{
int _factor = _weeks;
if (i < _daysOverWeeks)
_factor++;
timelist.TryGetValue(_firstRelevantDay.AddDays(i).DayOfWeek, out _tempList);
DateTime _start = _firstRelevantDay;
DateTime _end = new DateTime(_start.Year,
_start.Month,
_start.Day,
23, 59, 59);
TimeSpan _tempSpan = GetTimeSpanBetween(_start, _end, _tempList);
TimeSpan _multiplied = new TimeSpan(_tempSpan.Days * _factor,
_tempSpan.Hours * _factor,
_tempSpan.Minutes * _factor,
_tempSpan.Seconds * _factor);
_result = _result.Add(_multiplied);
}
}
break;
}
return _result;
}
private static TimeSpan GetTimeSpanBetween(DateTime start, DateTime end, IList<TimeSpan> timelist)
{
TimeSpan _result = new TimeSpan();
//timelist ist NULL wenn kein eintrag fuer den Wochentag im Dict --> leeren TimeSpan zurück geben
if (timelist != null)
{
for (int i = 0; i < timelist.Count; i += 2)
{
//(Startzeit < TimeListZeit[n]) + (Endzeit < TimeListZeit[n+1]) --> TimeListZeit[n] + Endzeit nehmen
if ((start.TimeOfDay ≤ timelist[i]) && (end.TimeOfDay ≤ timelist[i + 1]))
{
_result = _result.Add(end.TimeOfDay.Subtract(timelist[i]));
}
//(Startzeit < TimeListZeit[n]) + (Endzeit > TimeListZeit[n+1]) --> TimeListZeit[n] + TimeListZeit[n+1] nehmen
else if ((start.TimeOfDay ≤ timelist[i]) && (end.TimeOfDay ≥ timelist[i + 1]))
{
_result = _result.Add(timelist[i + 1].Subtract(timelist[i]));
}
//(Startzeit > TimeListZeit[n]) + (Endzeit < TimeListZeit[n+1]) --> Startzeit + Endzeit nehmen
else if ((start.TimeOfDay ≥ timelist[i]) && (end.TimeOfDay ≤ timelist[i + 1]))
{
_result = _result.Add(end.TimeOfDay.Subtract(start.TimeOfDay));
}
//(Startzeit > TimeListZeit[n]) + (Endzeit > TimeListZeit[n+1]) --> Startzeit + TimeListZeit[n+1] nehmen
else if ((start.TimeOfDay ≥ timelist[i]) && (end.TimeOfDay ≥ timelist[i + 1]))
{
_result = _result.Add(timelist[i + 1].Subtract(start.TimeOfDay));
}
else
{
throw new ArgumentException("Fehler! \n Ungueltige Zeiangabe");
}
}
}
return _result;
}
Also in einigen regulären Fällen fliegen noch Exceptions. Daher ist die Aufgabe noch nicht gelöst.
Zu Schönheit (die wie gesagt nicht gefordert ist) trotzdem noch ein Wort: Da fehlende Keys erlaubt sind, liegt keine Ausnahmesituation vor. Statt try-catch(KeyNotFoundException) solltest du besser überall Dictionary<>.TryGetValue verwenden (und dann auf null abfragen).
Außerdem hast du einer Stelle im Code ein DateTime.Add, ohne den berechneten Wert zu verändern. DateTime.Add ändert den übergebenen DateTime nicht, sondern liefert das Ergebnis der Berechnung nur zurück.
da wurde es ja auf die letzten Meter nochmal richtig knapp. Der Post mit der verbesserten Lösung von dir, Gwinn, ist von 12:58, das Edit mit der verbesserten Lösung von dir, mcdt, ist von 13:02. Ich habe mir beide Lösungen angeschaut und ich halte sie beide für richtig. Ihr habt die Aufgabe beide gelöst. Da du, Gwinn, einen Tick schneller warst, bist du mit der nächsten Aufgabe dran.
Unter dem Aspekt der Universialität ist die eine Behandlung für negative Werte, die du, Gwinn, eingebaut hast, etwas besser, da sie auch von der normalen Substract-Methode verwendet wird. Da ich aber nicht genau spezifiziert hatte, wie die Behandlung für start > end aussehen soll, ist auch das Werfen einer Exception, wie du, mcdt, es gemacht hast, korrekt.
Hier der Vollständigkeit halber noch meine Lösung (sicher noch verbesserungsfähig):
public static TimeSpan SubtractEx (DateTime start, DateTime end, Dictionary <DayOfWeek, IList <TimeSpan>> times)
{
if (start ≥ end) {
return new TimeSpan ();
}
int numDays = (end.Date - start.Date).Days + 1;
int numCompleteWeeks = 0;
if (numDays ≥ 9) {
numCompleteWeeks = (numDays - 2) / 7;
numDays -= numCompleteWeeks * 7;
}
TimeSpan sum = new TimeSpan ();
TimeSpan sumWeek = new TimeSpan ();
if (numCompleteWeeks > 0) {
foreach (DayOfWeek dayOfWeek in Enum.GetValues (typeof (DayOfWeek))) {
IList <TimeSpan> timesOfDay;
times.TryGetValue (dayOfWeek, out timesOfDay);
if (timesOfDay == null) { continue; }
for (int i = 0; i < timesOfDay.Count; i += 2) {
sumWeek += timesOfDay [i + 1] - timesOfDay [i];
}
}
sum = new TimeSpan (sumWeek.Ticks * numCompleteWeeks);
}
TimeSpan time0 = new TimeSpan ();
TimeSpan time24 = new TimeSpan (24, 0, 0);
for (int i = 0; i < numDays; ++ i) {
DayOfWeek dayOfWeek = (DayOfWeek)(((int)(start.DayOfWeek + i)) % 7);
IList <TimeSpan> timesOfDay;
times.TryGetValue (dayOfWeek, out timesOfDay);
if (timesOfDay == null) { continue; }
sum += SubtractEx ((i == 0 ? start.TimeOfDay : time0), (i == numDays - 1 ? end.TimeOfDay : time24), timesOfDay);
}
return sum;
}
public static TimeSpan SubtractEx (TimeSpan start, TimeSpan end, IList <TimeSpan> timesOfDay)
{
if (timesOfDay == null || start ≥ end) {
return new TimeSpan ();
}
TimeSpan sum = new TimeSpan ();
for (int i = 0; i < timesOfDay.Count; i += 2) {
if (start ≥ timesOfDay [i + 1]) { continue; }
if (end ≤ timesOfDay [i]) { break; }
sum += (end < timesOfDay [i + 1] ? end : timesOfDay [i + 1])
- (start > timesOfDay [i] ? start : timesOfDay [i]);
}
return sum;
}
Übrigens sind das - ohne die Leerzeilen - exakt 50 Zeilen.
als ich beim letzten Mal überlegt hatte, welche Aufgabe ich stelle, waren mir zwei Aufgaben eingefallen, die ich beide gleich gut und genauso spannend fand. Die mit den Zeitdifferenzen habe ich bereits gestellt, dann kommt jetzt das Berechnen von Quersummen. Und um es noch interessanter zu machen, das Ganze für beliebige Zahlensysteme.
Schreibe eine Methode [TT]Int32 Quersumme (Int32 wert, Int32 basis)[/TT], die mindestens für die Basen 2, 5, 8, 10 und 16 die Quersumme von [TT]wert[/TT] berechnet und zurückliefert, [B]ohne[/B] dabei den Umweg über Strings zu gehen, also alles rein mit Operatoren und Methoden der Klasse Int32.
Da die Herausforderung eher darin liegt, zu erkennen, wie man die Aufgabe am besten angeht, und wenn man das herausgefunden hat, sich die Methode selbst mit relativ wenig Code realisieren lässt, lege ich diesmal besonderen Wert auf korrekte (Fehler-)Behandlung alle richtigen und falschen Eingaben bezogen auf den [B]kompletten[/B] Wertebereich der verwendeten Typen.
[csharp]
// wert -> Quersumme
Console.WriteLine (Quersumme (10, 2)); // 1010 bin -> 2 dec
Console.WriteLine (Quersumme (10, 5)); // 20 pen -> 2 dec
Console.WriteLine (Quersumme (10, 8)); // 12 oct -> 3 dec
Console.WriteLine (Quersumme (10, 10)); // 10 dec -> 1 dec
Console.WriteLine (Quersumme (10, 16)); // A hex -> 10 dec[/csharp]
[COLOR]Der Code wird einfacher, wenn man beliebige (zulässige) Werte für die Basis akzeptiert und keine Basis besonders behandelt. Wenn man die (nicht zwingende) Einschränkung auf die in der Aufgabe genannten Basiswerte umsetzen würde, würde es also nicht einfacher, sondern schwerer. :-)[/COLOR]
ich hoffe ich habe keine Fehlerquellen übersehen.
Ungültige Argumente führen in meiner Version zu einer entsprechenden Exception.
Die Funktion nimmt als Argumente nichtnegative Zahlen und Basen von 2 bis 62.
Statt einer Exception könnte man auch den Ausgabestring entsprechend ändern. In Hinblick auf eine Anwendung gehe ich jedoch davon aus, dass man zuerst an dem Ergebniss der Berechnung interessiert ist. Deshalb habe ich als Rückgabewert die Quersumme gewählt und schreibe den Ausgabestring in den Parameter str.
public static int Quersumme(Int32 zahl, Int32 basis, out String str)
{
Int32 quersumme = 0;
Int32 ziffer;
StringBuilder strbuilder = new StringBuilder();
Int32 restzahl = zahl;
if ((basis > 62) || (basis < 2))
throw new ArgumentOutOfRangeException("Die Basis muss zwischen 2 und 62 liegen.");
if (zahl < 0)
throw new ArgumentOutOfRangeException("Die Quersumme ist nur für natürliche Zahlen definiert.");
while (restzahl > 0)
{
ziffer = restzahl % basis;
quersumme += ziffer;
if (ziffer < 10)
strbuilder.Insert(0, ziffer);
else
if (ziffer > 35)
strbuilder.Insert(0, (char)(ziffer + 61));
else
strbuilder.Insert(0, (char)(ziffer + 55));
restzahl = (restzahl - ziffer) / basis;
}
str = zahl.ToString() + "= " + strbuilder.ToString() + " base " + basis.ToString() + " -> Quersumme " + quersumme.ToString();
return quersumme;
}
die Ausgabe der Zahl in dem jeweiligen Ziffernsystem war gar nicht gefordert. :-) Es reicht die Berechnung der Quersumme, solange sie die nebenbei berechneten String-Repräsentation beruht. Nur auf die eigentliche Quersummenberechnung beziehe ich mich im folgenden.
Die Beschränkung, dass die Basis zwischen 2 und 62 liegen muss, ist zulässig. Die Beschränkung auf positive Werte auch. Die Definition in der deutschen Wikipedia bezieht sich ausdrücklich nur auf natürliche (und nicht etwa ganze) Zahlen.
Aus meiner Sicht gibt es drei Möglichkeiten, wie man die Quersumme negativer Zahlen definieren kann:
gar nicht, sprich Exception
als Quersumme des Absolutwerts der Zahl, also Quersumme (-x, y) == Quersumme (x, y)
oder durch Negieren der Quersumme des Absolutwerts der Zahl, also Quersumme (-x, y) == -Quersumme (x, y)
Ich hätte alle drei Lösungen als richtig interpretiert, wobei mir definitionsmäßig die zweite Variante am logischsten erscheint, denn die Quersumme ist nach meinem Verständnis die Summe der Ziffern und Ziffern haben kein Vorzeichen. Nur die Zahl als ganzes hat ein Vorzeichen und zwar auch dann, wenn sie nur aus einer Ziffer besteht. Ob die dritte Definition bei Berechnungen besser geeignet ist, habe ich mir nicht überlegt. Und bei der ersten Definition macht man sich die Aufgabe in meinen Augen zu leicht :-) weil man so das Problem umgeht, dass Math.Abs (Int32.MinValue) nicht definiert ist. Darauf zielte mein Hinweis, dass der komplette Wertbereich abgedeckt werden soll, was inbesondere deren Grenzen einschließt. Aber wie gesagt, ich akzeptiere alle drei Definitionen als richtig.
Und daher ist deine Lösung korrekt. Jetzt bist du aber wirklich mit einer neuen Aufgabe dran, denn es gilt das am Anfang des Threads Gesagte: "Postet nur eine Lösung, wenn ihr schon eine neue Aufgabe in petto habt."
Hier noch meine Lösung:
public static Int32 Quersumme (Int32 wert, Int32 basis)
{
if (basis < 2) { throw new ArgumentException ("basis muss größer als eins sein"); }
Int64 restwert = wert > 0 ? wert : -(Int64)wert;
Int32 quersumme = 0;
while (restwert > 0) {
quersumme += (Int32)(restwert % basis);
restwert /= basis;
}
return quersumme;
}
da wir zuvor schon bei einer Springeraufgabe waren, hier meine Aufgabe:
Gesucht ist eine Funktion, die einen Lösungsweg für das Springerproblem für ein 8x8 Feld liefert.
Als Parameter soll die Funktion die Koordinaten des Startfeldes empfangen.
Viel Spaß
Gwinn
Edit: Um die Laufzeit nicht zu sehr in die Höhe zu treiben soll es genügen, wenn als Startpunkt eine Ecke vorgegeben wird.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Gwinn am .
ich bin leider erst mit etwas Verzögerung dazu gekommen, mir die Lösungen anzusehen.
Funktionieren tun beide. Die Lösung von D4rkScr43m läuft dabei wesentlich performanter ab (auch als meine Lösung).
Da seine Lösung zudem etwas schneller kam, erhält er den Zuschlag für die nächste Aufgabe.
Schreibt eine Methode
void ExecuteHQ9Plus(String code, ref int acc);
Die den code nach den Regeln der "Programmiersprache" HQ9+ (HQ9+) abarbeitet und die Ausgabe auf der Konsole ausgibt. acc ersetzt dabei den Akkumulator.
Für den Fall dass im Code ein Nicht-Sprachelement vorkommt, hätte ich gerne anstatt der Ausgabe des Programms eine Fehlermeldung mit der Stelle des Fehlers.
Der Aufruf könnte z.B. so aussehen:
int i = 0;
ExecuteHQ9Plus("+H+QQH9++", ref i);
Console.WriteLine(i);
ExecuteHQ9Plus("HQ++++Q+H", ref i);
Console.WriteLine(i);
ExecuteHQ9Plus("++HQx++++", ref i);
Console.WriteLine(i);
und hätte dann z.B diese ausgabe:
Hello World!
+H+QQH9++
+H+QQH9++
Hello World!
[99 Bottles of beer... and so on...] // hier ist der gesammte Songtext gemeint.
4
Hello World!
HQ++++Q+H
HQ++++Q+H
Hello World!
9
Fehler im Programm an Stelle: 4 [...]x[...]
9
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von D4rkScr43m am .
"Nichts leichter als das" habe ich mir gedacht und bin dann prompt auf folgendes Ergebnis gekommen:
private static void ExecuteHQ9Plus(string code, ref int acc)
{
int i = 1;
foreach (var c in code.ToUpper().ToCharArray())
{
switch (c)
{
case 'H':
Console.WriteLine("Hello World!");
break;
case 'Q':
Console.WriteLine(code);
break;
case '9':
Console.WriteLine("[99 Bottles of Beer on the Wall]");
break;
case '+':
acc++;
break;
default:
Console.WriteLine("Fehler im Programm an Stelle: {0} [...]{1}[...]", i, c);
break;
}
i++;
}
}
Diese "kompiliert" allerdings nicht und gibt bis zum Fehler alle bis dato gültigen Befehle aus.
Um das zu umgehen, aber auch die Stelle des verkehrten Zeichens heraus zu filtern habe ich dann einfach die Ausgabe zwischengespeichert. (Den Akkumulator ebenfalls)
Ist sicherlich nicht die schönste Lösung wegen des ganzen Zwischengespeichere, aber sie funktioniert:
private static void ExecuteHQ9Plus(string code, ref int acc)
{
bool error = false;
int accOriginal = acc;
int i = 1;
string output = string.Empty;
foreach (var c in code.ToUpper().ToCharArray())
{
switch (c)
{
case 'H':
output += "Hello World!\n";
break;
case 'Q':
output += code;
break;
case '9':
output += "[99 Bottles of Beer on the Wall]\n";
break;
case '+':
acc++;
break;
default:
output = String.Format("Fehler im Programm an Stelle: {0} [...]{1}[...]", i, c);
acc = accOriginal;
error = true;
break;
}
if (error)
break;
i++;
}
Console.WriteLine(output);
}
da ist aber noch ein kleiner Fehler drin:
der Aufruf deines Programms mit
ExecuteHQ9Plus("qqqq", null);
für zu der Ausgabe von qqqqqqqqqqqqqqqq wobei eigentlich
qqqq
qqqq
qqqq
qqqq
heraus kommen müsste. Außerdem fehlt die Implementierung von 99 Bottles of beer.
Das ist aber wohl nur Fleißarbeit (oder C&P).
Richtig, dort habe ich vergessen dem output += code noch ein "\n" oder besser noch System.Environment.NewLine hinzuzufügen.
Zitat von D4rkScr43m
Außerdem fehlt die Implementierung von 99 Bottles of beer.
Das ist im Code oben mit drin und funktioniert meines Erachtens auch.
Eine neue Aufgabe folgt in Kürze!
[EDIT]
Okay, dann habe ich es wirklich falsch verstanden. Der case für 9 muss dann natürlich so lauten:
for (int beer = 99; beer > 0; beer--)
{
output += String.Format("{0} bottles of beer on the wall, {0} bottles of beer.{2}" +
"Take one down and pass it around, {1} bottles of beer on the wall.{2}",
beer, beer == 0 ? (beer - 1).ToString():"no more", System.Environment.NewLine);
}
output += String.Format("No more bottles of beer on the wall, no more bottles of beer.{0}" +
"Go to the store and buy some more, 99 bottles of beer on the wall.", System.Environment.NewLine);
[EDIT 2]
Okay, ich habe das etwas zu schnell "hingepfuscht" ohne ausgiebig genug zu testen. Nun sollte aber alles wie gewünscht funktionieren und auch der Singular bei der letzten Flasche.
Die Codes aus deinem Link habe ich natürlich nicht genommen, weil ich das selbst implementieren wollte :-/
case '9':
for (int beer = 99; beer > 0; beer--)
{
output += String.Format("{0} bottle{3} of beer on the wall, {0} bottle{3} of beer.{2}" +
"Take one down and pass it around, {1} bottle{4} of beer on the wall.{2}",
beer, beer > 1 ? (beer - 1).ToString():"no more", System.Environment.NewLine,
(beer > 1) || (beer ==0) ? "s" : "", beer == 2 ? "" : "s");
}
output += String.Format("No more bottles of beer on the wall, no more bottles of beer.{0}" +
"Go to the store and buy some more, 99 bottles of beer on the wall.{0}", System.Environment.NewLine);
break;
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von trib am .
Stell dir vor, du trinkst 98 Flaschen Bier ... wie viele Flaschen siehst du, wenn nur noch eine an der Wand steht? :D
Zitat von trib
[EDIT]
Okay, dann habe ich es wirklich falsch verstanden. Der case für 9 muss dann natürlich so lauten:
for (int beer = 99; beer > 0; beer--)
{
output += String.Format("{0} bottles of beer on the wall, {0} bottles of beer.{2}" +
"Take one down and pass it around, {1} bottles of beer on the wall.{2}",
beer, beer == 0 ? (beer - 1).ToString():"no more", System.Environment.NewLine);
}
output += String.Format("No more bottles of beer on the wall, no more bottles of beer.{0}" +
"Go to the store and buy some more, 99 bottles of beer on the wall.", System.Environment.NewLine);
Womit wir wieder beim vergessenen System.Environment.NewLine sind, bzw. bei einem fehlenden {0}.
Außerdem wird in einer Schleife mit der Bedingung beer > 0 beer == 0 niemals zu true.
Und ich dachte schon, ich würde damit jemandem einen Gefallen tun...
Dieser Beitrag wurde 3 mal editiert, zum letzten Mal von D4rkScr43m am .
[offtopic]vorweg: Ich habe nochmal meine Lösung angepasst und hoffe nun alles erfüllt zu haben.
Dazu habe ich meinen letzten Beitrag editiert um die neue Aufgabe hier nicht unübersichtlich zu gestalten.[/offtopic]
Aufgabe:
Die nächste Aufgabe ist ein kleines Bowlingspiel. Beziehungsweise die Auswertung dessen.
Regeln:
Es werden die allgemein gültigen Spielregeln angewendet Bowling - Spielregeln.
Demnach besteht jedes Spiel aus 10 Frames. Jeder Frame besteht aus bis zu zwei Würfen. Im Falle eines Strikes nur einem.
Der 10. (letzte) Frame macht die Ausnahme, werden dort ein Spare oder zwei Strikes geworfen, so darf der Spieler ein drittes Mal werfen.
Die maximale Punkteanzahl beträgt 300. Diese setzt sich aus der Summe aller Würfe zusammen.
Dabei werden nach einem Spare die Punkte aus dem Folgewurf addiert. Im Falle eines Strikes sogar die der beiden folgenden Würfe. (Bei einem "Miss" / "Pudel" natürlich 0-Punkte)
Durchführung:
Es sind zwei Funktionen gegeben:
public void Roll(int pins)
welche für jeden Wurf ausgeführt wird und
public int Score()
die die aktuelle Punktezahl ausgibt.
Einschränkungen:
Für eine gültige Lösung muss kein Wurfzähler implementiert werden. Sprich: Wie viele Würfe der Spieler noch hat.
Test:
//20 Würfe mit einem Punkt
for (int i = 0; i < 20; i++)
Roll(1);
Assert.AreEqual(20, Score());
//Spare (10 + 3) +3
Roll(5);
Roll(5);
Roll(3);
Assert.AreEqual(16, Score());
Viel Spaß! PS: Persönlich war ich überrascht, dass die Aufgabe doch etwas aufwändiger ist, als man zuerst denkt :)
ich hab ausversehen das Endgame bei der Punkteberechnung doppelt mit eingerechnet.
Hier die korrigierte Version (Außerdem hab ich noch weitere Fehleingaben abgefangen):
Meine UnitTests wurden alle bestanden und ich habe auch sonst nichts zu beanstanden!
In meiner Lösung habe ich die Berechnung ausschließlich in der Score() vorgenommen und in der Roll(int pins) nur die Werte gespeichert. Weiterhin hatte ich mit verschachtelten Klassen für den Frame und die dahinterliegenden Würfe gebaut. Das hat sich aber schnell als komplizierter herausgestellt als nötig. Die Version mit einem Array ist natürlich viel einfacher (auch wenn sie sich nicht sooooo korrekt anfühlt [Finde ich persönlich])
Da mir gerade etwas eingefallen ist, warum denn nicht, wenn sonst niemand will?
Schreibe folgende Methoden:
/// <summary>
/// This is used to indicate in which direction the image is "looking"
/// </summary>
public enum ImageDirection
{
Top,
Right,
Bottom,
Left
}
/// <summary>
/// Calculates the angle between 2 Vectors
/// </summary>
/// <param name="p1">Vector 1</param>
/// <param name="p2">Vector 2</param>
/// <returns>Angle between the vectors</returns>
public static float GetAngle(Point vectorA, Point vectorB);
/// <summary>
/// Calculates the angle
/// </summary>
/// <param name="p1">Point, where the image should be placed</param>
/// <param name="p2">Point, where the image should "look" to</param>
/// <param name="direction">The direction, where the image is "looking" actually</param>
/// <returns>The Angle, that would be needed to rotate the image to "look" at p2</returns>
public static float GetAngle(Point p1, Point p2, ImageDirection direction);
public static Bitmap RotateImage (Bitmap image, float angle);
Aufgabe:
Die Methode "GetAngle" soll den Winkel in ° (deg) zurückgeben, der von beiden Vektoren eingeschlossen ist:
siehe Anhang
Bei der Überladung mit ImageDirection muss man zuerst die Vektoren berechnen