Digitaluhr, Hilfe !

zide_07

Mitglied
Hallo folgende Aufgabenstellung habe ich erhalten, ich muss sagen bin eine Anfängerin und überfordert. Meine bisherige Bearbeitung führt einfach zu nicht, daher bitte ich um Lösungsvorschläge, Danke im vorraus 🙂.

Programmieren Sie eine Digitaluhr, die Stunden, Minuten, Sekunden und Zehntelsekunden wie folgt anzeigt: h:mm:ss,z Verwenden Sie vier Variablen h, m, s und z für die Werte. Beim Programmstart soll die Uhr 0:00:00,0 anzeigen und dann jede Zehntelsekunde aktualisiert werden. Um eine Zehntelsekunde verstreichen zu lassen, rufen Sie die folgende Anweisung auf: Thread.sleep(100);. Die Uhr soll endlos laufen. Zum Stoppen des Programms verwenden Sie den roten Stopp‐ Button in Eclipse.

Code:
public class DigiUhr {

    public static void main(String[] args) {


        int std = 18;
        int min = 18;
        int sek = 18;
        int ms = 18;


        for (ms=1;ms <= 1000;++ms);

        System.out.println(std + ":" + min + ":" + sek + "," + ms);
        }

    }
 
Du kannst sowohl formatierte Strings als auch Ausgaben erhalten. Probier mal
Java:
// via String:
String s = String.format("%02d", 1); 
System.out.println(s);

// direkt über Ausgabe
System.out.printf("%02d\n", 5); // das \n sorgt für einen Zeilenumbruch wie bei println
 
Zerlegen wir das alles doch einmal:
a) Es soll endlos laufen - wie kannst Du etwas bauen, das endlos läuft?
b) alle 100ms sollen die ms um eine Zehntelsekunden erhöht werden (Wie man 100ms warten ist ja vorgegeben.)
c) Ausgabe kannst Du nun bauen - siehe dazu auch den Hinweis von mihe7, wobei die Concatenation auch gehen sollte.
==> Nun kannst Du Dir das Ergebnis ansehen. Was läuft denn nun noch falsch? Was musst Du ändern, damit es korrekt wird? (Das sollte dann gut ersichtlich sein denke ich mal)
 
Wobei man hier kein Modulo braucht. Ein if mit == reicht komplett aus, da wir ja die Schrittgröße kennen. Wenn wir die ms immer um 100 erhöhen, dann wissen wir, dass wir dann mal auf 1000 kommen und dann müssen wir was machen.
Sekunden erhöhen wir immer um eins und wenn wir auf 60 kommen, dann machen wir etwas .....
u.s.w.
 
Java:
import java.util.Calendar;
import java.util.GregorianCalendar;

public class Uhr extends Thread {
	long waitfor = 0;

	@Override
	public void run() {
		try {
			Calendar c = new GregorianCalendar();
			int std = c.get(Calendar.HOUR_OF_DAY);
			int min = c.get(Calendar.MINUTE);
			int sek = c.get(Calendar.SECOND);
			int zs = c.get(Calendar.MILLISECOND) / 100;
			System.out.printf("(%d Millisekunden gewartet)%n%d:%02d:%02d,%d%n", waitfor, std, min, sek, zs);
			waitfor = 100 - System.currentTimeMillis() % 100 + 1;
			Thread.sleep(waitfor);
			run();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		Uhr uhr = new Uhr();
		uhr.start();
	}
}


Aber aufpassen, der Spaß beendet sich nicht einfach so...
 
Wenn Du @zide_07 Calendar nicht verwenden darfst, wird es frickelig... Dann wird das eine ganz schöne Rechnerei und Überlaufsprüfungen...
 
Also ich habe jetzt wieder Probleme, zu verstehen, was Du hier machst @Tobias-nrw:
Die Vorgaben waren doch klar und deutlich und Dein Code hat mit den Vorgaben sehr wenig zu tun.
Es wird kein Calendar benötigt, Thread braucht man nur das sleep(100), das explizit erwähnt wurde ... Ausgabe soll bei 0:00:00,0 anfangen und ansonsten soll da auch nichts angezeigt werden.

Somit dürfte die erwartete Lösung doch eher das Folgende sein:
Java:
public class Uhr {

    public static void main(String[] args) throws InterruptedException {
        int std = 0;
        int min = 0;
        int sek = 0;
        int zs = 0;

        while (true) {
            System.out.printf("%d:%02d:%02d,%d\n", std, min, sek, zs);
            Thread.sleep(100);
            zs++;
            if (zs==10) {
                zs = 0;
                sek++;
                if (sek==60) {
                    sek=0;
                    min++;
                    if (min==60) {
                        min = 0;
                        std++;
                        if (std==24) {
                            std=0;
                        }
                    }
                }
            }
        }
    }
}

Weitere Optimierungen um da die Uhr genau zu halten oder dass die Uhr die korrekte Uhrzeit anzeigt oder sonst irgendwas ist in keiner Weise gefordert.
 
Diese ganzen ifs machen mich ganz wuschig. 🙂 Mit Hilfe von Java 9 VarHandles und Lambdas kann man das noch etwas abstrahieren. Naja... nur, dass man hierfür Instanzvariablen benötigt... aber egal:
Java:
import static java.lang.invoke.MethodHandles.lookup;
import java.lang.invoke.VarHandle;
public class Uhr {
  private static final VarHandle stdH = varHandleTo("std");
  private static final VarHandle minH = varHandleTo("min");
  private static final VarHandle sekH = varHandleTo("sek");
  private static final VarHandle zsH = varHandleTo("zs");
  private static VarHandle varHandleTo(String name) {
    try {
      return lookup().findVarHandle(Uhr.class, name, int.class);
    } catch (NoSuchFieldException | IllegalAccessException e) {
      throw new AssertionError(e);
    }
  }

  private int std;
  private int min;
  private int sek;
  private int zs;

  public void tick() {
    advance(zsH,  10, () -> 
    advance(sekH, 60, () -> 
    advance(minH, 60, () -> 
    advance(stdH, 24, null))));
  }

  private void advance(VarHandle var, int cmp, Runnable next) {
    if ((Integer) var.getAndAdd(this, 1) == cmp - 1) {
      var.set(this, 0);
      if (next != null)
        next.run();
    }
  }

  @Override
  public String toString() {
    return String.format("%d:%02d:%02d,%d", std, min, sek, zs);
  }

  public static void main(String[] args) throws InterruptedException {
    Uhr uhr = new Uhr();
    while (true) {
      System.out.println(uhr);
      Thread.sleep(100);
      uhr.tick();
    }
  }
}
Ja, ich weiß, dass das too much ist, aber mich hat mal interessiert, ob man das Inkrementieren, die Vergleiche und das Reset der einzelnen Zähler wegabstrahieren kann. 🙂
 
Nur leider gibt es (noch) keine Syntax dafür in der Sprache selbst (wie etwa der Adressoperator '&' in C bzw. Referenzoperator in C++), sondern nur API-Konstrukte wie eben ein VarHandle. Und man kann auch nur Referenzen auf Instanz- und Klassenvariablen haben, nicht auf lokale Methodenvariablen. Sonst wäre "Pass-by-Reference" endlich möglich. 🙂 Naja, zumindest ist jetzt schonmal Pass-by-Reference für Klassen- und Instanzvariablen möglich, wenn auch der Zugriff auf diese Referenz per API erfolgen muss.
Ich hab das Ding aber noch niemals wirklich in Produktivcode benutzt.
 
Red mir nicht mit so einem Bullshit dazwischen, was interessieren mich Deine Vorgaben, den kannst Du für Dich behalten... Wenn er eine genaue Uhr haben möchte, kommt er darum nicht herum.
Es sind nicht meine Vorgaben, es sind die Vorgaben des TE. Und der TE wollte eben nicht einfach eine Uhr haben. Wenn Du den Thread gelesen hättest, dann wüsstest Du das auch.

Und statt da meine Aussage als "Bullshit" zu bezeichnen solltest Du einfach einmal den Post vom TE lesen und verstehen.
So ist das, was Du schreibst, einfach nur "Bullshit".
 
Wieso nicht einfach ein OO Ansatz?

Das Verhalten einer Stelle ist ja trivial, so dass man da nicht weiter drauf eingehen muss (aktueller Stand, max Stand, erhöhen als Methode).
Und dann per Observer Pattern bekommt die nächste Stelle den Überlauf der vorherigen Stelle.
 
Wenns nur um die ifs geht:
Java:
public class Uhr {

    public static void main(String[] args) throws InterruptedException {
        int std = 0;
        int min = 0;
        int sek = 0;
        int zs = 0;
        int z = 0;

        while (true) {
            System.out.printf("%d:%02d:%02d,%d\n", std, min, sek, zs);
            Thread.sleep(100);
            z++;
            zs = z % 10;
            sek = (z/10) % 60;
            min = (z/600) % 60;
            std = (z/36000) % 24;
            if (std == 0) { z = 0; }
        }
    }
}
 
Ja, das ist auch ein interessanter Ansatz, aber bei der Implementation ist noch ein Fehler: die Abfrage std==0 kann so nicht gehen, denn in der ersten Stunde ist std immer 0, d.h. z wird immer wieder auf 0 gesetzt. Also ein if (std == 0 && z > 36000) würde das Problem lösen können.
 
Ich hatte mich vor ein paar Jahren auch mal an so einem Beispiel ausgetobt, es OOP zu machen. Ich habe Counter verkettet, um deren Überläufe zu übertragen.
Java:
public class Counter {
    private AtomicInteger count = new AtomicInteger(0);

    public int increment() {
        return count.incrementAndGet();
    }

    public int decrement() {
        return count.decrementAndGet();
    }

    public int set(int count) {
        return this.count.getAndSet(count);
    }

    public int getCount() {
        return count.get();
    }

    @Override
    public String toString() {
        return "" + getCount();
    }
}

public class ModCounter extends Counter {

    private int mod;

    public ModCounter(int mod) {
        this.mod = mod;
    }

    @Override
    public int increment() {
        set( super.increment() % mod);
        return 0;
    }

    @Override
    public int decrement() {
        return set( ( getCount() + mod - 1 ) % mod);
    }
}

public class LinkedModCounter extends ModCounter {
    private LinkedModCounter next;

    public LinkedModCounter(final int mod, final LinkedModCounter next) {
        super(mod);
        this.next = next;
    }

    @Override
    public int increment() {
        super.increment();
        if (0 == getCount() && null != next) {
            next.increment();
        }
        return 0;
    }
}

public class Clock {

    private final LinkedModCounter hours = new LinkedModCounter(24, null);
    private final LinkedModCounter minutes = new LinkedModCounter(60, hours);
    private final LinkedModCounter seconds = new LinkedModCounter(60, minutes);

    public int getSeconds() {
        return seconds.getCount();
    }

    public int getMinutes() {
        return minutes.getCount();
    }

    public int getHours() {
        return hours.getCount();
    }

    public void tick() {
        seconds.increment();
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("Clock{");
        sb.append("seconds=")
          .append(seconds);
        sb.append(", minutes=")
          .append(minutes);
        sb.append(", hours=")
          .append(hours);
        sb.append('}');
        return sb.toString();
    }
}

public class Main {

    private final Clock clock = new Clock();

    public static void main(String[] args) {
        new Main().run();
    }

