Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Das Programmier-Spiel: nette Übungsaufgaben für zwischendurch
Gwinn
myCSharp.de - Member



Dabei seit:
Beiträge: 48

beantworten | zitieren | melden

Oups,

da hatte ich mich an die Bearbeitung gemacht, bevor ich alles gelesen hatte. Ich werd mich später am Tag damit nochmal befassen...

Gruß Gwinn
private Nachricht | Beiträge des Benutzers
mcdt
myCSharp.de - Member



Dabei seit:
Beiträge: 56

beantworten | zitieren | melden

Hi,

dann würde ich mal einen Vorschlag posten.
Der Code dürfte für die meisten nicht sehr attraktiv wirken.
Kritik nehme ich gerne per PM entgegen :-)

Ich habe den Code zwar etwas aufgehübscht, aber das einige Stellen sich wiederholen ist mir bewusst, wollte ich aber nicht noch ausbessern.


		public static TimeSpan SubtractEx(DateTime start, DateTime end, Dictionary<DayOfWeek, IList<TimeSpan>> timelist)
		{
			TimeSpan _result = new TimeSpan();
			int _totalDaysBetween = end.Subtract(start).Days;

			if ( _totalDaysBetween < 0 )
				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();

			switch ( _totalDaysBetween )
			{
				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,
												23, 59, 59);

				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;
		}
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo mcdt,

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:
0
5
13
21
29
31
31
37
45
53
61
---
0
0
3
11
19
26
26
27
35
43
51

Statt der der Ausgabe 0 dürfte auch eine Exception fliegen, weil in den Fällen end vor start liegt. Mit deiner Methode erhalte ich folgende Ausgabe:
5
5
13
5,00027777777778
29
31
31
37
45
53
61
---
Exception
-5
-5
3
-4,99972222222222
26
26
27
35
43
51

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.

herbivore
private Nachricht | Beiträge des Benutzers
mcdt
myCSharp.de - Member



Dabei seit:
Beiträge: 56

beantworten | zitieren | melden

Hallo,

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;
        }


Meine Ausgabe mit dem geposteten Testfall lautet:
Exception
5
13
21
29
31
31
37
45
53
61
---
Exception
Exception
3
11
19
26
26
27
35
43
51



Edit:
Habe den Code editiert.
Da nur 2 Zeilen geändert wurden habe ich keinen neuen Post erstellt.
Aus:


int _totalDaysBetween = end.DayOfYear - start.DayOfYear;

Wird:


// *** Aenderung ***
TimeSpan _totalDaysBetween = end.Date.Subtract(start.Date);


und aus:


switch (_totalDaysBetween)

wird:


// *** Aenderung ***
switch (_totalDaysBetween.Days)
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von mcdt am .
private Nachricht | Beiträge des Benutzers
Gwinn
myCSharp.de - Member



Dabei seit:
Beiträge: 48

beantworten | zitieren | melden

Hallo,

