Skip to content

Code Review#23

Open
Soamid wants to merge 63 commits intoreviewfrom
main
Open

Code Review#23
Soamid wants to merge 63 commits intoreviewfrom
main

Conversation

@Soamid
Copy link
Collaborator

@Soamid Soamid commented Jan 9, 2023

No description provided.

smelaa and others added 30 commits December 8, 2022 08:40
SimultaionEngine commit
classes added + Vector2d&Direction implemented
classes & basic methods added
LittleAdjustment and TotalRandom implementation
class Animal implementation
IHolyGardener variants implementation
FileMenager, Statistics, Map
last parts of gui planned
Copy link
Collaborator Author

@Soamid Soamid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Funkcje:

1 / 1 wiele symulacji - da się odpalić kilka różnych.
2 / 2 warianty - wszystko jest!
1 / 1 konfiguracja + zapis wyników - jest!
2 / 2 wyświetlanie symulacji (kolorki, pauza, podglądanie) - wygląda ładnie, bardzo estetyczny róż i bardzo puchate futerka. Końce świata trochę depresyjne, ale co poradzić, taki mamy, ekhm, klimat.
1 / 1 statystyki - jest wszystko a nawet więcej niż się spodziewałem. :)

Kod:

4 / 4 Architektura
Jestem pod wrażeniem, pomimo tylu różnych pułapek udało Wam się to naprawdę dobrze poukładać. Czepiałbym się w kilku miejscach zasady SRP, ale to raczej niewielkie uwagi na tle całości i tego jak np. rozegrałyście wszystkie strategie, a nawet wprowadziłyście FXML, o którym nie mówiliśmy.
No i zarządzanie parametrami przypomina ręczną wersję profesjonalnego wstrzykiwania zależności, no jak złoto. Miałem odjąć za to SRP, ale wyszłyście znacznie ponad program więc nie odejmuję nic. ;)

1.7 / 2 Czystość kodu
Tu też bardzo ok, choć muszę się czepić jednego powtarzającego się problemu: hermetyzacja, a właściwie jej naruszanie. W Javie atrybuty są "niskopoziomowe" w przeciwieństwie do propertiesów w C# czy Kotlinie albo Scali. Musimy więc oznaczać go jako prywatne i ewentualnie dorabiać do nich gettery/settery w razie gdy są potrzebne.
Poza tym niektóre metody można by podzielić na mniejsze, a tak to spoko.

1 / 1 Obsługa błędów - jest i to całkiem realna, nawet w GUI się pokazują komunikaty. :) Jedynie uwaga do wyjąków unchecked (patrz komentarze w kodzie).

Łącznie: 13.7 + 1.8 za intro = 15.5 za projekt.

Jak na razie to rzeczywiście najpiękniejszy generator ewolucyjny, jaki widziała ludzkość, brawo. ;)
Podesłałbym jako nagrodę najlepszą piosenkę na świecie, ale po tylu godzinach sprawdzania nie pamiętam już, która jest najlepsza więc podeślę tylko: https://www.youtube.com/watch?v=_lK4cX5xGiQ

private Map map;

//konstruktor dla Adama i Ewy
public Animal(SimulationVar var,Map map) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

konstruktory warto byłoby zwinąć tak by przypisania były robione tylko w jednym (prawdopodobnie trzeba by tu wprowadzić trzeci).

private Map map;

//konstruktor dla Adama i Ewy
public Animal(SimulationVar var,Map map) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var to bardzo niebezpieczna nazwa dla zmiennej, bo w Javie jest takie słowo kluczowe :P

position=mommy.getPosition();
genes= new Direction[var.getGenomeLength()];
activeGeneIx=generator.nextInt(var.getGenomeLength());
int energy1 = mommy.energy / 2;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, przy czym wyrzuciłbym logikę rozmnażania do osobnej metody, bo konstruktory z definicji są bezimienne i trzeba się domyślać co tu się dzieje właściwie.

try {
createGenome(mommy, daddy, fromMommy);
}
catch (IllegalArgumentException exception){
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

czy na pewno chcemy to tu łapać? w takiej sytuacji dziecko z niepoprawnie stworzonym genomem będzie dalej funkcjonować w aplikacji i przejdziemy do procedury mutacji :P

if (genesToString().equals(map.getTheMostPopularGenome())){
circle.setStroke(Color.valueOf("#fff705"));
}
circle.setOnMousePressed(new EventHandler<MouseEvent>() {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tu mamy wmieszany kod UI w model, tego unikajcie za wszelką cenę (to najgorszy przypadek złamania zasady jednej odpowiedzialności i zasady otwarte-zamknięte). Można by tu po prostu zwracać np. ścieżkę do obrazka albo stringa opisującego kolor, ale nie kontrolki FX.

map.removeAnimal(animal);
}

//poruszamy wszystkie zwierzątka
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tu ponownie fajnie byłoby wydzielić metody-etapy symulacji, np. moveAnimals(), dinnerTime(), weAllGonnaDie() itp. ;)

}
possibleMatch.sort(Comparator.<Animal>comparingInt(el -> -el.energy).thenComparingInt(el -> -el.age).thenComparingInt(el -> -el.children));
lastIndex = howManyOnThisSpot;
Animal winner = possibleMatch.get(0); //wygrał trawkę
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mechanizm porównania i wybierania silnych zwierzątek wydzieliłbym w ogóle na zewnątrz, nawet do jakiejś klasy helpera, strasznie tu śmieci

public void run() {

while(map.getStats().getAmountOfAnimals()>0 && !interrupted){
Platform.runLater(()->{dayRitual();});
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to oznacza, że cały dayRitual() wykona się w wątku UI zamiast w wątku symulacji! Co czyni w sumie wątek symulacji bezużytecznym i zrzuca ciężar obliczeń na GUI.

private final int grassSpawnedEveryday;
private final int refreshTime;
private final int genomeLength;
//bardzo brzydkie, aż nam wstyd:(
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, ale można to łatwo naprostować:

  1. Bazowanie na numerkach to zło, chciałem żeby ten config był w formacie "klucz=wartość", bo wtedy od razu widać w pliku co można ustawiać, ale też w kodzie łatwiej się to ogarnia. Można od razu wczytać do mapy wszystkie parametry, a potem...
  2. Dla każdego parametru stworzyć metodę providera, która zwraca odpowiedni obiekt strategii w przypadku tych złożonych parametrów typu rozdzaj mapy itp.
  3. Wydzielić wszystkie klucze do stałych static final
  4. Opcjonalnie można też rozdzielić wczytywanie i samo przechowywanie parametrów w dwóch osobnych klasach (z czego przechowywanie można by załatwić rekordem a nie klasą).

for (Vector2d position: positionsIterator){
if(!map.isGrassThere(position)){positions.add(position);}
}
positions.sort(new Comparator<Vector2d>() {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, ale można krócej lambdą

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants