Celem laboratorium jest wykorzystanie modelu obiektowego do rozwiązania prostego zadania. Wykorzystamy wcześniej zaimplementowane klasy, dzięki czemu unikniemy powtórzeń i sprawimy, że rozwiązanie będzie czytelne. Wprowadzimy także nowe struktury danych - kolekcje obiektów.
Najważniejsze zadania:
- Stworzenie klasy
Animal
. - Stworzenie klasy
Simulation
, która pozwoli poruszać zwierzętami. - Zapoznanie się z kolekcjami w Javie, na przykładzie list.
- Testy integracyjne.
-
Wykorzystaj definicje klas
Vector2d
,MapDirection
orazMoveDirection
z laboratorium 2. -
W pakiecie
agh.ics.oop.model
utwórz klasęAnimal
, która:- posiada atrybut określający obecną orientację zwierzęcia (początkowo zawsze ustawioną na
NORTH
), - posiada atrybut określający położenie zwierzęcia na mapie,
- posiada dwa konstruktory:
- domyślny, który ustawia pozycję na
Vector2d(2,2)
i orientację naNORTH
(przyjmij, że zwierzę znajduje się w pierwszej ćwiartce układu współrzędnych, a północ jest tożsama z kierunkiem wyznaczanym przez rosnące wartości na osi OY) - przyjmujący i ustawiający pozycję podawaną z zewnątrz. Orientacja początkowa powinna być ustawiona na
NORTH
.
- domyślny, który ustawia pozycję na
- definiuje metodę
toString()
, która w reprezentacji łańcuchowej zawiera informacje o położeniu zwierzęcia (pozycję oraz orientację), - definiuje metodę
boolean isAt(Vector2d position)
, która zwraca prawdę, jeśli zwierzę znajduje się na pozycjiposition
.
- posiada atrybut określający obecną orientację zwierzęcia (początkowo zawsze ustawioną na
-
Zmodyfikuj klasę
World
, która w metodziemain
stworzy zwierzę i wyświetli w konsoli jego pozycję. -
Dodaj do klasy
Animal
metodęmove(MoveDirection direction)
, która:- Dla kierunków
RIGHT
iLEFT
zmienia orientację zwierzęcia na mapie, np. kiedy zwierzę ma orientacjęNORTH
, a zmiana kierunku toRIGHT
, to orientacja zwierzęcia powinna wynosićEAST
. - Dla kierunków
FORWARD
iBACKWARD
zmienia pozycję zwierzęcia o 1 pole, uwzględniając jego orientację, np. kiedy zwierzę jest na pozycji(2,2)
i jego orientacja toNORTH
, to po ruchuFORWARD
jego pozycja to(2,3)
. - Uniemożliwia wyjechanie poza mapę, która ustalona jest od pozycji
(0,0)
do pozycji(4,4)
(pięć na pięć pól). W sytuacji, w której zwierzę miałoby wyjść poza mapę, wywołaniemove
nie ma żadnego skutku.
- Dla kierunków
- Zmodyfikuj klasę
OptionsParser
w taki sposób, by zamiast tablicyMoveDirection[]
zwracała kolekcjęList<MoveDirection>
. Zastanów się, w jaki sposób dokonać tutaj zmian by maksymalnie uprościć kod i nie zmieniać zachowania metody (niepoprawne opcje nadal powinny być pomijane!). - Zmodyfikuj miejsca w kodzie oraz testy, które korzystały z
OptionsParser
tak, by program się kompilował. Upewnij się, że testy nadal przechodzą.
-
W pakiecie
agh.ics.oop
stwórz klasęSimulation
. -
Klasa powinna przyjmować w konstruktorze listę pozycji początkowych zwierząt (
List<Vector2d>
) oraz listę ruchów (List<MoveDirection>
). Na podstawie pozycji początkowych stwórz listę zwierząt, które będzie przechowywać obiekt symulacji. -
W klasie
Simulation
zdefiniuj również metodęrun()
, która na przemian steruje ruchem wszystkich zwierząt. Przykładowo, jeśli użytkownik wprowadzi ciąg:f b r l
, a na mapie są dwa zwierzęta, to pierwsze zwierzę otrzyma ruchyf
ir
, a drugieb
il
. Ruchy obu zwierząt mają być wykonywane na przemian, tzn. po każdym ruchu pierwszego zwierzęcia następuje ruch drugiego zwierzęcia. -
Zapewnij by po każdym ruchu program wypisywał informację
Zwierzę i : (x ,y)
, gdziei
- numer zwierzęcia na liście,x
,y
- pozycja zwierzęcia po ruchu (skorzystaj z przygotowanego wcześniejtoString()
). -
W celu weryfikacji rozwiązania wykonaj następujący kod w metodzie
main
klasyWorld
:java List<MoveDirection> directions = OptionsParser.parse(args); List<Vector2d> positions = List.of(new Vector2d(2,2), new Vector2d(3,4)); Simulation simulation = new Simulation(positions, directions); simulation.run();
Sprawdź, czy zwierzęta poruszają się poprawnie dla ciągu:
f b r l f f r r f f f f f f f f
. -
Napisz testy integracyjne weryfikujące poprawność implementacji. Uwzględnij:
- czy zwierzę ma właściwą orientację,
- czy zwierzę przemieszcza się na właściwe pozycje,
- czy zwierzę nie wychodzi poza mapę,
- czy dane wejściowe podane jako tablica łańcuchów znaków są poprawnie interpretowane.
-
Po realizacji zadania zastanów się, której implementacji listy w Javie najlepiej użyć w przypadkach opisanych w naszych zadaniach. W razie potrzeby podmień implementację na inną i uzasadnij odpowiedź (w formie komentarza w kodzie lub komentarza w PR).
-
Początkowe wartości obiektu można określić albo w konstruktorze, albo bezpośrednio przypisując je do pól, np.
class Animal { private Vector2d position = new Vector2d(2,2); }
-
W Javie istnieją dwie podstawowe struktury sekwencyjne (poza tablicami): LinkedList oraz ArrayList. W przeciwieństwie do tablic, obie klasy pozwalają na określenie początkowego rozmiaru na 0 i dowolne rozszerzanie kolekcji.
-
Obie klasy implementują interfejs
List
, który definiuje podstawowe operacje na listach. -
Klasy te różnią się implementację -
LinkedList
oparta jest o listę dwukierunkową, przez co operacje dodawania i usuwania elementów są szybkie, ale swobodny dostęp za pomocą operatoraget
jest wolniejszy.ArrayList
oparta jest o tablicę, dlatego dostęp jest szybki, ale dodawanie i usuwanie elementów jest wolniejsze. -
W Javie występują typy parametryzowane i typ
List
jest tego przykładem. Taki typ jest podobny do szablonów w C++. Wymaga on podania innego typu (lub typów) jako parametru (parametr musi być typem obiektowym):List<Animal> animals = new ArrayList<>();
W tym przykładzie tworzona jest lista zwierząt, a jako implementacja wybrana została klasa
ArrayList
. Dzięki temu wywołania takie jak:animals.get(1);
zwracają obiekty klasy
Animal
, dzięki czemu mogą one być używane w "bezpieczny" sposób - tzn. kompilator może sprawdzić, czy wywoływane metody faktycznie występują w klasieAnimal
.