ich hab mal an der Performance gearbeitet...


        public static DateTime EndOfDay(this DateTime day)
        {
            return (day.AddDays(1)).Date;
        }

        public static TimeSpan SubtractEx( DateTime start, DateTime end, Dictionary<DayOfWeek, IList<TimeSpan>> timelist)
        {
            if (end < start)
                throw new ArgumentException("Das Enddatum muss nach dem Startdatum liegen.");

            IList<TimeSpan> todaysList;

            Dictionary<DayOfWeek, TimeSpan> timespanPerDay = new Dictionary<DayOfWeek, TimeSpan>();
            TimeSpan helperTimeSpan;
            TimeSpan timespanPerWeek=new TimeSpan();
            foreach (DayOfWeek dayofweek in Enum.GetValues(typeof(DayOfWeek)))
            {
                try
                {
                    todaysList = timelist[dayofweek];
                }
                catch (KeyNotFoundException)
                {
                    todaysList = null;
                }
                helperTimeSpan = new TimeSpan();
                if (todaysList != null)
                {
                    for (int i = 0; i < todaysList.Count; i += 2)
                    {
                        helperTimeSpan += todaysList[i + 1] - todaysList[i];
                    }
                    timespanPerDay.Add(dayofweek, helperTimeSpan);
                    timespanPerWeek += helperTimeSpan;
                }
            }

            int fulldays=(end.Date - start.EndOfDay()).Days;
            int fullweeks = (int)Math.Floor(fulldays / 7.0);
            TimeSpan result = new TimeSpan(fullweeks*timespanPerWeek.Ticks);

            DateTime calcend = end.Subtract(new TimeSpan(fullweeks*7,0,0,0));

            DateTime time = start;
            try
            {
                todaysList = timelist[time.DayOfWeek];
            }
            catch (KeyNotFoundException)
            {
                todaysList = null;
            }
            if (todaysList != null)
            {
                for (int i = 0; i < todaysList.Count; i += 2)
                {
                    if (time.TimeOfDay≤todaysList[i])
                        result+=(todaysList[i+1]-todaysList[i]);
                    else
                        if (time.TimeOfDay<todaysList[i+1])
                            result+=(todaysList[i+1]-time.TimeOfDay);
                }
            }
            time = time.AddDays(1);
            while (time.Date < calcend.Date)
            {
                result += timespanPerDay[time.DayOfWeek];
                time = time.AddDays(1);
            }
            time=calcend;

            try
            {
                todaysList = timelist[time.DayOfWeek];
            }
            catch (KeyNotFoundException)
            {
                todaysList = null;
            }
            if (todaysList != null)
            {
                for (int i = 0; i < todaysList.Count; i += 2)
                {
                    if (todaysList[i+1]<calcend.TimeOfDay)
                        result+=(todaysList[i+1]-todaysList[i]);
                    else
                        if (todaysList[i]<calcend.TimeOfDay)
                            result +=(calcend.TimeOfDay - todaysList[i]);
                }
            }
            return result;
        }
    }

Ich hoffe das genügt jetzt deiner Aufgabenstellung...

Gruß Gwinn
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo mcdt,
Zitat
Bei einem speziellen Fall dürfte der Code evtl noch Probleme haben
so ist das. Bei (sehr) langen Zeiträumen kommen noch falsch Ergebnisse. Daher ist die Aufgabe noch nicht gelöst.


Hallo Gwinn,

der obige Testcode liefert mit deiner Methode folgende Ausgabe:
Exception
Exception
13
21
29
31
Exception
Exception
Exception
53
61
---
Exception
Exception
3
11
19
26
Exception
Exception
Exception
43
51

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.

herbivore
private Nachricht | Beiträge des Benutzers
Gwinn
myCSharp.de - Member



Dabei seit:
Beiträge: 48

beantworten | zitieren | melden

Also,


        public static DateTime EndOfDay(this DateTime day)
        {
            return (day.AddDays(1)).Date;
        }

        public static TimeSpan SubtractEx( DateTime start, DateTime end, Dictionary<DayOfWeek, IList<TimeSpan>> timelist)
        {
            bool negativ = false;
            if (end < start)
            {
                DateTime tmp = start;
                start = end;
                end = tmp;
                negativ = true;
            }

            IList<TimeSpan> todaysList;

            Dictionary<DayOfWeek, TimeSpan> timespanPerDay = new Dictionary<DayOfWeek, TimeSpan>();
            TimeSpan helperTimeSpan;
            TimeSpan timespanPerWeek=new TimeSpan();
            foreach (DayOfWeek dayofweek in Enum.GetValues(typeof(DayOfWeek)))
            {
                timelist.TryGetValue(dayofweek,out todaysList);
                helperTimeSpan = new TimeSpan();
                if (todaysList != null)
                {
                    for (int i = 0; i < todaysList.Count; i += 2)
                    {
                        helperTimeSpan += todaysList[i + 1] - todaysList[i];
                    }
                    timespanPerDay.Add(dayofweek, helperTimeSpan);
                    timespanPerWeek += helperTimeSpan;
                }
            }

            int fulldays=(end.Date - start.EndOfDay()).Days;
            int fullweeks = (int)Math.Floor(fulldays / 7.0);
            TimeSpan result = new TimeSpan(fullweeks*timespanPerWeek.Ticks);

            DateTime calcend = end.Subtract(new TimeSpan(fullweeks*7,0,0,0));

            DateTime time = start;
            timelist.TryGetValue(time.DayOfWeek,out todaysList);
            if (todaysList != null)
            {
                for (int i = 0; i < todaysList.Count; i += 2)
                {
                    if (time.TimeOfDay≤todaysList[i])
                        result+=(todaysList[i+1]-todaysList[i]);
                    else
                        if (time.TimeOfDay<todaysList[i+1])
                            result+=(todaysList[i+1]-time.TimeOfDay);
                }
            }
            time = time.AddDays(1);
            while (time.Date < calcend.Date)
            {
                if (timespanPerDay.TryGetValue(time.DayOfWeek, out helperTimeSpan));
                    result += helperTimeSpan;
                time = time.AddDays(1);
            }
            time=calcend;

            timelist.TryGetValue(time.DayOfWeek, out todaysList);

            if (todaysList != null)
            {
                for (int i = 0; i < todaysList.Count; i += 2)
                {
                    if (todaysList[i+1]<calcend.TimeOfDay)
                        result+=(todaysList[i+1]-todaysList[i]);
                    else
                        if (todaysList[i]<calcend.TimeOfDay)
                            result +=(calcend.TimeOfDay - todaysList[i]);
                }
            }
            if (negativ)
                result = -result;
            return result;
        }

Das liefert jetz mit einer Ausnahme deine Testergebnisse zurück.

DateTime.Substract liefert nämlich nicht 0, sondern einen negativen Wert, falls das Enddatum vor dem Startdatum liegt.

Gruß Gwinn
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo Gwinn, hallo mcdt,

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.

herbivore
private Nachricht | Beiträge des Benutzers
Gwinn
myCSharp.de - Member



Dabei seit:
Beiträge: 48

beantworten | zitieren | melden

Da ich bis jetz noch keine 'schöne' neue Aufgabe habe, gebe ich die Aufgabenstellung einfach mal frei.

Wer also eine neue Aufgabe stellen möchte, sei herzlich dazu eingeladen, das zu tun.

Gruß Gwinn
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo Community,

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]

herbivore
private Nachricht | Beiträge des Benutzers
Gwinn
myCSharp.de - Member



Dabei seit:
Beiträge: 48

beantworten | zitieren | melden

Hi herbivore,

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;
        }

Gruß Gwinn
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo Gwinn,

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:
  1. gar nicht, sprich Exception
  2. als Quersumme des Absolutwerts der Zahl, also Quersumme (-x, y) == Quersumme (x, y)
  3. oder durch Negieren der Quersumme des Absolutwerts der Zahl, also Quersumme (-x, y) == -Quersumme (x, y)

  4. 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;
       }
    

    herbivore
private Nachricht | Beiträge des Benutzers
Gwinn
myCSharp.de - Member



Dabei seit:
Beiträge: 48

beantworten | zitieren | melden

Hallo Community,

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 .
private Nachricht | Beiträge des Benutzers
D4rkScr43m
myCSharp.de - Member



Dabei seit:
Beiträge: 32

beantworten | zitieren | melden

Ich hoffe mal, dass das so akzeptiert wird:

        public static int[,] Springer(int x, int y)
        {
            if(x ≥ 8 || x < 0 || y ≥ 8 || y < 0)
                throw new ArgumentException();
            int[,] field = new int[8,8];
            int count = 1;
            if (Springer(field, x, y, count))
                return field;
            return null;
        }

        private static bool Springer(int[,] field, int x, int y, int count)
        {
            field[x, y] = count++;
            if (count > field.Length)
                return true;
            foreach (int[] fields in AvailableFields(field, x, y))
            {
                if (Springer(field, fields[0], fields[1], count))
                    return true;
            }
            field[x, y] = 0;
            return false;
        }

        private static List<int[]> AvailableFields(int[,] field, int x, int y)
        {
            List<int[]> fields = new List<int[]>();
            int[] directions = new int[] { -2, -1, 1, 2 };
            foreach (int direction in directions)
            {
                if (x + direction ≥ 0 && x + direction < 8)
                {
                    int direction2 = direction % 2 == 0 ? 1 : 2;
                    if (y + direction2 < 8 && field[x + direction, y + direction2] == 0)
                        fields.Add(new int[] { x + direction, y + direction2 });
                    if (y - direction2 ≥ 0 && field[x + direction, y - direction2] == 0)
                        fields.Add(new int[] { x + direction, y - direction2 });
                }
            }
            return fields;
        }
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von D4rkScr43m am .
private Nachricht | Beiträge des Benutzers
Betrayal
myCSharp.de - Member