    public void run() {
        new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    Thread.sleep(TimeUnit.SECONDS.toMillis(1));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                clock.tick();
                System.out.println(clock);
            }
        }).start();
    }
}
 
Ja genau, so in der Art meinte ich das.

Ich selbst habe einen direkten Vergleich statt Modulo, da diese Operation ja unnötig ist (Es wird ja immer nur um 1 erhöht). Dafür habe ich da noch ein format-String mit dazu genommen und die toString() Methode überschrieben.

Daher sah meine OO Lösung für dieses Uhr Thema wie folgt aus:

UhrElement
Java:
package uhr;

public class UhrElement {
    int value = 0;
    int maxValue;
    UhrElement next;
    String format;

    public UhrElement(int startValue, int maxValue, String format, UhrElement next) {
        this.maxValue = maxValue;
        this.next = next;
        this.format = format == null ? "%d" : format;
        this.value = startValue;
    }

    public void increase() {
        value++;
        if (value == maxValue) {
            value=0;
            if (next != null) next.increase();
        }
    }

    @Override
    public String toString() {
        return String.format(format, value);
    }
}

Uhr:
Java:
package uhr;

public class Uhr {
    public static final int START_VALUE = 0;
    public static final int MAX_STUNDEN = 24;
    public static final int MAX_MINUTEN = 60;
    public static final int MAX_SEKUNDEN = 60;
    public static final int MAX_ZEHNTEL_SEKUNDEN = 10;
    public static final String FORMAT_SINGLE = "%d";
    public static final String FORMAT_DOUBLE_LEADING_ZERO = "%02d";
    public static final String FORMAT_DOUBLE = "%2d";

    private UhrElement stunden = new UhrElement(START_VALUE, MAX_STUNDEN, FORMAT_DOUBLE, null);
    private UhrElement minuten = new UhrElement(START_VALUE, MAX_MINUTEN, FORMAT_DOUBLE_LEADING_ZERO, stunden);
    private UhrElement sekunden = new UhrElement(START_VALUE, MAX_SEKUNDEN, FORMAT_DOUBLE_LEADING_ZERO, minuten);
    private UhrElement zehntelSekunden = new UhrElement(START_VALUE, MAX_ZEHNTEL_SEKUNDEN, FORMAT_SINGLE, sekunden);

    @Override
    public String toString() { return String.format("%s:%s:%s,%s", stunden, minuten, sekunden, zehntelSekunden); }

    public void run() {
        try {
            while (true) {
                System.out.println(this);
                Thread.sleep(100);
                zehntelSekunden.increase();
            }
        } catch (InterruptedException e) {
            System.out.println("Thread.sleep interrupted!");
            e.printStackTrace();
        }
    }

    public static void main (String[] args) {
        Uhr uhr = new Uhr();
        uhr.run();
    }
}
 
b) Abhängigkeit von Java 9
Das kann man fixen:
Java:
import java.util.function.Supplier;
public class Uhr {
  private int std;
  private int min;
  private int sek;
  private int zs;
  public void tick() {
    advance(() -> ++zs,  10, () -> zs  = 0, () -> 
    advance(() -> ++sek, 60, () -> sek = 0, () -> 
    advance(() -> ++min, 60, () -> min = 0, () -> 
    advance(() -> ++std, 24, () -> std = 0, null))));
  }
  private void advance(Supplier<Integer> incr, int cmp, Runnable rst, Runnable next) {
    if (incr.get() == cmp) {
      rst.run();
      if (next != null)
        next.run();
    }
  }
  @Override
  public String toString() {
    return String.format("%d:%02d:%02d,%d", std, min, sek, zs);
  }
  public static void main(String[] args) throws InterruptedException {
    Uhr uhr = new Uhr();
    while (true) {
      System.out.println(uhr);
      Thread.sleep(100);
      uhr.tick();
    }
  }
}
Jetzt ist das Problem: Abhängig von Java 8. 🙂
 

Zurück
Oben