Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Ich dachte schon. Ich meine er hat auch irgendwo davon gesprochen als Werkstudent nebenbei wo in der Software Entwicklung zu beginnen. Tut mir leid, falls ich das falsch in Erinnerung habe.
Prinzipiell hast du recht und es sollte uns egal sein, durch diesen Thread ist es mir das aber nicht. Wenn ich mir vorstelle, dass er mein Kollege ist kommt mir das Grauen.
Ach du scheisse ... jetzt bekomme ich Alpträume: Ich werde jetzt bestimmt träumen, dass mein Chef zu mir kommt um mir den neuen Werkstudenten vorzustellen....
Also kann gut sein, dass ich da etwas verpasst habe ... aber die Leistungen hier würden dazu nicht wirklich passen....
Ich dachte schon. Ich meine er hat auch irgendwo davon gesprochen als Werkstudent nebenbei wo in der Software Entwicklung zu beginnen. Tut mir leid, falls ich das falsch in Erinnerung habe.
Prinzipiell hast du recht und es sollte uns egal sein, durch diesen Thread ist es mir das aber nicht. Wenn ich mir vorstelle, dass er mein Kollege ist kommt mir das Grauen.
Ich bin hier nur zur Unterhaltung. Ihre Energie verschwenden hier nur die Leute die dir helfen wollen, da du einfach nichts von den Ratschlägen umsetzen kannst/willst.
Ich bin hier nur zur Unterhaltung. Ihre Energie verschwenden hier nur die Leute die dir helfen wollen, da du einfach nichts von den Ratschlägen umsetzen kannst/willst.
Ich habe es ja bereits erwähnt: Antworten wie z.B.: "Try catch" auf die ausführliche Antwort von @kneitzel sind eine Frechheit gegenüber jenen, die dir hier ihre Hilfe anbieten. Dies ist ja nicht das erste Mal, sondern zieht sich konsequent durch den Thread: Dir gibt jemand eine gute Hilfestellung, deine Antwort ist ein simples "i". Was soll sowas? Das ist einfach an Dreistigkeit nicht zu überbieten. Wenn du genauso kommunizierst wird dich keine Firma je länger als die Probezeit behalten.
Ich habe es ja bereits erwähnt: Antworten wie z.B.: "Try catch" auf die ausführliche Antwort von @kneitzel sind eine Frechheit gegenüber jenen, die dir hier ihre Hilfe anbieten. Dies ist ja nicht das erste Mal, sondern zieht sich konsequent durch den Thread: Dir gibt jemand eine gute Hilfestellung, deine Antwort ist ein simples "i". Was soll sowas? Das ist einfach an Dreistigkeit nicht zu überbieten. Wenn du genauso kommunizierst wird dich keine Firma je länger als die Probezeit behalten.
Solche Antworten sind respektloser. Keiner ist dir böse wenn du nicht sofort antwortest, deine Antwort sollte aber auf das Vorherige eingehen, zeigen, dass du dich damit beschäftigt hast, eine konkrete Frage zu dem stellen was du nicht verstehst oder etwas sein wie "Danke, das hat mir geholfen. Es funktioniert jetzt, das ist der neue Code: //Code einfügen"
Sinnlose Antworten spare dir bitte.
Solche Antworten sind respektloser. Keiner ist dir böse wenn du nicht sofort antwortest, deine Antwort sollte aber auf das Vorherige eingehen, zeigen, dass du dich damit beschäftigt hast, eine konkrete Frage zu dem stellen was du nicht verstehst oder etwas sein wie "Danke, das hat mir geholfen. Es funktioniert jetzt, das ist der neue Code: //Code einfügen"
Sinnlose Antworten spare dir bitte.
dann hast du meinen Standpunkt gehört dann hoffe ich dass wir auf einen Nenner kommen werden.
Es war nicht meine Absicht
Ich werde sem
Kollegen schreiben direkt wenn ich daran sitze.
Aber nicht wegen der Aufgabe aondern wie man Debuggen.
Außerdem sollte alles hier nicht persönlich genommen werden!
Wenn ich respektlos wäre hätte ich längst beleidigt....
Ich habe weiter oben ganz konkret eine Codezeile zitiert, in der ein Fehler auftritt. Du musst diese Zeile umschreiben, auch das wurde hier schon sehr oft erwähnt. Nur so kannst du genau feststellen, wo der Fehler liegt.
Übrigens muss das Debuggen nicht extra gelehrt werden, da jeder, der schon mal programmiert hat, weiß, dass die Fehlersuche eine wichtige Arbeit dabei ist. Das Debuggen usw. lernt man mit dem Programmieren parallel.
Hmm ... noch keine 500 Posts und schon Ende? Das ist jetzt aber sehr enttäuschend. Aber das Thema ist damit wohl für den TE erledigt und es ist Zeit, ein paar Dinge bezüglich Clean Code zu bringen.
Also paar Dinge sind tabu in Clean Code. Ein wichtiger Punkt ist etwas, das oft als "Magic Numbers" bezeichnet wird (Etwas irritierend, denn es betrifft nicht nur Zahlen):
Direkt im Code-Verlauf darf es keine Konstanten geben. Konstanten müssen immer in entsprechenden Konstrukten definiert werden.
Hier gibt es dann mehrere Arten von Lösungen:
a) Verwendung von Konstanten. Also statt ein Byte Array mit Größe 1024 zu definieren, definiert man an eine Konstante BUFFER_SIZE oder so und erstellt dann ein Byte Array it der Größe BUFFER_SIZE. Das hat den Vorteil, dass der Code lesbar ist. Und ein Refactoring ist einfacher, denn mal angenommen, das soll von 1024 auf 4096 erhöht werden. Nun muss man nach allen 1024 suchen, entscheiden, ob das eine Stelle ist, die geändert werden muss um dann ggf. die Stelle zu ändern oder nicht... Mit Konstanten ändert man dann einfach die Konstante an einer Stelle.
b) Oft gibt es Konstanten, die zusammen gehören. Ein Beispiel dafür ist z.B. die Liste der Befehle, die möglich sind. ('f','b','l' und 'r') oder aber auch die Feldinhalte die möglich sind ('#', 'v', '<', ....)
Hier kann man dann eine Enum verwenden. Der große Vorteil dabei ist dann auch, dass man damit teilweise switch Statements / if ketten und so vermeiden kann. Hintergrund ist dabei, dass man Enum Werten auch weitere Werte geben kann. Also bei den Beispielen bedeutet das, dass man jedem Befehl (FORWARD, LEFT, RIGHT, ...) auch die Befehl-Zeichen mitgeben kann ('f', 'l', 'r', ...) Und dann kann man z.B. zu einem Befehl einfach das Befehlszeichen bekommen oder eben in einer kleinen Schleife vom Befehlszeichen zu dem Befehl kommen...
c) Der letzte wichtige Part sind Ausgaben. Diese gehören auch nicht in den Code. Statt dessen sollten Ausgaben immer aus einer Ressource Datei kommen. Dies hat den großen Vorteil, dass die Ausgabe schnell angepasst werden kann. So können die Ressource-Dateien z.B. an einen Übersetzer gehen, der von Software Entwicklung keine Ahnung haben muss. Und Übersetzungen sollten sich ohne komplette Neuübersetzung einpflegen lassen.
Speziell zu b) sähe der Code für Befehle und FeldInhalte dann z.B. so aus:
Java:
package rover;
/**
* Commands the rover understands
*/
public enum Command {
/**
* Move rover forward.
*/
FORWARD('f'),
/**
* Move rover backwards.
*/
BACKWARD('b'),
/**
* Turn rover right.
*/
TURN_RIGHT('r'),
/**
* Turn rover left.
*/
TURN_LEFT('l');
/**
* Command character used when submitting a command.
*/
private char commandChar;
/**
* Create a new instance of Command.
* @param commandChar Character to use to transfer the command.
*/
Command(char commandChar) {
this.commandChar = commandChar;
}
/**
* Gets the command character ot the command.
* @return Character used to transfer command.
*/
public char getCommandChar() { return commandChar; }
/**
* Get a Command instance from a command character.
* @param commandChar Command character
* @return Command instance.
* @throws IllegalArgumentException if character is not a valid command chaarcter.
*/
public static Command fromChar(char commandChar) {
for (Command command: Command.values()) {
if (command.getCommandChar() == commandChar) return command;
}
throw new IllegalArgumentException("commandChar");
}
}
Und das kann dann auch entsprechend genutzt werden. Also um Befehle aus den Zeichen zu bekommen, könnte man in der main Methode folgenden Code verwenden:
Dann sollte eine Aufgabe in Java Objektorientiert aufgebaut werden. Und bei der Aufgabe sieht man direkt mehrere Dinge.
Zum einen die Position, welche einfach über ein int Array abgebildet wurde. Also ideal, um es als Klasse abzubilden:
Java:
package rover;
/**
* Position inside the map
*/
public class Position {
private int x;
private int y;
public Position (int x, int y) {
this.x = x;
this.y = y;
}
public boolean validate(int maxX, int maxY) {
return (maxX > x) && (maxY > y) && (x>=0) && (y>=0);
}
public int getX() { return x; }
public int getY() { return y; }
@Override
public int hashCode() {
return x + (y<<16);
}
@Override
public boolean equals(Object obj) {
// Check if same reference
if (obj == this) return true;
if (obj instanceof Position) {
Position other = (Position) obj;
return
other.x == x &&
other.y == y;
}
return false;
}
}
Das die Position auch als Key verwendet werden soll, ist natürlich klar, dass ein equals (und damit natürlich auch der hashCode) überschrieben werden muss. Ein Verändern eines Keys ist aber kritisch, so auch der Hashcode verwendet wird, daher wurden Setter explizit weggelassen. (Das Thema hatte ich ja schon vorab angesprochen....)
Und dann hat man natürlich eine Karte. Die kann man dann auch mit entsprechenden Funktionen implementieren. Hier kann man überlegen, ob man generics verwenden möchte, aber dann läuft es schnell auf eine schon vorhandene Klasse heraus. Somit kann man überlegen, ob diese Klasse notwendig ist. Aber ohne Generics ist das eine recht schöne Kapselung:
Java:
package rover;
import java.util.LinkedHashMap;
/**
* ItemMap for rover solution
*/
public class ItemMap {
private int height;
private int width;
private LinkedHashMap<Position, FieldContent> map;
public ItemMap(int width, int height) {
map = new LinkedHashMap<>();
this.height = height;
this.width = width;
}
public FieldContent get(Position position) {
// Get result.
FieldContent result = map.get(position);
// return EMPTY when field is empty.
if (result == null) return FieldContent.EMPTY;
// return result
return result;
}
public void put(Position position, FieldContent content) {
// Validate
if (!position.validate(width, height)) throw new IllegalArgumentException("position");
map.put(position, content);
}
public FieldContent remove(Position position) {
// Validate
if (!position.validate(width, height)) throw new IllegalArgumentException("position");
return map.remove(position);
}
public void move(Position oldPosition, Position newPosition) {
// Validate
if (!oldPosition.validate(width, height)) throw new IllegalArgumentException("oldPosition");
if (!newPosition.validate(width, height)) throw new IllegalArgumentException("newPosition");
FieldContent content = remove(oldPosition);
if (content != null)
put(newPosition, content);
}
public boolean isBlocked(Position position) {
return get(position) != FieldContent.EMPTY;
}
}
Dabei ist ein Punkt wichtig, ob den man in der Aufgabe auch mehrfach gestolpert ist: Rückgabe von NULL Werten! Das ist etwas, das leicht Probleme mit sich bringt. Es gibt hier ein paar Ansätze bei Java mit Annotations zu arbeiten (@null, @NotNull), aber andere Sprachen gehen hier noch deutlich weiter (z.B. Kotlin). Aber man kann hier sauber bleiben und z.B. bei get auf eine Rückgabe von null verzichten und da dann statt dessen ein EMPTY zurück geben.
Und dann hat man schon eine Grundlage für leserlichen Code, den man direkt nutzen kann. Die Funktionen könnten dann z.B. in der Form aufgebaut sein:
Java:
/**
* Initialization of map.
*/
public static void newInit() {
map = new ItemMap(mapWidth, mapHeight);
roverPosition = new Position(
mapWidth / 2,
mapHeight / 2);
for (int x = 0; x < mapWidth; x++) {
for (int y = 0; y < mapHeight; y++) {
Position p = new Position(x, y);
if (r.nextDouble() < 0.25 &&
!(roverPosition.getX() == x && roverPosition.getY() == y))
map.put(p, FieldContent.BLOCKED);
}
}
map.put(roverPosition, FieldContent.ROVER_NORTH);
}
/**
* Turn right from a given direction.
* @param direction Current direction as FieldContent
* @return New direction as FieldContent
*/
public static FieldContent turnRight(FieldContent direction) {
switch (direction) {
case ROVER_NORTH:
return FieldContent.ROVER_EAST;
case ROVER_EAST:
return FieldContent.ROVER_SOUTH;
case ROVER_SOUTH:
return FieldContent.ROVER_WEST;
case ROVER_WEST:
return FieldContent.ROVER_NORTH;
default:
throw new IllegalArgumentException("direction");
}
}
/**
* Turn left from a given direction.
* @param direction Current direction as FieldContent
* @return New direction as FieldContent
*/
public static FieldContent turnLeft(FieldContent direction) {
switch (direction) {
case ROVER_NORTH:
return FieldContent.ROVER_WEST;
case ROVER_EAST:
return FieldContent.ROVER_NORTH;
case ROVER_SOUTH:
return FieldContent.ROVER_EAST;
case ROVER_WEST:
return FieldContent.ROVER_SOUTH;
default:
throw new IllegalArgumentException("direction");
}
}
/**
* Moves an object that is at the given position. Must be a rover at the location.
*
* Checks that the map is not left and does not move on not empty fields.
* @param position Position to check.
* @param forward Should the rover move forward (true) or backwards (false)
* @return New Position or ld position if new position was invalid (blocked, outside map)
*/
public static Position move(Position position, boolean forward) {
// Get new position when moving.
Position newPosition = getNewPosition(position, forward);
// Validate new position
if (!newPosition.validate(mapWidth, mapHeight)) return position;
// Check if new position is blocked
if (map.isBlocked(newPosition)) return position;
// Do move
map.move(position, newPosition);
// Return new position
return newPosition;
}
/**
* Gets a new position when moving into a direction.
* @param position Current position
* @param forward Moving forward or backwards
* @return new Position.
*/
private static Position getNewPosition(Position position, boolean forward) {
FieldContent direction = map.get(position);
switch (direction) {
case ROVER_NORTH:
return new Position(
position.getX(),
forward ? position.getY() - 1 : position.getY() + 1);
case ROVER_EAST:
return new Position(
forward ? position.getX() + 1 : position.getX() - 1,
position.getY());
case ROVER_SOUTH:
return new Position(
position.getX(),
forward ? position.getY() + 1 : position.getY() - 1);
case ROVER_WEST:
return new Position(
forward ? position.getX() - 1 : position.getX() + 1,
position.getY());
default:
throw new IllegalArgumentException("direction");
}
}
/**
* Handles a given command.
* @param command to handle.
*/
public static void handleCommand(Command command) {
FieldContent roverDirection = map.get(roverPosition);
switch (command) {
case FORWARD:
roverPosition = move(roverPosition, true);
break;
case BACKWARD:
roverPosition = move(roverPosition, false);
break;
case TURN_LEFT:
roverDirection = turnLeft(roverDirection);
map.put(roverPosition, roverDirection);
break;
case TURN_RIGHT:
roverDirection = turnRight(roverDirection);
map.put(roverPosition, roverDirection);
break;
default:
System.out.println("Unknown command: " + command);
}
}
/**
* Print out the map.
*/
public static void printMap() {
for (int y = 0; y < mapHeight; y++) {
for (int x = 0; x < mapWidth; x++) {
FieldContent content = map.get(new Position(x, y));
System.out.print(content.getPrintChar());
}
System.out.println();
}
for (int x = 0; x < mapWidth; x++) {
System.out.print("=");
}
System.out.println();
}
Generell sollte man alle Funktionen und so dokumentieren. JavaDoc ist da die Lösung, die in erster Linie verwendet wird.
Bei dem letzten Code sieht man das relativ gut. Bei den vorherigen Code-Postings sind diese auch noch weggelassen.
Und natürlich sollten so Funktionen nicht statisch sein. Statt dessen sollte es auch noch eine Klasse geben, von der dann eine Instanz erstellt wird. Aus der init Funktion wird dann ein Konstruktor und so ....
Und noch eine Anmerkung: In meinem Code hatte ich den alten Code parallel in der Klasse behalten. Daher so Namen wie "newInit". Das ist natürlich auch schlecht. Code, den man nicht braucht, löscht man. Eine Source Verwaltung wie git sorgt dafür, dass man an den alten Stand auch wieder ran kommen kann. Und dann sind die Namen natürlich auch sauber und es gibt nur ein "init" oder so.
@kneitzel ich habe mir jetzt nicht alles im Detail durchgelesen (bin mir aber sicher, dass das passt) und wollte mal meine Anerkennung für die ganze Arbeit zum Ausdruck bringen. Das kann man einfach nicht unkommentiert stehen lassen.
Bleibt noch eine Frage: was machen wir jetzt mit den verbleibenden 37 Kommentaren?
@kneitzel ich habe mir jetzt nicht alles im Detail durchgelesen (bin mir aber sicher, dass das passt) und wollte mal meine Anerkennung für die ganze Arbeit zum Ausdruck bringen. Das kann man einfach nicht unkommentiert stehen lassen.
Bleibt noch eine Frage: was machen wir jetzt mit den verbleibenden 37 Kommentaren?
Also wir könnten den Thread für ein neues Thema entführen ...
Also mein Vorschlag für ein Thema wäre:
Da ein unter 18 Jähriger bestimmt nicht die Geduld hat, den Thread bis hier hin zu lesen, haben wir einen effektiven Jugendschutz.
So in den nächsten paar Antworten alle zustimmen, haben wir evtl. noch Platz für paar nicht Jugendfreie Witze?
Ich habe da jetzt vor kurzem erst einen Witz gehört bezüglich Punktrechnung vor Strichrechnung
Also wir könnten den Thread für ein neues Thema entführen ...
Also mein Vorschlag für ein Thema wäre:
Da ein unter 18 Jähriger bestimmt nicht die Geduld hat, den Thread bis hier hin zu lesen, haben wir einen effektiven Jugendschutz.
So in den nächsten paar Antworten alle zustimmen, haben wir evtl. noch Platz für paar nicht Jugendfreie Witze?
Ich habe da jetzt vor kurzem erst einen Witz gehört bezüglich Punktrechnung vor Strichrechnung
Du bekommst ein Bußgeld wegen zu schnellem Fahren .... 3 Punkte und 250€.
Und vom letzten Besuch eines Freudenhauses kommt auch noch eine Rechnung mit der Post: ebenfalls 250€!
kann mir einer helfen ahahahich, ich weiß nicht wie ich die if bedinung machen soll also ich muss wissen was frößer ist aber bei generischen klassen ist das bischen komplizierter.
Java:
public void sorting(){
ListNode current = head;
ListNode currentvor = current.next;
for(int i= 1; i < size(); i++){
for(int j = 0; i < size(); i++){
if(current.value.compareTo(currentvor.value) < 0){
}
}
}
}
das buggt auch nicht merh aber leider fehlt mir den programmier ansatz wie ich die beiden listnodes vergleichen kann mit der compare methode.
kann mir einer helfen ahahahich, ich weiß nicht wie ich die if bedinung machen soll also ich muss wissen was frößer ist aber bei generischen klassen ist das bischen komplizierter.
Java:
public void sorting(){
ListNode current = head;
ListNode currentvor = current.next;
for(int i= 1; i < size(); i++){
for(int j = 0; i < size(); i++){
if(current.value.compareTo(currentvor.value) < 0){
}
}
}
}
das buggt auch nicht merh aber leider fehlt mir den programmier ansatz wie ich die beiden listnodes vergleichen kann mit der compare methode.
Hmm, den Witz habe ich jetzt nicht verstanden. Aber evtl. kannst Du den Witz ja für mich kurz erläutern.
Ansonsten hast Du ja einen Thread, in dem das Thema behandelt wird. Und da hattest Du ja auch schon eine erste Erwiederung bekommen.... Und nein, auch mit Generics wird das nicht wirklich komplizierter.
Ja, wo Du Recht hast, hast Du durchaus Recht. Peinlich wird es dadurch, dass ich es am Computer geschrieben habe und der eine automatische Rechtschreibkontrolle drin hat. Da ist das Wort sogar rot unterstrichen....
Natürliche Zahlen ist halt auch nicht eindeutig! Gehört da die 0 mit dazu, oder eben nicht?
Es gibt hier zwei Definitionen, einmal mit 0 und einmal ohne. Früher war es immer ohne 0, da war es also eindeutig. Ein Hr. Fermat oder Hr. Euler wird damit also keine Schmerzen gehabt haben. Aber gerade wir Informatiker haben es ja mit dem Herrn Neumann ... und dann gehört die Null auf jeden Fall mit dazu.....
Es gibt hier zwei Definitionen, einmal mit 0 und einmal ohne. Früher war es immer ohne 0, da war es also eindeutig. Ein Hr. Fermat oder Hr. Euler wird damit also keine Schmerzen gehabt haben. Aber gerade wir Informatiker haben es ja mit dem Herrn Neumann ... und dann gehört die Null auf jeden Fall mit dazu.....
Ich will euch ja nicht den Spaß verderben, aber es is nicht abhängig von Mathe- oder Informatik-Vorlesungen, sondern von der Präferenz des Dozierenden, ob und wenn ja wie 0 dabei ist.
Ich will euch ja nicht den Spaß verderben, aber es is nicht abhängig von Mathe- oder Informatik-Vorlesungen, sondern von der Präferenz des Dozierenden, ob und wenn ja wie 0 dabei ist.