Dabei seit:
Beiträge: 2

beantworten | zitieren | melden

Quick&Dirty


using System;
using System.Collections.Generic;
using System.Drawing;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            solve(new Point(4, 7), 1);

            foreach (var pnt in solution)
                Console.WriteLine(pnt.ToString());
            Console.ReadKey(true);
        }

        static bool[,] board = new bool[8, 8];
        static List<Point> solution = new List<Point>();

        static Point[] vectors = new Point[] { new Point(1, 2),new Point(2, 1),new Point(2, -1),new Point(1, -2),
                                               new Point(-1, -2),new Point(-2, -1),new Point(-2, 1),new Point(-1, 2) };

        static bool valid(Point p)
        {
            return 0 ≤ p.X && p.X ≤ 7 && 0 ≤ p.Y && p.Y ≤ 7 && !board[p.X, p.Y];
        }

        static Point add(Point a, Point b)
        {
            return new Point(a.X + b.X, a.Y + b.Y);
        }

        static bool solve(Point pos, int depth)
        {
            if (depth == 1)
                solution.Add(pos);

            board[pos.X, pos.Y] = true;

            if (depth == 64)
                return true;

            for (int i = 0; i < vectors.Length; ++i)
            {
                Point next = add(pos, vectors[i]);

                if (valid(next))
                {
                    if (solve(next, depth + 1))
                    {
                        solution.Insert(1, next);
                        return true;
                    }

                    board[next.X, next.Y] = false;
                }
            }

            return false;
        }
    }
}


Ausgabe:

{X=4,Y=7}
{X=6,Y=6}
{X=7,Y=4}
{X=6,Y=2}
{X=7,Y=0}
{X=5,Y=1}
{X=6,Y=3}
{X=7,Y=5}
{X=5,Y=4}
{X=7,Y=3}
{X=6,Y=1}
{X=4,Y=0}
{X=5,Y=2}
{X=6,Y=4}
{X=7,Y=6}
{X=5,Y=5}
{X=6,Y=7}
{X=4,Y=6}
{X=6,Y=5}
{X=7,Y=7}
{X=5,Y=6}
{X=4,Y=4}
{X=3,Y=2}
{X=5,Y=3}
{X=7,Y=2}
{X=6,Y=0}
{X=4,Y=1}
{X=2,Y=0}
{X=0,Y=1}
{X=1,Y=3}
{X=2,Y=5}
{X=3,Y=7}
{X=4,Y=5}
{X=5,Y=7}
{X=3,Y=6}
{X=1,Y=7}
{X=0,Y=5}
{X=2,Y=6}
{X=0,Y=7}
{X=1,Y=5}
{X=2,Y=7}
{X=0,Y=6}
{X=1,Y=4}
{X=3,Y=3}
{X=2,Y=1}
{X=0,Y=0}
{X=1,Y=2}
{X=2,Y=4}
{X=0,Y=3}
{X=1,Y=1}
{X=3,Y=0}
{X=4,Y=2}
{X=3,Y=4}
{X=2,Y=2}
{X=4,Y=3}
{X=3,Y=5}
{X=1,Y=6}
{X=0,Y=4}
{X=2,Y=3}
{X=0,Y=2}
{X=1,Y=0}
{X=3,Y=1}
{X=5,Y=0}
{X=7,Y=1}
private Nachricht | Beiträge des Benutzers
Gwinn
myCSharp.de - Member



Dabei seit:
Beiträge: 48

beantworten | zitieren | melden

Hi Community,

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.

Gruß Gwinn
private Nachricht | Beiträge des Benutzers
D4rkScr43m
myCSharp.de - Member



Dabei seit:
Beiträge: 32

beantworten | zitieren | melden

Dann mal was ganz simples:

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 .
private Nachricht | Beiträge des Benutzers
trib
myCSharp.de - Member



Dabei seit:
Beiträge: 692

beantworten | zitieren | melden

Hallo D4rkScr43m,

"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);
        }
private Nachricht | Beiträge des Benutzers
D4rkScr43m
myCSharp.de - Member



Dabei seit:
Beiträge: 32

