Kann man Pygame auf dem iPhone installieren?

Man kann PyGame-Spiele auf iOS portieren. Deinem weiteren Text zufolge suchst du aber eigentlich nach einer Python-Entwicklungsumgebung für dein Gerät.

Zwei Optionen wären da replit (in der du auch PyGame installieren kannst) oder Pythonista. Mit letztgenannter App kannst du zwar auch kleine Spiele oder Animationen entwickeln, jedoch nicht mit PyGame.

(...) aber er ist so alt und langsam, das man fast nichts mit ihm anfangen kann (...)

Python/PyGame hat keine hohen Systemanforderungen. Daher wird es da wohl kaum Probleme geben.

...zur Antwort
Weiß jemand wie man das beheben (...)

Mit FreeConsole löst du dich (bzw. den Prozess deines Programms) von der Konsole. Das heißt, du hast auf sie auch keinen Zugriff mehr. Du müsstest dich erst mit AttachConsole oder AllocConsole an eine Konsole binden, um wieder schreiben zu können.

(...) und vlt. auch welche Bedeutung die Rückgabewerte beider Imports haben?

Der Rückgabewert gibt bei beiden Funktionen jeweils an, ob die Aktion erfolgreich war. In dem Fall muss er ungleich 0 sein.

...zur Antwort

Groovy ist ganz nett, da du - so wie man es auch von anderen Skriptsprachen kennt - recht schnell und einfach kleine Anwendungen (z.B. Automatisierungsskripte, Unittests) entwickeln kannst. Im Gegensatz zu Java bietet Groovy mehr syntactic sugar (z.B. implizit generierte Getter/Setter, ein stärker ausgebautes switch-case-Konstrukt, Support für truthy-Werte) und generell kann man die Syntax viel schlanker halten.

Es macht meiner Meinung aber nur Sinn, Groovy als Erweiterung zu Java zu lernen (was es nun ja auch sein soll). Du wirst sie eh meist nur im Java-Umfeld antreffen. Einige Projekte nutzen Groovy direkt im Mix mit der Java-Sprache.

Was einen Umstieg von Java auf Groovy meines Erachtens etwas erschwert, sind Verhaltensunterschiede selbst bei gleichem Code (Beispiele: Der Equality-Operator, String-Literale, Multimethods, Standardsichtbarkeit von Feldern).

...zur Antwort

Bei InOut handelt es sich um eine Klasse, die vom Java Editor vordefiniert wird (siehe hier). Das heißt, in anderen Entwicklungsumgebungen (wie Eclipse, NetBeans, u.ä.) kannst du sie nicht verwenden, sofern du diese Klassendefinition nicht explizit mit in dein Projekt kopierst.

Diese Klasse stellt dir ein paar Methoden zur Verfügung, mit denen du Eingaben vom Konsoleneingabekanal lesen oder Ausgaben in den Konsolenausgabekanal schreiben kannst.

Die Methode readInt gibt zuerst die an sie übergebene Zeichenkette ("Zahl (>=0) : ") in der Konsole aus. Anschließend versucht sie die nächste Eingabe in der Konsole auszulesen und in eine Ganzzahl zu konvertieren. Wenn das klappt, wird die gelesene Zahl in eine Variable namens zahl abgelegt.

...zur Antwort

Ich würde es zunächst an einem bildlichen Beispiel beschreiben.

Stell dir vor, du bist Kellner in einem Bierzelt. Du könntest hier nun jedes Maß einzeln transportieren, was dich einige Zeit kosten dürfte. Effektiver wäre es, mehrere Krüge auf einem Tablett zu transportieren, welches so weit gefüllt wird, bis seine Belastungsgrenze ausgereizt ist.

Das Commit-Log wäre in diesem Fall die Kundenbestellliste. Sie sichert ab, dass jeder registrierte Kunde seine Bestellung erhält. Das Tablett stellt die MemTable dar. Es ist ein lokaler Zwischenspeicher, der erst einmal so viel aufnimmt, wie ihm möglich ist. Sobald das Tablett voll ist, werden die Krüge (Daten) zum tatsächlichen Zielsystem transportiert (SSTable) und somit die Bestellung abgeschlossen.

Was ist ein In-Memory-System?

Im Grunde ist damit ein Speicherbereich innerhalb des Arbeitsspeichers gemeint. Also Speicherplatz, der dem Programm (Cassandra) zur Programmlaufzeit zur Verfügung steht.

Der Vorteil an so einem System ist, dass die Daten schneller verarbeitet werden können. Der Computer hat einfachere, schnellere Zugriffsmöglichkeiten auf seinen Arbeitsspeicher.

Allerdings ist der Speicherplatz natürlich begrenzt und nicht persistent (bei Programmbeendigung wird der Bereich neu reserviert und die Daten sind weg). Daher müssen die Daten irgendwann in ein persistentes System übertragen (Speicherung auf der Festplatte/SSTable) werden.

Müsste Cassandra auf diesen Zwischenspeicher verzichten und die Daten stattdessen sofort auf der Festplatte speichern, würden die Schreibvorgänge viel länger dauern. Andersherum bietet der Zwischenspeicher den Vorteil, dass du Daten, die erst kürzlich geschrieben (aber noch nicht persistent gespeichert) wurden, schneller abrufen kannst.

Was ist ein MemTable?

MemTable ist einfach nur der Name für so einen Speicherbereich. Da die Daten im Speicher entsprechend formatiert werden (sodass sie später leichter/schneller in das persistente System übertragen werden können), ist das Wort Table in dem Begriff inkludiert.

Cassandra kann übrigens mehrere MemTables anlegen. Zu jeder Datenbanktabelle gibt es maximal eine aktive MemTable (die aktuelle Schreibvorgänge aufnimmt) und dazu kann es noch mehrere inaktive MemTables geben, die noch darauf warten, weiter befüllt oder geleert zu werden.

Was ist mit "die Daten hält, bis sie voll sind" gemeint?

Einfach gesagt, wartet eine MemTable darauf, einen bestimmten Schwellenwert zu erreichen. Ist die Datenbank z.B. so konfiguriert, dass eine Memtable maximal 5 MB fassen darf, würde sie bei Überbieten dieses Werts ihre Daten an die SSTable abgeben.

Es gibt allerdings noch andere Kriterien/Konfigurationsmöglichkeiten, die bestimmen, wann eine MemTable geleert wird. Du könntest eine Zeitperiode vorgeben (z.B. Speichere alle fünf Sekunden die Daten einer MemTable persistent) und es gibt ein Speicherlimit für das Commit-Log.

...zur Antwort

Die Klasse steht in Abhängigkeit zu anderen Packages (aus der Mod), die dir bei der Kompilierung logischerweise fehlen.

Du brauchst den Java-Code der kompletten Mod (mitsamt ihrer Abhängigkeiten zu weiteren Bibliotheken o.ä.). In dem kannst du die Klasse ersetzen, dann kannst du das Programm neu kompilieren.

...zur Antwort

Legt euch eine Variable an, die die verbleibende Zeit (in Sekunden) speichert. Immer wenn das Programm eine Sekunde wartet, muss auch die Variable um 1 verringert werden. Des Weiteren wäre es günstig, sich die aktuelle Zielscheibe sowie die Menge aller verfügbaren Zielscheiben global zu speichern.

Anschließend braucht es nur zwei Abfragen:

  1. Ist die Zeit abgelaufen? Wenn ja, wird eine neue Zielscheibe gesucht und angezeigt. Um zu verhindern, dass zweimal nacheinander dieselbe Zielschreibe ausgewählt wird, könnte man das Fisher-Yates-Verfahren nutzen. Des Weiteren muss die Zeitvariable zurückgesetzt werden
  2. Wurde die Zielscheibe getroffen? Wenn ja, wird die Zeitvariable auf 0 gesetzt (Zeitablauf).

In dem Fall, dass weder die erste, noch die zweite Bedingung erfüllt wurden, wird eine Sekunde lang gewartet, bis das Programm weiterläuft.

Erstellt euch dazu ein Struktogramm oder einen Programmablaufplan. Aktionen wie die Auswahl einer neuen Zielscheibe oder die Prüfung, ob die aktuelle Zielscheibe getroffen wurde, werden in eigenen Struktogrammen/Programmablaufplänen skizziert.

...zur Antwort

Da dein Beispielbaum klein ist, kannst du den Algorithmus auch gut Schritt-für-Schritt durchgehen.

Ich zeige einmal den Ablauf für den linken Teilbaum. Wir starten mit dem Wurzelknoten (n(5)):

n(5) is not None > wahr
in_order_traversal(n(3))
  n(3) is not None > wahr
  in_order_traversal(n(1))
    n(1) is not None > wahr
    in_order_traversal(None)
      None is not None > unwahr
    Ausgabe von 1
    in_order_traversal(None)
      None is not None > unwahr
  Ausgabe von 3
  in_order_traversal(n(4))
    n(4) is not None > wahr
    in_order_traversal(None)
      None is not None > unwahr
    Ausgabe von 4
    in_order_traversal(None)
      None is not None > unwahr
  Ausgabe von 5
  in_order_traversal(n(8))
    usw. ...

Die in_order_traversal-Funktion ist rekursiv. Das heißt, sie ruft sich immer wieder selbst auf. Immer wenn der Programmfluss in einen neuen Funktionskontext wechselt, habe ich im obigen Verlauf die Einrückungsstufe weiter nach rechts gesetzt.

Da bei jedem Aufruf ein Subknoten übergeben wird, kann in der Baumstruktur nach unten geklettert werden. Die Prüfung, ob der übergebene Knoten existiert, ist die Abbruchbedingung der Rekursion. In diesem Fall ruft sich die Funktion nicht wieder selbst auf, sondern wird beendet. Somit kann der Programmfluss wieder zum Aufrufer springen (bzw. hier hochklettern).

...zur Antwort

In der Planungsphase (also noch vor dem Schreiben von Code) solltest du dir Gedanken darüber gemacht haben, was dein zu lösendes Problem ist und welche Anforderungen es stellt. Auf dieser Grundlage können Testfälle definiert werden.

Ein Beispiel: Ein Programm für die Berechnung des Quotient aus der Division zweier natürlicher Zahlen (inklusive 0) soll entwickelt werden.

Ein paar mögliche Testfälle:

  • 4 / 2 = 2
  • 5 / 2 = 2.5
  • 5.1 / 2 = nicht erlaubt
  • 2 / 5.1 = nicht erlaubt
  • 5 / 0 = NaN / nicht erlaubt
  • 0 / 5 = 0
  • a / 2 = NaN / nicht erlaubt
  • 2 / a = NaN / nicht erlaubt

Diese decken nicht nur die erwarteten, üblichen Anwendungsfälle ab, sondern ebenso Randfälle.

Sicherlich findet man nicht immer alle möglichen Fälle, aber man kann zumindest eine große Menge abdecken, wenn man sich etwas Zeit nimmt. Wenn du das zudem schon vor der konkreten Implementation machst, kann die einfacher und stabiler ausfallen, als wenn man erst im Nachhinein nochmals Änderungen hineinfrickelt.

Während der Implementationsphase kannst du Unittests implementieren, die einzelne Funktionen testen. Jest wäre ein Framework, welches man an der Stelle einsetzen kann.

Auch eine statische Codeanalyse wäre sinnvoll. Wenn ich mir nun nur einmal deinen Codesnippet anschaue, fallen mir direkt undefinierte Symbole auf: displayTimeSetting und antwort. Mit age wiederum machst du gar nichts.

Deine genutzten Sprachelemente sind übrigens nicht mehr zeitgemäß. Statt Variablen mit var zu erstellen, wären let/const sinnvoller. Den Request kannst du einfacher mit der Fetch API verschicken.

async function getAge() {
  const response = await fetch("update_time.php");

  if (!response.ok) {
    throw new Error("Request failed");
  }

  return await response.text();
}

async function updateTime() {
  const age = await getAge();
  // ...
}

Die Funktion habe ich in diesem Fall in zwei Funktionen aufgeteilt, da der Prozess aus getAge somit einfacher testbar ist. Ob der Funktionsname passt, müsstest du dir selbst überlegen.

Für eine Analyse des Laufzeitverhaltens der Anwendung würde ich dir empfehlen, einen Debugger zu verwenden. In all den bekannten Browsern (Brave, Chrome, Edge, Firefox, Opera, Safari, ...) ist in deren Webentwicklungstools ein solcher integriert.

...zur Antwort

Wie du die Fenster neu positionieren kannst, steht im Manual unter Arrange tool windows. Diese neue Layoutanordnung kannst du entweder als Standardlayout abspeichern (Window > Layout Settings > Store Current Layout as Default) oder als separates, neues Layout.

...zur Antwort

Beim Domain Reloading wird der Zustand deiner Skripte zurückgesetzt, sodass du beim nächsten Wechsel in den Play-Modus wieder den Initialzustand hast. Insofern könnte die Problemursache tatsächlich in deinen Skripts oder deinen Packages liegen.

Prüfe zunächst, ob du Ressourcen (wie Datenbankverbindungen, Netzwerkverbindungen, Streams, u.ä.) in deinen Skripts richtig handhabst. Sie sollten beispielsweise bei Stop/Beendigung richtig geschlossen und im Speicher wieder freigesetzt werden (Dispose). Ein anderer Grund könnte eine ausgelöste Endlosrekursion sein (z.B. in der Serialisierung oder Event Handlers wie OnEnable, OnDisable).

Ob und wenn ja, an welchem externen Asset oder Plugin es liegen könnte, ist wiederum etwas schwieriger zu prüfen. Entweder man probiert es mit Entfernen/Einfügen (in einem neuen / duplizierten Projekt; nicht genutzte Plugins sollten prinzipiell raus) oder (was generell hilfreich wäre) man betrachtet die Unity-Prozesse einmal unter einem Profiler, um zu sehen, an welcher Ressource sich der Prozess aufhängt. Dieser Thread aus dem Unity-Forum stellt eine Methodik vor, um den Call Stack auszulesen.

Wenn du bei deinen Analysen nichts findest, wäre es ebenso noch eine Alternative, Domain Reloading einfach auszuschalten. Statische Felder musst du dann allerdings selbst zurücksetzen und statische Event Handler selbst abmelden. Im Unity Manual steht mehr dazu (s. Domain Reloading).

Ein paar weitere Vorschläge zum Ausprobieren:

  • Deaktiviere den Burst Compiler im Editor (Jobs > Enable Burst Compilation; zumindest in den Unity 2022er-Versionen gab es deswegen noch Probleme)
  • Ändere das Refresh-Verhalten (Edit > Preferences > General: Script Changes While Playing = Stop Playing And Recompile)
  • Der Artikel Faster Unity Script Changes listet mehrere allgemeine Punkte auf, die im Zusammenhang mit dem Script-Reload stehen bzw. für eine Abhilfe sorgen können (z.B. Softwareaktualisierungen, Cache Restores, etc.)
  • Starte Unity mit Administratorrechten
...zur Antwort

Geh die gesamte Transportkette noch einmal schrittweise durch. In den Webentwicklungstools deines Browsers (Network-Tab) kannst du prüfen, welcher Payload mit deinen Requests übertragen wurde. Insofern kannst du ermitteln, ob es folgend beim Lesen des Werts oder bei der Weitergabe scheitert.

Anhand der von dir geteilten Informationen ist nicht ersichtlich, wo es genau scheitert. Man könnte lediglich vermuten, dass du in Schritt 2 kein Formular nutzt oder in Schritt 3 tatsächlich eine undefinierte Variable einsetzt.

Ein funktionaler Weg würde jedenfalls so aussehen:

Initialer Trigger:

<?php header("Location: page2.php?variable=123");

page2.php:

<!-- ... -->
<form action="page3.php" method="post">
  <!-- ... -->
    <input type="submit" name="a" value="<?= $_GET['variable'] ?>">
  <!-- ... -->
</form>

page3.php:

<?php
  if (isset($_POST['a'])) {
    header("Location: a.php?variable=" . $_POST['a']);
    exit;
  }

a.php:

<?php print $_GET['variable'];

Wenn alle drei Seiten über dieselbe Domain laufen und sich der Wert zwischen dem ersten und letzten Schritt nie ändert, wäre es allerdings durchaus eine Überlegung wert, den Wert stattdessen in einer Session abzulegen.

Erste Seite:

<?php
  session_start();
  $_SESSION['variable'] = 123;

Letzte Seite:

<?php
  session_start();
  print $_SESSION['variable'];

