From feb01978e40e6c2c7aa22bd7c9f559f45d359b24 Mon Sep 17 00:00:00 2001 From: bjornregnell Date: Thu, 14 Jun 2018 15:24:36 +0200 Subject: [PATCH] add requirements on new lab blockbattle --- compendium/modules/w05-classes-lab.tex | 376 ++++++------------------- 1 file changed, 81 insertions(+), 295 deletions(-) diff --git a/compendium/modules/w05-classes-lab.tex b/compendium/modules/w05-classes-lab.tex index 62694c6e2..67bf5c03b 100644 --- a/compendium/modules/w05-classes-lab.tex +++ b/compendium/modules/w05-classes-lab.tex @@ -9,315 +9,101 @@ \end{Goals} \begin{Preparations} -\item \DoExercise{\ExeWeekFIVE}{05} - -\item Läs igenom hela laborationen och studera dokumentationen för: -\begin{itemize}[nolistsep,noitemsep] -\item klassen \jcode{SimpleWindow} här: \url{http://cs.lth.se/pgk/api/} - -\item \code{scala.Double} och \code{scala.math}, speciellt metoder för avrunding, trigonometri och polära koordinater, här: -\url{http://www.scala-lang.org/api/current/} -\end{itemize} - -\item Studera den givna koden i kursens workspace på GitHub här:\\ -\url{https://github.com/lunduniversity/introprog/tree/master/workspace} -%i katalogen \href{https://github.com/lunduniversity/introprog/tree/master/workspace}{\texttt{w05\_turtle}} - +\item \DoExercise{\ExeWeekFIVE}{05}, speciellt uppgift \ref{exe:classes:labprep}. +\item Läs igenom hela laborationen och planera ditt arbete. \end{Preparations} \subsection{Bakgrund} -Under den här laborationen ska du skapa en samling av klasser som tillsammans kan användas för att rita i ett fönster. Du ska bland annat skapa en klass \code{Turtle} som använder den färdigskrivna Java-klassen \code{SimpleWindow} för att möjliggöra sköldpaddsgrafik liknande det vi gjorde i Kojo-laborationen i avsnitt \ref{section:lab:kojo}. - -%SimpleWindow kan skapa ett enkelt ritfönster på skärmen, med metoder för att rita linjer, etc. SimpleWindow håller koll på en ''penna'' som representerar \textit{aktuell ritposition}. Det finns metoder för att flytta pennan och att rita en rak linje från pennans aktuella ritposition till en ny pennposition. -%Delar av dokumentationen för SimpleWindow återspeglas i nedan specifikation. -%Den fullständiga dokumentationen återfinns här: \url{http://cs.lth.se/pgk/api/} - -%\vspace{1em}%hack to keep comment with method -%\begin{JavaSpec}{class SimpleWindow} -% /** mouse click event type */ -% public final static int MOUSE_EVENT = 1; -% -% /** key pressed event type */ -% public final static int KEY_EVENT = 2; -% -% /** window closed event type */ -% public final static int CLOSE_EVENT = 3; -% -% /** Creates a window and makes it visible. */ -% public SimpleWindow(int width, int height, String title); -% -% /** Returns the width of the window. */ -% public int getWidth(); -% -% /** Returns the height of the window. */ -% public int getHeight(); -% -% /** Clears the window. */ -% public void clear(); -% -% /** Closes the window.*/ -% public void close(); -% -% /** Opens the window. */ -% public void open(); -% -% /** Moves the pen to a new position. */ -% public void moveTo(int x, int y) ; -% -% /** Moves the pen to a new position while drawing a line. */ -% public void lineTo(int x, int y); -% -% /** Writes a string at the current position.* / -% public void writeText(String txt); -% -% /** Draws a bitmap image at the current position.*/ -% public void drawImage(Image image); -% -% /** Returns the pen's x coordinate. */ -% public int getX(); -% -% /** Returns the pen's y coordinate. */ -% public int getY(); -% -% /** Sets the line width. */ -% public void setLineWidth(int width); -% -% /** Sets the line color. */ -% public void setLineColor(Color col); -% -% /**Returns the current line width. */ -% public int getLineWidth(); -% -% /** Returns the current line color. */ -% public Color getLineColor(); -% -% /** Waits for a mouse click. */ -% public void waitForMouseClick(); -% -% /** Returns the mouse x coordinate at the last mouse click. */ -% public int getMouseX(); -% -% /** Returns the mouse y coordinate at the last mouse click. */ -% public int getMouseY(); -% -% /**Adds a sprite to the window. */ -% public void addSprite(Sprite sprite); -% -% /** Wait for a specified time. */ -% public static void delay(int ms); -%\end{JavaSpec} -% -% -%\clearpage - -\subsection{Obligatoriska uppgifter} - - -\Task Skapa dessa kataloger %(kallas även bibliotek eller mappar på svenska och \emph{''folder''} eller \emph{directory} på engelska) -och tomma filer för din kod med hjälp av nedan Linuxkommandon (eller motsvarande på annat lämpligt sätt): -\begin{REPLnonum} -mkdir turtle -cd turtle -mkdir -p src/main/scala/graphics -touch Main.scala -mv Main.scala src/main/scala/graphics/. -ls src/main/scala/graphics/ -\end{REPLnonum} -Om man skriver mycket kod blir det lättare att hitta olika delar om man har dem i olika filer med lämpliga filnamn. Det är vanligt att man lägger kodfilerna i katalogen \code{src/main/scala} och där skapar en egen underkatalog för varje paket med samma namn som paketet.\footnote{Flera verktyg kräver exakt denna katalogstruktur för att hitta koden utan specialinställningar.} - - -\Task Lägg din punktklass från veckans övning här:\\ \texttt{src/main/scala/graphics/Point.scala}. - -Kontrollera att du kan använda din punkt-klass enligt nedan. Starta REPL och klistra först in din case-klass med sitt kompanjonsobjekt efter kommandot \code{:paste} (eller kortare \code{:pa}). (Du ska inte ta med paketdeklarationen, då \code{package} inte fungerar i REPL.) När koden för \code{Point} är tolkad av REPL utan kompileringsfel, testa detta: -\begin{REPLnonum} -scala> Point(1,1).theta.toDegrees -res0: Double = 45.0 - -scala> Point(3,4).r -res1: Double = 5.0 - -scala> Point(1,1).negY + Point(2,5) -res2: Point = Point(3.0,4.0) - -scala> Point.polar(2, 60.0.toRadians).theta.toDegrees -res3: Double = 60.000001669652114 -\end{REPLnonum} - - -\Task Lägg \code{cslib.jar} i katalogen \code{lib}, t.ex. med dessa Linuxkommandon: -\begin{REPLnonum} -> mkdir lib -> wget -O lib/cslib.jar http://cs.lth.se/pgk/cslib -\end{REPLnonum} - -\Task Skapa en \code{main}-metod i singelobjektet \code{Main} i paketet \code{graphics} i filen \code{src/main/scala/graphics/Main.scala} -som gör något enkelt med både \code{Point} och \code{SimpleWindow}, t.ex. drar en linje mellan två punkter enlig nedan. -\scalainputlisting[numbers=left,basicstyle=\ttfamily\fontsize{11}{13}\selectfont]% -{../workspace/w05_turtle/src/main/scala/graphics/Main.scala} - -\noindent När många kodfiler beror av varandra behöver kompilatorn ha tillgång till alla kodfiler samtidigt. Detta kan åstadkommas genom att ge argumentet \code{*.scala} till \code{scalac} enligt nedan. Dessutom blir det en hel del \code{.class}-filer som utdata från kompilatorn, så man brukar lägga dem i en katalog med namnet \code{bin} (eller ibland \code{target}) för att separera dem från övriga filer. -Använd följande Linuxkommandon\footnote{I Windows, byt ut kolon mot semikolon.} för att skapa en \code{bin}-katalog\footnote{Optionen \code{-d} berättar för kompilatorn var bytekodfilerna ska ligga.}, samkompilera alla filer och köra \code{main}-metoden: -\begin{REPLnonum} -> mkdir bin -> scalac -cp lib/cslib.jar -d bin src/main/scala/graphics/*.scala -> scala -cp "lib/cslib.jar:bin" graphics.Main -\end{REPLnonum} - - -\Task Skapa klassen Turtle som representerar en virtuell sköldpadda med en penna under magen som kan rita i \code{SimpleWindow} enligt nedan riktlinjer: - -\begin{enumerate} -\item Klassen \code{Turtle} ska vara en klass med ett förändringsbart tillstånd bestående av tre privata attribut som håller reda på detta: - -\begin{itemize} -\item en position av typen \code{Point} där ett positivt y-värde räknas \emph{nedåt} i fönstret (alltså annorlunda jämfört med hur skjöldpaddan i Kojo fungerar). -\item en riktning av typen \code{Double} som anges som en vinkel i grader (och inte radianer), där ett positivt värde anger vinkeln motsols från x-axeln. -\item ett läge på pennan av typen \code{Boolean} där \code{true} anger att pennan är nere. -\end{itemize} - -\item Utgå från det ofärdiga kodskelettet nedan där dokumentationskommentarerna ger ytterligare detaljer att ta hänsyn till. Om du skriver klassen från början behöver du inte skriva av dokumentationskommentarerna. Kodskelettet finns även på \href{https://github.com/lunduniversity/introprog/blob/master/workspace/}{GitHub}. - -\item Flera metoder har \code{Turtle} som returtyp. I dessa fall ska en referens till den egna instansen returneras för att möjliggöra upprepad punktnotation, t.ex.:\\ -\code{t.jumpTo(Point(100, 200)).turnNorth.penDown} - -\scalainputlisting[numbers=left,basicstyle=\ttfamily\fontsize{10}{12}\selectfont]% -{../workspace/w05_turtle/src/main/scala/graphics/Turtle.scala} -\end{enumerate} - -\noindent Tips: - -\begin{itemize} -\item Allteftersom du implementerar de saknade delarna, utöka din \code{main}-metod i \code{Main.scala} med fler tester och kolla så att dina implementationer funkar som det är tänkt. Testa på nytt efter varje litet tillägg så att du hela tiden har något som fungerar. Det är mycket lättare att felsöka efter en liten ändring än efter många och stora ändringar. - -\item Du får namnge de privata variablerna som representerar det förändringsbara tillståndet så som du själv anser lämpligt. Tänk på att det i Scala kan bli namnkrock mellan metoder och privata attribut. I dessa fall brukar man namnge det privata attributet med ett understreck i början för att skilja dem åt, t.ex.: \\ -\code{private var _direction: Double = ???} - -\item I metoden \code{forward} har du nytta av metoden \code{Point.polar}, metoden \code{.toRadians} som kan konvertera en \code{Double} i grader till radianer, samt metoden \code{Point.negY} (se övning \texttt{\ExeWeekFIVE}). - -\item Tänk på att vinkelberäkningar på radianer förutsätter kartesiskt koordinatsystem. Negeringen av $y$-koordinaten ska ske \emph{efter} sådana beräkningar, men \emph{innan} uppdatering av positionen sker. - -\end{itemize} - - -\Task Implementera case-klassen \code{Rect} enligt specifikationen nedan. Kodskelettet finns på \href{https://github.com/lunduniversity/introprog/blob/master/workspace/w05_turtle/src/main/scala/graphics/Rect.scala}{GitHub}. Testa dina implementationer allteftersom du skriver dem, genom att stegvis utöka din \code{main}-metod. -En rektangel har sin position \code{pos} i övre vänstra hörnet och en vridning \code{angle} som anges som en vinkel i grader (och inte radianer), där ett positivt värde anger vinkeln motsols från x-axeln. -I utgångsläget är rektangeln ej vriden, vilket motsvarar $0$ grader. -Metoderna har \code{Rect} som returtyp, vilket möjliggör upprepad punktnotation, t.ex.:\\ -\code{r.rotatedLeft(15).draw(t).scaled(1.5).translated(5, 5).draw(t)} - - -\emph{Tips:} Du har vid implementationen av flera av metoderna i \code{Rect} nytta av att använda metoden \code{copy}, som erbjuds automatiskt i alla case-klasser. Nedan exempel använder \code{copy} för att skapa ett nytt objekt där bara ett attribut har ett annat värde: -\begin{REPLnonum} -scala> case class Point3D(x: Int, y: Int, z: Int) - -scala> Point3D(2,3,4).copy(x = 5) -res0: Point3D = Point3D(5,3,4) -\end{REPLnonum} - - +{\raggedright% +\begin{minipage}{0.56\textwidth} \begin{figure}[H] -\scalainputlisting[numbers=left,basicstyle=\ttfamily\fontsize{10.5}{12}\selectfont]% -{../workspace/w05_turtle/src/main/scala/graphics/Rect.scala} + \centering + \includegraphics[width=\textwidth]{../img/blockbattle.png} +% \caption{En lundensisk blockmullvad fångad på bild under aktivt grävanade.} + \label{lab:blockbattle:fig:game} \end{figure} +\end{minipage}% +}% +\newlength{\currentparskip}% +\newlength{\currentparindent}% +{ +\setlength{\currentparskip}{\parskip}% save the value +\setlength{\currentparindent}{\parindent}% save the value +\hfill% +\begin{minipage}{0.4\textwidth} +\setlength{\parskip}{\currentparskip}% restore the value +\setlength{\parindent}{\currentparindent}% restore the value +\noindent Under denna laboration ska du träna på att deklarera klasser och skapa flera instanser av samma klass. Du tränar även på att bygga ett större program från grunden. + +Du ska utveckla ett spel för två spelare som sitter vid samma tangentbord, där den vänstra spelaren styr en blockmullvad med tangenterna A,S,D,W, och den högra spelaren styr en annan blockmullvad med piltangenterna. + +I bilden till höger ser du hur spelet kan se ut. Det finns en ljusbrun och en mörkbrun mullvad. Poängräkningen visas överst i himlen. Det finns fyra rosa blockmaskar (se uppgift \ref{lab:blockmole:task:blockworm} i laboration \code{blockmole}) som mullvadarna tävlar om att försöka fånga. När en blockmask teleporterar sig till en ny slumpmässig position lämnar den jord efter sig. När en mullvad är vid gräsytan lämnar den jord efter sig. +Det ger poäng att gräva tunnlar och att fånga blockmaskar. + +Du bestämmer själv hur poängsättningen ska ske och kriteriet för när spelet är slut etc. +\end{minipage}% +} + + + +\subsection{Obligatoriska krav} + +Följande krav ska uppfyllas av din implementation: +\begin{itemize}[nosep, label={$\square$},] +%\item Det ska finnas två blockmullvadar, en för vänster spelare och en för höger spelare, som styrs med ASDW resp. piltangerna. +\item Varje mullvad rör sig i sin aktuella riktning tills användaren ändrar riktning genom att trycka på ''sin'' motsvarande knapp, t.ex. W eller pil-upp. +\item Då en mullvad går i mörkbrun jord grävs ljusbruna tunnlar. +\item Då en blockmullvad når fönstrets kant eller himlen ska mullvadens riktning bli den motsatta. +\item Det ska finnas poängräkning för varje spelares blockmullvad som visas under spelets gång. +\item Det ska ge poäng att gräva tunnlar. +\item Ett spel ska avslutas när något valfritt kriterium uppfyllts och texten \emph{Game over} ska då skrivas ut i spelfönstret. +\item Vid \emph{Game over} ska användaren kunna välja att avsluta programmet eller att starta ett nytt spel. +\end{itemize} +\vspace{1em}\noindent Din kod ska uppfylla dessa krav: +\begin{itemize}[nosep, label={$\square$}] +\item Du ska utgå från klasserna som du implementerat i uppgift \ref{exe:classes:labprep} i övning \texttt{\ExeWeekFIVE}. +\item Varje klass med ev. tillhörande kompanjonsobjekt ska finnas i en egen kodfil och tillhöra paketet \code{blockbattle}. +\item Det ska finnas en klass \code{Game} som skapas i huvudprogrammet och som har en metod \code{start()} som sätter igång spelet. +\item Konstanter ska, om lämpligt, namnges och placeras i kompanjonsobjekt. +\item Din kod ska kunna byggas med hjälp av byggverktyget \code{sbt}, se appendix \ref{appendix:build}. +\end{itemize} -%\clearpage - -\Task\Checkpoint När \code{Point}, \code{Turtle} och \code{Rect} är färdigimplementerade ska du testa klasserna i samverkan genom att köra \code{main}-metoden i singelobjektet \code{Demo} nedan, som även finns i kursens \href{https://github.com/lunduniversity/introprog/blob/master/workspace/w05_turtle/src/main/scala/graphics/Rect.scala}{workspace}. - - -\begin{figure}[H] -\begin{minipage}{0.45\textwidth} - -\includegraphics[width=0.9\textwidth]% -{../img/snurre-rect} -\end{minipage} -\begin{minipage}{0.54\textwidth} -Den första bilden som ritas ska visa två lika stora kvadrater i samma höjd. Efter musklick kommer en animering av tre färgglada rektanglar, som avslutningsvis ger bilden till vänster. -Från vänster till höger har rektanglarna gröna, blåa respektive röda konturer. -\end{minipage} - - -\end{figure} - -\noindent När det finns en handledare ledig, redovisa vad du åstadkommit. Vid väntetid, fortsätt med efterföljande uppgifter. - - -\begin{figure}[H] -\scalainputlisting[numbers=left,basicstyle=\ttfamily\fontsize{11}{13}\selectfont]% -{../workspace/w05_turtle/src/main/scala/graphics/Demo.scala} -\end{figure} - - - - - -\clearpage - -\subsection{Frivilliga extrauppgifter} - -Nedan uppgifter kan göras i valfri ordning. - -\Task Använd din Turtle för att rita en cirkel. För att göra detta kan du t.ex. låta din Turtle gå ett kort steg och svänga någon grad tills den har gjort ett fullt varv. - -\Task Skapa två stycken Turtles i samma fönsterobjekt som rör sig alternerande. Fungerar allt som tänkt? - - -\Task Studera dokumentationen för de \code{SimpleWindow}-metoder som erbjuder hantering av händelser \Eng{event} och använd dessa för lösa deluppgifterna nedan. - -\Subtask Gör så att en Turtle kan styras med hjälp av tangentbordstryckningar W--A--S--D för upp--vänster--ner--höger och att den ritar ett spår allteftersom den förflyttas. - -\Subtask Gör så att en andra Turtle kan styras med hjälp av tangentbordstryckningar I--J--K--L för upp--vänster--ner--höger och att den också ritar ett spår allteftersom den förflyttas. - -\Subtask Gör så att, när de två sköldpaddorna ovan befinner sig tillräckligt nära varandra, det ritas ut en rektangel med hörn där de två sköldpaddorna finns. (Denna uppgift är lite svårare och kan behöva delas upp i delar.) - - -\Task Studera dokumentationen för de \code{SimpleWindow}-metoder som erbjuder hantering av flyttbara bilder \Eng{sprites}. Gör så att en fin Sprite ritas vid positionen för de styrbara sköldpaddorna i föregående uppgift. - - -\Task Skapa en case-klass \code{RectSeq} enligt specifikation på sidan \pageref{code:classes:graphics:rectanglesequence}. I denna klass skall metoden \code{draw} rita ut ett antal rektanglar där varje rektangel har förflyttat sig, roterats och skalats jämfört med föregående rektangel i sekvensen. - -\begin{figure}[H] -\centering -\includegraphics[width=0.75\textwidth]{../img/turtle/RectSeq.png} -%\caption Rotation av rektangel med koden nedan. -%\label{fig:classes:graphics:rollingrectangle} -\end{figure} -\noindent Bilden ovan ska skapas med denna kod: -\begin{Code} - def rectSeqExample(t: Turtle): Unit = { - val rect = Rect(pos = Point(200, 200), width = 50, height = 30) - RectSeq(rect, n = 5, dist = 70, rot = -30, scale = 0.67).draw(t) - } -\end{Code} -\noindent Nedan kod ritar bilden i fig. \ref{fig:classes:graphics:rectanglesequence} på sidan \pageref{fig:classes:graphics:rectanglesequence}. Använd gärna \code{setLineColor} i \code{SimpleWindow} för att göra en färggladare stjärna. Slumpvisa transformationer är också kul. +\subsection{Valfria krav -- välj minst ett} -\begin{Code} -val w = new SimpleWindow(500, 500, "Shapes") -val t = new Turtle(w, new Point(200, 200), 0, false) -val rect = Rect(pos = Point(225, 235), width = 50, height = 30) -val roll = RectSeq(rect, n = 100, dist = 2, scale = 0.98) -for (i <- 0 to 360 by 20) roll.rotatedLeft(i).draw(t) -\end{Code} +Välj själv att implementera minst ett, gärna fler, av följande krav: +\begin{itemize}[nosep, label={$\square$}] +\item Det ska finns ett lagom antal blockmaskar, förslagsvis 4 stycken i början. +\item Blockmullvadarna ska även ha ett heltalsvärde som representerar hälsan. Hälsan minskas något när man gräver tunnlar. Hälsan ska synas i spelfönstret. +\item Att springa på gräset ska ge poäng men kosta i hälsa. +\item Att fånga blockmask påverkar poäng och/eller hälsa. +\item Det ska finnas gula blockdiamanter som ger många poäng om man tar dem först. +\item Det ska gå att välja namn på sin blockmullvad och namnet ska synas i spelet vid poängutskriften. +\item Det ska gå fortare att gå i gångar jämfört med att gräva i jord. +\item Den blockmullvad som fångar en blockmask ska öka sin grävhastighet. +\item Vid varje \emph{Game Over} ska \emph{highscore} visas. +\end{itemize} +\subsection{Förebredelser inför redovisningen} +Innan du redovisar din implementation, förbered dig genom att vara beredd på att muntligt kunna redogöra för följande: +\begin{itemize}[nosep, label={$\square$}] + \item Beskriv hur ditt program är organiserat. + \item Beskriv vilka åtgärder du gjort för att koden ska vara lätt att läsa. + \item Beskriv hur du stegvis utvecklat ditt program från enklare till mer avancerad funktionalitet, samt vilka buggar du upptäckt och fixat. + \item Beskriv vilket eller vilka valfria krav som din implementation uppfyller. + \item Beskriv hur du hade behövt ändra i klassen \code{Mole} för att det ska gå att skriva \code{new Mole.move().move().reverseDir().move()} +\end{itemize} -\begin{figure} -\centering -\includegraphics[width=0.5\textwidth]{../img/w06-lab/RectangleSequence.png} -\caption {En stjärna skapad med hjälp av \code{RectSeq}.} -\label{fig:classes:graphics:rectanglesequence} -\end{figure} +\subsection{Tips och goda råd} -\noindent Nedan finns ett kodskelett som du kan utgå ifrån. Dokummentationskommentarerna innehåller fler detaljer om hur det är tänkt att klassen ska fungera. %De metoder som returnerar \code{RectSeq} ska returnera en referens till den egna instansen så att upprepad punktnotation möjliggörs. - \emph{Tips:} Alla metoder utom två implementeras lättast med metoden \code{copy} som finns i alla case-klasser. -\begin{figure}[H] -\scalainputlisting[numbers=left,basicstyle=\ttfamily\fontsize{9.8}{11.8}\selectfont]% -{../workspace/w05_turtle/src/main/scala/graphics/RectSeq.scala} -\label{code:classes:graphics:rectanglesequence} -\end{figure} +% \begin{figure}[H] +% \scalainputlisting[numbers=left,basicstyle=\ttfamily\fontsize{9.8}{11.8}\selectfont]% +% {../workspace/w05_turtle/src/main/scala/graphics/RectSeq.scala} +% \label{code:classes:graphics:rectanglesequence} +% \end{figure} %\Task En riktig utmaning, för den som har lust: Implementera spelet ''Masken'' som beskrivs här: \url{https://sv.wikipedia.org/wiki/Snake}.