beantworten | zitieren | melden

Hallo trib,

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).

Also lass ich das mal so gelten, weitermachen!
private Nachricht | Beiträge des Benutzers
trib
myCSharp.de - Member



Dabei seit:
Beiträge: 692

beantworten | zitieren | melden

Zitat von D4rkScr43m
da ist aber noch ein kleiner Fehler drin:
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 .
private Nachricht | Beiträge des Benutzers
D4rkScr43m
myCSharp.de - Member



Dabei seit:
Beiträge: 32

beantworten | zitieren | melden

Zitat von trib
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.

Ach ja? Ich hätte diese Ausgabe erwartet http://99-bottles-of-beer.net/lyrics.html
bei dir kommt ja nur die Zeile "[99 Bottles of Beer on the Wall]"

Aber wenn du willst, darfst du das ganze selbst implementieren ohne die Beispiele von http://99-bottles-of-beer.net/ zu verwenden :)
private Nachricht | Beiträge des Benutzers
DeZio
myCSharp.de - Member

Avatar #avatar-3334.png


Dabei seit:
Beiträge: 81

beantworten | zitieren | melden

1 bottles? :-)
private Nachricht | Beiträge des Benutzers
D4rkScr43m
myCSharp.de - Member



Dabei seit:
Beiträge: 32

beantworten | zitieren | melden

Zitat von DeZio
1 bottles? :-)

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 .
private Nachricht | Beiträge des Benutzers
trib
myCSharp.de - Member



Dabei seit:
Beiträge: 692

beantworten | zitieren | melden

Hallo zusammen,

[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 :)
private Nachricht | Beiträge des Benutzers
D4rkScr43m
myCSharp.de - Member



Dabei seit:
Beiträge: 32

beantworten | zitieren | melden

Mal sehen ob das so OK ist. Einen Wurfzähler in dem Sinne habe ich ja nicht verwendet:

private bool? m_lastRollStrike = null; // null = normaler Wurf, false = spare, true = strike
private bool m_lastButOneRollStrike = false;
private bool m_firstRoll = true;
private int[] m_score = new int[] { -1, -1, -1, -1, -1,
                                    -1, -1, -1, -1, -1,
                                    -1, -1, -1, -1, -1,
                                    -1, -1, -1, -1, -1,
                                    -1};

public void Roll(int pins)
{
    int roll = actualRoll();
    if (roll == -1 || (roll == 21 && m_lastRollStrike != null && !(bool)m_lastRollStrike))
        throw new NotSupportedException("Keine Würfe mehr! Zuerst die Punktzahl abrufen!");
    if (pins > 10)
        throw new ArgumentException("Es können nicht mehr als 10 Pins umgeworfen werden pro Wurf!");

    if (m_firstRoll)
    {
        if (m_lastButOneRollStrike)
            m_score[roll - 3] += pins;

        m_lastButOneRollStrike = false;
        if (m_lastRollStrike != null)
        {
            m_score[roll - 1] += pins;
            m_lastButOneRollStrike = (bool)m_lastRollStrike;
        }

        if (pins == 10)
        {
            if (roll + 2 < m_score.Length)
            {
                m_score[roll] = 0;
                m_score[roll + 1] = 10;
            }
            else
            {
                m_score[roll] = 10;
            }
            m_lastRollStrike = true;
        }
        else
        {
            m_score[roll] = pins;
            m_firstRoll = false;
            m_lastRollStrike = null;
        }
    }
    else
    {
        if (pins + m_score[roll - 1] > 10)
            throw new ArgumentException("Es wurden mehr Pins umgeworfen als noch standen!");

        m_score[roll] = pins;

        if (m_lastButOneRollStrike)
            m_score[roll - 2] += pins;

        if (m_score[roll - 1] + pins == 10)
            m_lastRollStrike = false;
        else
            m_lastRollStrike = null;

        m_lastButOneRollStrike = false;
        m_firstRoll = true;
    }
}

public int Score()
{
    int s = 0;
    for (int i = 0; i < m_score.Length; i++)
    {
        s += m_score[i] == -1 ? 0 : m_score[i];
        m_score[i] = -1;
    }
    m_firstRoll = true;
    return s;
}