Auch auf allen dazwischenliegenden Seiten muss am Dateianfang erst die session_start-Funktion aufgerufen werden, um die bestehende Session nicht zu verlieren.

...zur Antwort

Wenn ein Fall zutrifft, sind weitere Prüfungen unnötig.

wenn Z1 > Z2
ja:               nein:
Ausgabe: größer   wenn Z1 < Z2:
                  ja:                   nein:
                  Ausgabe: kleiner      Ausgabe: gleich

Dein Programm scheitert sicherlich daran, dass du Vergleiche in die Anweisungsblöcke gepackt hast, die auf ja/nein deiner Verzweigungen folgen.

...zur Antwort

Zuallerst möchte ich darauf eingehen:

(...) der Stundenvideos macht, in denen man kostenlos seine Projekte nachcoden (...) kann, um zu üben (...)

denn hier steht doch tatsächlich die Frage im Raum, wie du effektiv als (vermutlich) Anfänger etwas lernen kannst. Wenn ich so stichprobenhaft durch das Video springe, höre ich stets nur Tippgeräusche, aber keinerlei Erklärung zu dem, was er tut oder der allgemeinen Strategie. Insofern sehe ich das eher als verschwendete Lebenszeit an - sich einfach nur den fertigen Quellcode herunterzuladen und den dann zu benutzen, geht doch viel schneller (und sorgenfreier).

Ich würde dir grundsätzlich von Abtippkursen deutlich abraten, zumal sie dich eben sehr schnell in so eine Situation bringen, in der du nun steckst. An irgendeinem Punkt wurde etwas nicht richtig nachgemacht und diese(n) Fehler gilt es nun zu finden. Wenn du nun auch den Code nicht richtig verstehst, stehst du am selben Punkt wie zuvor. Du bleibst abhängig von den Lösungen anderer.

Sollten dir noch generelle Grundlagenkenntnisse zu HTML, CSS oder JavaScript (mitsamt der DOM-API) fehlen, solltest du dich erst einmal damit auseinandersetzen.

Gute Lernquellen in dieser Hinsicht bieten diese drei Seiten:

  • MDN
  • Media Event
  • SelfHTML

Eine Wetterapp wäre im Anschluss zwar kein schlechtes Anfängerprojekt, allerdings wäre es besser, so etwas ohne Vorlage anzugehen. Natürlich dauert das länger und ist am Ende sicherlich noch nicht so qualitativ hochwertig, doch es bietet viel mehr Lernpotenzial. Vor allem, da du selbst schauen musst, wie du Lösungen zu deinen gestellten Problemen (Anforderungen) findest.

Ohne Grundlagenkenntnisse brauchst du von hier an übrigens nicht mehr weiterlesen.

Ich bin mehrmals durch den Code gegangen und habe einige Fehler finden können, aber es wurde nicht besser (...)

Da der Google Drive-Link inzwischen funktioniert, habe ich mir den Code aus dem weatherio-software-starter-duc-thanh-neuer-versuch-Ordner kurz angeschaut. Ob die Probleme, die ich gefunden habe, nun von dir stammen oder bereits im Originalquellcode falsch sind, habe ich nicht geprüft (es ist eh unwichtig).

