diff --git a/problem-set/RotatingStar.java b/problem-set/RotatingStar.java new file mode 100644 index 0000000..3c187a2 --- /dev/null +++ b/problem-set/RotatingStar.java @@ -0,0 +1,106 @@ +/* + * File: RotatingStar.java + * ----------------------- + * This program draws a customizable star and makes it rotate + */ + +import java.util.ArrayList; + +import acm.graphics.*; +import acm.program.*; +import javafx.util.Pair; + +public class RotatingStar extends GraphicsProgram { + + // Size of the application + int appWidth = 1000; + int appHeight = 1000; + + // Center the star will be generated at + GPoint center = new GPoint(appWidth / 2, appHeight / 2); + // Amount of corners the star will have + int points = 5; + // Amount of points jumped from start to end of single line + int jumpAm = 2; + // Radius of the star + int length = 400; + // The degree at which the star spins in one iteration + double speed = 0.5; + // The delay between iterations + int delay = 5; + + public void run() { + setSize(appWidth, appHeight); + + Pair, ArrayList> starInfo = generateStar(); + // Lines the star contains + ArrayList starLines = starInfo.getKey(); + // The degree of each line + ArrayList starDegs = starInfo.getValue(); + + while (true) { + rotateStar(starLines, starDegs); + pause(delay); + } + } + + /* + * Pre-Condition : None + * + * Post-Condition : Displays the star and returns all the relevant information about it + */ + private Pair, ArrayList> generateStar() { + // Amount of radians between each corner + double jumpDeg = 2 * Math.PI / points; + + ArrayList lineRes = new ArrayList(); + ArrayList degRes = new ArrayList(); + for (int i = 0; i < points; i++) { + // Get cords of the start and end of a line + GPoint start = getPointOnCircle(i * jumpDeg); + // End corner is always jumpAm amount of corners after the starting corner + GPoint end = getPointOnCircle((i + jumpAm) * jumpDeg); + + GLine curLine = new GLine( + start.getX(), start.getY(), + end.getX(), end.getY()); + + lineRes.add(curLine); + degRes.add(i * jumpDeg); + add(curLine); + } + return new Pair, ArrayList>(lineRes, degRes); + } + + /* + * Pre-Condition : None + * + * Post-Condition : Returns the coordinates of a point on the star circle at deg radians + */ + private GPoint getPointOnCircle(double deg) { + return new GPoint( + center.getX() + length * Math.cos(deg), + center.getY() + length * Math.sin(deg)); + } + + /* + * Pre-Condition : Star has to be already generated + * + * Post-Condition : Rotates the star by speed radians + */ + private void rotateStar(ArrayList starLines, ArrayList starDegs) { + double jumpDeg = 2 * Math.PI / points; + for (int i = 0; i < points; i++) { + // Calculate the next rotation degrees + double nextDeg = (starDegs.get(i) + speed) % (2 * Math.PI); + + // Move line points + GPoint nextStart = getPointOnCircle(nextDeg); + GPoint nextEnd = getPointOnCircle(nextDeg + jumpAm * jumpDeg); + + starLines.get(i).setStartPoint(nextStart.getX(), nextStart.getY()); + starLines.get(i).setEndPoint(nextEnd.getX(), nextEnd.getY()); + starDegs.set(i, nextDeg); + } + } +} \ No newline at end of file diff --git a/problem-set/RotatingStar.md b/problem-set/RotatingStar.md new file mode 100644 index 0000000..9bec849 --- /dev/null +++ b/problem-set/RotatingStar.md @@ -0,0 +1,127 @@ +# Rotating Star + +ამოცანა: +``` +გამოვსახოთ ვარსკვლავი, რომელიც ტრიალებს +``` + +ამ ამოცანის სირთულე იმაში მდგომარეობს, რომ მცირედით მოითხოვს მათემატიკურ ცოდნას, თუმცა ძირითადი მიზანი არის ის, რომ სტუდენტს აჩვენოს განზოგადებით მიღებული საინტერესო თვისებები. + +## როგორ შეგვიძლია დავხატოთ ვარსკვლავი? +ვარსკვლავები, რომლებსაც ვხატავთ, შედგება მრავალი ხაზისა და წვეროსგან, იქნება ეს ჩვეულებრივი 5-ქიმიანი, დავითის ვარსკვლავი(6-ქიმიანი) თუ სხვა. ყველა ასეთ ვარსკვლავში არსებობს გარკვეული კანონზომიერები: +1. ყოველ მეზობელ(უახლოეს) წვეროებს შორის მოთავსებული კუთხე, რომელიც მდებარეობს ვარსკვლავის ცენტრზე, არის ტოლი +1. ყველა ვარსკვლავის წვერო არის მოთავსებული წრეწირზე, რომლის ცენტრიც არის თვითონ ამ ვარსკვლავის ცენტრი +1. ყოველი ვარსკვლავის მონაკვეთის მიერ გამოტოვებული წვეროების რაოდენობა(ანუ ხაზის საწყისი წვეროდან ბოლო წვერომდე არსებული მეზობელი წვეროების რაოდენობა) არის ტოლი + +მაგ: + + + +სურათზე გამოსახულ 5-ქიმიან ვარსკვლავში მეზობელ მწვანე მონაკვეთებს შორის კუთხეები არის ტოლი(1), ყველა წვერო მოთავსებულია წრეწირზე(2) და რაც შეეხება გამოტოვებულ წვეროებს, აქ წითელი(ვარსკვლავის) მონაკვეთი ტოვებს ზუსტად 1 წერტილს(შეიძლება ითქვას 2-საც, თუ მეორე მხრიდან წავალთ, მაგრამ ორივე ერთნაირი ფორმის ვარსკვლავს წარმოქმნიდა) + +ჩვენი მიზანი ახლა არის ამ ყველაფრის ჯავაში დაწერა და ვიზუალურად გამოტანა. ნაბიჯებად რომ დავყო: +1. გავწეროთ ყველა საჭირო ცვლადი ვარსკვლავის ყველა თვისების აღსაწერად +1. შევქმნათ მეთოდი, რომელიც შექმნის ამ ვარსკვლავისთვის საჭირო მონაკვეთებს და დაგვიბრუნებს მასზე სამუშაოდ(მის დასატრიალებლად) საჭირო ინფორმაციას +1. დავატრიალოთ ეს ვარსკვლავი + +## საჭირო ცვლადები +```java + GPoint center; + int points; + int jumpAm; + int length; + double speed; +``` +- `center` - ვარსკვლავის ცენტრის კოორდინატები +- `points` - ვარსკვლავის წვეროების კოორდინატები +- `jumpAm` - გამოტოვებული წვეროების რაოდენობას +1(კოდის დასაწერად უფრო მარტივია) +- `length` - ვარსკვლავის რადიუსი +- `speed` - ვარსკვლავის ბრუნვის სიჩქარე(რადიანებში) + +## ვარსკვლავის შექმნა და ინფორმაციის დაბრუნება +```java + /* + * Pre-Condition : None + * + * Post-Condition : Displays the star and returns all the relevant information about it + */ + private Pair, ArrayList> generateStar() { + // Amount of radians between each corner + double jumpDeg = 2 * Math.PI / points; + + ArrayList lineRes = new ArrayList(); + ArrayList degRes = new ArrayList(); + for (int i = 0; i < points; i++) { + // Get cords of the start and end of a line + GPoint start = getPointOnCircle(i * jumpDeg); + // End corner is always jumpAm amount of corners after the starting corner + GPoint end = getPointOnCircle((i + jumpAm) * jumpDeg); + + GLine curLine = new GLine( + start.getX(), start.getY(), + end.getX(), end.getY()); + + lineRes.add(curLine); + degRes.add(i * jumpDeg); + add(curLine); + } + return new Pair, ArrayList>(lineRes, degRes); + } +``` + +> ამ ფუნქციას გადაეცემა ზევით ნახსენები ცვლადები, მაგრამ სიმარტივის გამო გატანილია გლობალურად + +თავდაპირველად `jumpDeg` ცვლადში ვინახავ თითო მეზობელ წვეროს შორის არსებულ კუთხეს. შემდეგ ვინახავთ 2 სიას, რომელიც აღწერს ამ ვარსკვლავს და გაგვიადვილებს მის ტრიალს. `lineRes` ინახავს თვითონ ვარსკვლავის შემადგენელ მონაკვეთებს, ხოლო `degRes` ყოველი ამ მონაკვეთის საწყისი წერტილის შესაბამის კუთხეს + +> შესაძლებელია `degRes` ცვლადის გარეშეც ვარსკვლავის დატრიალება, მაგრამ ამ სიის არსებობა გვეხმარება იმაში, რომ ლოგიკა ძალიან არ გაგვირთულდეს დატრიალებისას + +შემდეგ ვქმნით ვარსკვლავის მონაკვეთებს, რომლის რაოდენობაც ემთხვევა წვეროების რაოდენობას. ყოველი მონაკვეთის საწყისი წერტილი უნდა იყოს ამ წრეზე i-ური წერტილი, რომელსაც აქ ავღნიშნავ ცვლადით `start`, ხოლო ბოლო წერტილი არის `jumpAm` წერტილის მერე, ანუ (i+jumpAm)-ური წერტილი, რომელსაც ავღნიშნავ ცვლადით `end`. ამ წერტილების კოორდინატების გამოსათვლელად კიდევ ვიყენებ დამხმარე მეთოდს `getPointOnCircle` + +```java + /* + * Pre-Condition : None + * + * Post-Condition : Returns the coordinates of a point on the star circle at deg radians + */ + private GPoint getPointOnCircle(double deg) { + return new GPoint( + center.getX() + length * Math.cos(deg), + center.getY() + length * Math.sin(deg)); + } +``` + +ეს კოდი ნაკლებადაა დამოკიდებული პროგრამირებაზე და მეტად მათემატიკურ ცოდნაზე. აქ ხდება შემდეგი: მეთოდს გადაეცემა კუთხე(რადიანებში) და აბრუნებს `center` წერტილზე `length` რადიუსის მქონე წრეწირზე მაგ კუთხის შესაბამისი წერტილს. `getPointOnCircle(i * jumpDeg)` მეთოდის გამოძახებისას არგუმენტი i იმიტომ მრავლდება `jumpDeg` ცვლადზე, რომ i არის მხოლოდ წერტილის ნომერი, რომელიც ჩვენ მივანიჭეთ. ამ გამრავლებით ვიგებთ თუ ეს ნომერი რომელ კუთხეს მიესადაგება. მაგალითად, i=0 იქნება 0 რადიანი, i=1 იქნება jumpDeg რადიანი და ა.შ. ეს ყველა წერტილი კიდევ მეზობელი წერტილებისგან ტოლი კუთხეებით იქნება დაშორებული, როგორც საჭიროა ვარსკვლავისთვის + +შემდეგი კიდევ მარტივია. ვქმნი მონაკვეთს და ვამატებ სიაში `lineRes`, ხოლო თვითონ საწყისი წერტილის კუთხეს - `degRes`. ბოლოს კიდევ ამ 2 სიას ვაბრუნებთ. + +> 2 ცვლადის დასაბრუნებლად ვიყენებ ცვლადის ტიპს `Pair`, რომელიც ინახავს 2 ცვლადს. ამ 2 ცვლადის ტიპი არ არის აუცილებელი, რომ ერთმანეთს დაემთხვეს, როგორც მაგალითში ვხედავთ + +## ვარსკვლავის ტრიალი +```java + /* + * Pre-Condition : Star has to be already generated + * + * Post-Condition : Rotates the star by speed radians + */ + private void rotateStar(ArrayList starLines, ArrayList starDegs) { + double jumpDeg = 2 * Math.PI / points; + for (int i = 0; i < points; i++) { + // Calculate the next rotation degrees + double nextDeg = (starDegs.get(i) + speed) % (2 * Math.PI); + + // Move line points + GPoint nextStart = getPointOnCircle(nextDeg); + GPoint nextEnd = getPointOnCircle(nextDeg + jumpAm * jumpDeg); + + starLines.get(i).setStartPoint(nextStart.getX(), nextStart.getY()); + starLines.get(i).setEndPoint(nextEnd.getX(), nextEnd.getY()); + starDegs.set(i, nextDeg); + } + } +``` + +შენახული ინფორმაციის გამო, დატრიალება ამ ვარსკვლავის ახლა არის მარტივი ოპერაცია. `rotateStar` მეთოდს მხოლოდ სჭირდება იცოდეს ის 2 სია, რომელიც ვარსკვლავის შექმნისას დავაბრუნეთ. იმისთვის, რომ ვარსკვლავი დატრიალდეს, ყველაზე ლოგიკური გზა იქნება წერტილების თანაბარი გადაადგილება ამ წრეწირზე, რისთვისაც საჭიროა ვიცოდეთ ყოველ იტერაციაში თუ რამდენი რადიანით გადაადგილდება წერტილი. ამ რაოდენობას ვინახავთ `speed` ცვლადში. + +თავდაპირველად ვიგებთ შემდეგ კუთხეს, რაც მობრუნების შემდეგ გვექნება. ეს მარტივია, საჭიროა მონაკვეთის კუთხეს დავუმატოთ მობრუნების სიჩქარე(განაშთვა არაა აუცილებელი). ამას ვაკეთებთ ყოველი მონაკვეთისთვის და თითოს მობრუნებისას შემდეგი საწყისი წერტილის კუთხეს ვიმახსოვრებთ `nextDeg` ცვლადში. ამის შემდეგ იგივეს ვიმეორებთ, რაც ზევით: ვიგებთ საწყისსა და საბოლოო წერტილებს მონაკვეთის და `generateStar` მეთოდში როცა ვქმნიდით ამ მონაკვეთებს, აქ მხოლოდ მნიშვნელობებს ვუცვლით. ბოლოს კიდევ სიაში ვცვლით ამ i-ური მონაკვეთის საწყისი წერტილის კუთხეს. + +> ერთი დამაბნეველი ნაწილი შეიძლება იყოს `nextEnd` ცვლადში არგუმენტს რატომ ვუმატებთ jumpAm * jumpDeg, მაგრამ ვიცით, რომ ეს არის საბოლოო წერტილი, ანუ ის საწყისი წერტილისგან უნდა იყოს `jumpAm` წერტილით დაშრებული, ხოლო თითო წერტილს შორის არის `jumpDeg` სიდიდის კუთხე \ No newline at end of file diff --git a/problem-set/images/rotating-star-5-point-ex.jpeg b/problem-set/images/rotating-star-5-point-ex.jpeg new file mode 100644 index 0000000..3e67808 Binary files /dev/null and b/problem-set/images/rotating-star-5-point-ex.jpeg differ