private int actualRoll()
{
    for (int i = 0; i < m_score.Length; i++)
        if (m_score[i] == -1)
            return i;
    return -1;
}
private Nachricht | Beiträge des Benutzers
trib
myCSharp.de - Member



Dabei seit:
Beiträge: 692

beantworten | zitieren | melden

Hallo D4rkScr43m,

Folgender Test für einen Perfekten Lauf liefert einen Fehler:

for (int i = 0; i < 12; i++)
    Roll(10);
    //Für Spartaaaa
    Assert.AreEqual(300, Score());
Keine Würfe mehr! Zuerst die Punktzahl abrufen!
private Nachricht | Beiträge des Benutzers
D4rkScr43m
myCSharp.de - Member



Dabei seit:
Beiträge: 32

beantworten | zitieren | melden

hallo trib,

ich hab ausversehen das Endgame bei der Punkteberechnung doppelt mit eingerechnet.

Hier die korrigierte Version (Außerdem hab ich noch weitere Fehleingaben abgefangen):

private bool? m_lastRollStrike = null; // null = normaler Wurf, false = spare, true = strike
private bool m_lastButOneRollStrike = false;
private bool m_firstRoll = true;
private int[] m_score = new int[] { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };

public void Roll(int pins)
{
    int roll = actualRoll();
    if (roll == -1 || (roll == 20 && m_lastRollStrike == null) || (roll == 21 && (m_lastRollStrike == null || !(bool)m_lastRollStrike)))
        throw new NotSupportedException("Keine Würfe mehr! Zuerst die Punktzahl abrufen!");
    if (pins > 10)
        throw new ArgumentException("Es können nicht mehr als 10 Pins umgeworfen werden pro Wurf!");
    if(pins < 0)
        throw new ArgumentException("Die Anzahl der Pins die umgeworfen wurden muss größer gleich 0 sein!");
    if (m_firstRoll)
    {
        if (m_lastButOneRollStrike)
            m_score[roll - 3] += pins;

        m_lastButOneRollStrike = false;
        if (m_lastRollStrike != null)
        {
            m_score[roll - 1] += pins;
            m_lastButOneRollStrike = (bool)m_lastRollStrike;
        }

        if (pins == 10)
        {
            if (roll + 2 < m_score.Length)
            {
                m_score[roll] = 0;
                m_score[roll + 1] = 10;
            }
            else
            {
                m_score[roll] = 10;
            }
            m_lastRollStrike = true;
        }
        else
        {
            m_score[roll] = pins;
            m_firstRoll = false;
            m_lastRollStrike = null;
        }
    }
    else
    {
        if (pins + m_score[roll - 1] > 10)
            throw new ArgumentException("Es wurden mehr Pins umgeworfen als noch standen!");

        m_score[roll] = pins;

        if (m_lastButOneRollStrike)
            m_score[roll - 2] += pins;

        if (m_score[roll - 1] + pins == 10)
            m_lastRollStrike = false;
        else
            m_lastRollStrike = null;

        m_lastButOneRollStrike = false;
        m_firstRoll = true;
    }
}

public int Score()
{
    int s = 0;
    for (int i = 0; i < m_score.Length; i++)
    {
        if (i < m_score.Length - 2)
            s += m_score[i] == -1 ? 0 : m_score[i];
        m_score[i] = -1;
    }
    m_firstRoll = true;
    return s;
}

private int actualRoll()
{
    for (int i = 0; i < m_score.Length; i++)
        if (m_score[i] == -1)
            return i;
    return -1;
}
private Nachricht | Beiträge des Benutzers
trib
myCSharp.de - Member



Dabei seit:
Beiträge: 692

beantworten | zitieren | melden

Zitat von D4rkScr43m
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])

Dann bist Du dran, D4rkScr43m!
private Nachricht | Beiträge des Benutzers
D4rkScr43m
myCSharp.de - Member



Dabei seit:
Beiträge: 32

beantworten | zitieren | melden

Mir fällt beim besten Willen keine Aufgabe ein, also darf jeder der möchte eine stellen!
private Nachricht | Beiträge des Benutzers
Daniel B.
myCSharp.de - Member



Dabei seit:
Beiträge: 87
Herkunft: Linz

beantworten | zitieren | melden

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
Attachments
private Nachricht | Beiträge des Benutzers