Im HTML- und CSS-Code habe ich direkt diese Fehler gefunden:

  1. Im Humidity-Teaser ist der schließende sub-Tag unvollständig.
  2. In der Feels Like-Card fehlt der schließende sup-Tag. Das gilt sowohl in der index.html, als auch in der app.js.
  3. Mehreren img-Tags fehlt ein alt-Attribut. Dessen Wert stellt einen textuellen Ersatz des Bildes dar, sofern dieses zum Seiteninhalt aktiv beiträgt (also nicht dekorativer Bedeutung ist). Die Icons bei der 5d-Vorhersage stellen beispielsweise bedeutungsvollen Inhalt dar. Bei dem Logo handelt es sich normalerweise um ein dekoratives Element, weshalb da der Wert leer sein sollte (alt=""). Da es bei dir allerdings in einem Link liegt, der keinen Linktext hat, sollte das alt-Attribut den Linktext verkörpern (alt="Go to start page").
  4. Der href-Wert des Powered by OpenWeather Api-Links ist invalid. Innerhalb der URL dürfen keine Leerzeichen vorkommen.
  5. Ab und an werden Paragraphen innerhalb von span-Elementen verschachtelt (anders ausgedrückt: Du setzt ein Blockelement in ein Inline-Element). Das ist ein Widerspruch und nicht zulässig. Verzichte entweder auf das span oder vertausche das span gegen ein Blockelement (wie div) oder noch besser: Vertausche die Verschachtelung (das span-Element kommt in den Paragraph).
  6. In der CSS-Regel mit dem Selektor .search-field ::-webkit-search-cancel-button ist der display-Wert falsch (noen statt none).
  7. Für das overflow-y-Property wird zweimal der Wert overlay gesetzt. Das ist allerdings ein ungültiger Wert. Schau hier für die, die tatsächlich möglich sind.
  8. Wenn ein CSS-Property mehrmals in einer CSS-Regel gesetzt wird, überschreibt das letzte Vorkommen übrigens die vorherigen (siehe .search-view .view-list). Es ist dahingehend kein Fehler, doch ich würde solche Redundanzen vermeiden.
  9. In der CSS-Regel für den Footer ist der Name des CSS-Properties --on-surface-variant aufgrund des zwischengesetzen Leerzeichens nicht richtig.
  10. In der app.js wird einmal das HTML-Entity &deg; falsch geschrieben (vor dem Semikolon ist ein Leerzeichen).
  11. Bei den Media Queries wurde width stets falsch geschrieben. Das dürfte dein Grid-Problem dann auch lösen.

Bezüglich des JavaScript-Codes fällt Folgendes auf:

1) Keines der Skripte ist im Dokument eingebunden. Insofern wird da auch nie etwas ausgeführt werden.

Achte im Übrigen darauf, die Seite am besten über einen Webserver auszuführen. Andernfalls wird dein Browser die AJAX-Requests automatisch blockieren (Stichwort: CORS). Das steht so dann auch in der Browserkonsole.

2) Die Variablennamen in der getDate-Funktion sind falsch. Sowohl logisch (es soll ein Wochentags- und ein Monatsname gespeichert werden - Singular statt Plural) als auch sprachlich. Letzteres an einem kurzen, vereinfachten Beispiel erklärt:

const a = a;

Hier gibt es den Versuch, die Variable a zu erstellen und mit dem Wert von a zu definieren. Das ist ein Widerspruch, da a ja noch nicht wirklich existiert (bzw. undefiniert ist). Würde das rechtsseitige a aus einem äußeren (globalen) Kontext kommen (so wie auch in deinem Fall), wäre das bedeutungslos, da die Deklaration der (linksseitigen) Konstante a tatsächlich zuerst erfolgt und globale gleichnamige Symbole überdeckt.

Von daher:

const weekDayName = weekDayNames[date.getUTCDate()];
const monthName = monthNames[date.getUTCMonth()];

return `${weekDayName} ${date.getUTCDate()}, ${monthName}`;

3) Zwei Fehler betreffen fehlende bzw. unauffindbare Elemente.

Zum einen wird für das aktuelle Wetter ein Element mit einem data-location-Attribut gesucht, welches im Template-String wohl nicht gesetzt wurde:

<p class="title-3 meta-text" data-location>data-location</p>

Ebenso kann bei der Ausgabe der Wettervorhersage kein Element mit einem data-temp-Attribut gefunden werden. Das liegt schlichtweg daran, dass der gesamte Inhalt des Elternelements ([data-hourly-forecast]) zuvor überschrieben und anschließend nirgendwo mehr das data-temp-Attribut gesetzt wird. Wenn du in das (initiale) HTML schaust, siehst du, dass es auf dem Slider (.slider-list) liegen sollte.

4) Bei der Ausgabe für die heutigen Höhepunkte wird im Template-String eine undefinierte Variable api benutzt. Vermutlich ist das ein Tippfehler und aqi wäre richtig.

5) Bei der Extraktion der Wetterdaten (currentWeather) ist das Property visibility falsch geschrieben. Dieser Schreibfehler muss auch im Template-String weiter unten behoben werden, damit die Berechnung klappt.

6) Die 5d-Vorhersage wird nicht gerendert, da die Schleife vollkommen falsch ist. Bei forecastList handelt es sich um ein Array, folglich kannst du es nicht mit einer Zahl vergleichen. Richtig wäre ein Vergleich mit der Länge:

for (let i = start, day = 0; i < forecastList.length && day < 5; i += 8, ++day) 

Die Variable day würde in diesem Zug dazu dienen, die Anzahl an Tagen zu begrenzen und im Schleifenkörper die richtigen Datumsangaben zu berechnen.

Des Weiteren wird der Startindex statisch gesetzt, obwohl die Startzeit der Einträge im Array zeitlich variiert. So ist aktuell der erste Eintrag für den 1.4., 15 Uhr. Der vierte Eintrag entspricht bereits dem 2.4..

Du solltest also zuerst ermitteln, für welche Startzeit die API-Rückgabe erfolgt, um dann den richtigen Startindex für die Schleife zu finden. Die Stundenanzahl des ersten Eintrags kannst du dir über dessen dt-Property holen:

const startHours = new Date(forecastList[0].dt * 1000).getUTCHours();

Die Multiplikation mit 1000 ist notwendig, um einen Zeitstempel in Millisekunden zu erhalten.

Möglicherweise gibt es noch weitere (logische) Fehler. Die solltest du dann allerdings selbst erst einmal prüfen (oder zumindest genauer beschreiben).

Nutze für eigene Analysen die Webentwicklungstools deines Browsers (Konsole, Debugger, Inspektor). Solltest du einen Chromium-basierten Browser nutzen (Chrome, Brave, Edge, Opera), kann dir die Chrome DevTools-Dokumentation für einen Einstieg helfen. Firefox hat ebenso eine Dokumentation zu seinen Entwicklungstools.

...zur Antwort

In der Softwareentwicklung nimmt man oft eine Aufteilung vor, die die Anwendungslogik und die Nutzeroberfläche voneinander trennt. Für Letztere kommt dann oft eine Sprache zum Einsatz, mit der man schnell und einfach die notwendigen Oberflächenkomponenten anlegen kann. Bei der Entwicklung von Webseiten würde HTML diese Rolle einnehmen. Mit JavaScript wird hingegen Anwendungslogik formuliert.

Ein sehr einfaches Beispiel:

<!doctype html>
<title>Example</title>
<body>
  <button id="sayButton" type="button">Say hello</button>
  <p id="output"></p>
  <script src="script.js"></script>
</body>

script.js:

const button = document.getElementById("sayButton");
button.addEventListener("click", function() {
  const output = document.getElementById("output");
  output.textContent = "Hello!";
});

Mit HTML wird ein Dokument erstellt, welches einen Button und einen Paragraph beinhaltet. Außerdem wird ein Skript eingebunden, welches dafür sorgt, dass bei Buttonklick ein Text in den Paragraph geschrieben wird.

Oberfläche und Funktionalität (Anwendungslogik) sind somit ganz klar voneinander getrennt. Der erste Teil wird mit HTML umgesetzt, der zweite Teil mit JavaScript. Neben einer besseren Übersichtlichkeit (jede Datei beinhaltet möglichst nur eine Sprache) werden beide Ressourcen auch eher wiederverwendbar/einfacher austauschbar. Du könntest das Skript auch gegen ein anderes austauschen, welches bei Buttonklick stattdessen die Seite grün einfärbt, o.ä..

Wenn du dich nun weiter mit der Entwicklung von Webseiten beschäftigen möchtest, solltest du dich zunächst mit HTML (sowie CSS) auseinandersetzen. Entsprechende Ressourcen findest du auf diesen Seiten:

  • MDN
  • Media Event
  • SelfHTML
Richtig programmieren lernen (...)

Beginne stets bei den Grundlagen (Syntax, Konzepte).

Lernquellen lassen sich in der Regel recht leicht finden. Zu vielen Technologien (z.B. den meisten Programmiersprachen) gibt es eine offizielle Webseite/Dokumentation - das sollte bestenfalls immer dein erstes Rechercheziel sein. Ebenso gibt es Lernplattformen (wie Exercism, Hyperskill, Udemy, ...) die Kurse zu einer größeren Auswahl an Programmiersprachen anbieten. Andernfalls lohnt es sich, auch hier (oder anderen Foren, die sich mit Softwareentwicklung/Programmierung befassen) wenigstens einmal die Suchfunktion zu nutzen. Die Frage, wie man mit Programmieren (oder explizit Sprache XY) anfangen kann, ist ja nun nicht wirklich neu oder unbeantwortet.

Definitiv meiden solltest du allerdings jegliche Art von Crashkurs (Programmieren lernen in X Minuten/Stunden/Tagen...). Programmieren lernen erfordert Geduld. Eile und Kurzfassungen führen eher zu Halbwissen, was dir später wieder auf die Füße fällt.

Nimm dir daher die Zeit; vermische Theorie mit Praxis, indem du das, was du dir anliest/anhörst selbst praktisch ausprobierst. Umso mehr du dir aneignest, umso mehr kannst du miteinander verbinden und so komplexere Übungen angehen. Übungsaufgaben/-ideen findest du unter anderem auf Webseiten wie Edabit oder Exercism.

Ein großer Teil neben dem Erlernen einer Programmiersprache ist das Erstellen eigener Algorithmen (Lösungsfindung), was einer Problemanalyse vorausgeht. Sprich, der Kern der Programmiertätigkeit. Das wird meiner Erfahrung nach in vielen Tutorials/Kursen/... sehr vernachlässigt und doch eine der größten Hürden für Anfänger. Da ich dazu schon oft genug geschrieben habe, würde ich hierfür auf einen älteren Beitrag von mir verweisen.

Sobald du etwas Sicherheit in Grundlagenthemen (bezogen auf JS: Kontrollstrukturen, Arrays/Listen, Operatoren, Funktionen, Closures) gesammelt hast, wäre es gut, sich mit der objektorientierten Programmierung auseinderzusetzen. Für die Kommunikation mit HTML-Elementen wäre zudem die DOM-API von Bedeutung.

Nachfolgend wäre es interessant, sich mit Entwurfsmustern in JavaScript zu beschäftigen sowie Node.js und einer/m Bibliothek/Framework wie Angular, Nextjs, React oder Vue.

...zur Antwort

1) Es ist seltsam, dass du für deine drei Personen Funktionen definierst. Funktionen sind nicht als Datenspeicher gedacht, sondern dazu da, eine Operation zu beschreiben / auszuführen (z.B. addieren, Daten speichern, ...).

Erstelle doch stattdessen eine Klasse, von der du drei Instanzen ableitest.

class Person:
  def __init__(self, first_name, last_name, age, nationality, birthday, id):
    self.first_name = first_name
    self.last_name = last_name
    self.age = age
    self.nationality = nationality
    self.birthday = birthday
    self.id = id

max = Person("Max", "Mustermann", 26, "german", "27. August", 244233333)
# etc. ...

2) Die Namen deiner Variablen, die eine Eingabe aufnehmen, sind irreführend. Du nutzt den Plural, obwohl der enthaltene Wert immer nur einem Namen entspricht.

3) Das Schlüsselwort and entspricht einer logischen Verknüpfung. Geprüft wird, ob first_names wahr ist (ja, so lange der Wert nicht leer ist) und last_names dem String "Max Mustermann" entspricht. Du möchtest doch aber eher prüfen, ob beide Variablen zusammengenommen dem vollen Namen entsprechen.

if first_names == "Max" and last_names = "Mustermann":

4) Deine Funktionen liefern keinen Rückgabewert. Daher bekommst du auch keine Antwort in der Konsole.

Bei Anwendung von Klassen/Objekten könnte man die String-Repräsentation überschreiben.

Beispiel:

class Person:
  """ constructor ... """

  def __str__(self):
    return self.first_name + " " + self.last_name + """ etc. ... """

max = Person("Max", "Mustermann", 26, """ etc. .... """)
print(max)

Implizit wird die print-Funktion versuchen, das Objekt max in einen String zu konvertieren. Dabei wird dessen __str__-Methode aufgerufen.

...zur Antwort

Dir fehlt einfach nur ein return-Statement vor dem await:

return await fetch(/* etc. ... */

Für den Fall, dass der Request aus irgendeinem Grund einmal fehlschlägt, wäre es allerdings gut, noch ein catch-Aufruf anzuhängen.

...zur Antwort