diff --git a/problem-set/Division.java b/problem-set/Division.java new file mode 100644 index 0000000..6f22342 --- /dev/null +++ b/problem-set/Division.java @@ -0,0 +1,105 @@ +import stanford.karel.SuperKarel; + +public class Division extends SuperKarel { + public void run() { + move(); // We need to stand on correct starting point. + while (beepersPresent()) { + doMainOperation(); + } + collectBeepers(); + } + + /* + * This method describes the main operation. we need to move on third square + * first. suppose, we have n beepers on second square and m on third square. + * We need to do subtraction n/m times and save that result on fourth + * square. + */ + private void doMainOperation() { + move(); + subtractSecondSquare(); + resetThirdSquare(); + } + + /* + * starting position: 3x1, facing east ending position: 5x1, facing east/ + */ + private void subtractSecondSquare() { + while (beepersPresent()) { + subtractOperation(); // this line subtracts third square's beepers + // // from second square's beepers + } + increaseResult(); // this method calculates final answer on 4x1 square. + } + + /* + * this method increases result each time by one. + */ + private void increaseResult() { + move(); + putBeeper(); + move(); + } + + /* + * this is the main method for subtraction operation for second and third + * squares. + */ + private void subtractOperation() { + pickBeeper(); + turnAround(); + move(); + pickBeeper(); + turnAround(); + move(); + move(); + move(); + putBeeper(); + turnAround(); + move(); + move(); + turnAround(); + } + + /* + * starting position: 5x1, facing east ending position: 2x1, facing east + * this function picks all beepers from 5x1 square and return to third + * square to start subtract operation again. + */ + private void resetThirdSquare() { + while (beepersPresent()) { + pickBeeper(); + turnAround(); + move(); + move(); + putBeeper(); + turnAround(); + move(); + move(); + } + returnToSecondSquare(); // return to main square to start operation + // again. + } + + // starting position 5x1, facing east + // end position 2x1, facing east. + private void returnToSecondSquare() { + turnAround(); + move(); + move(); + move(); + turnAround(); + } + + /* + * we need this method to leave beepers only on fourth square. it picks + * beepers from third square. starting position 2x1, facing east. end + * position: 3x1, facing east. + */ + private void collectBeepers() { + move(); + while (beepersPresent()) { + pickBeeper(); + } + } +} \ No newline at end of file diff --git a/problem-set/Division.md b/problem-set/Division.md new file mode 100644 index 0000000..24219a9 --- /dev/null +++ b/problem-set/Division.md @@ -0,0 +1,97 @@ +# Division +პრობლემა: +``` +კარელმა უნდა გაყოს ორი რიცხვი, 2x1 უჯრაზე დევს n ცალი ბრილიანტი, 3x1 უჯრაზე m +ცალი ბრილიანტი, კარელმა 4x1 უჯრაზე უნდა დადოს n / m ბრილიანტი. ჩათვალეთ, რომ n +ზუსტად იყოფა m-ზე და კარელს ჩანთაში უსასრულო რაოდენობის ბრილიანტი აქვს. +``` +##ამოცანის ამოხნის ალგორითმი +ჩვენი ამოცანა შეიცავს რამდენიმე რთულ ნაწილს. იმისათვის, რომ მეორე უჯრაზე დადებული ბრილიანტები გავყოთ მესამე უჯრაზე არსებულთან, ამისათვის +მესამე უჯრაზე დალაგებული ბრილიანტები იმდენჯერ უნდა გამოვაკლოთ მეორე უჯრაზე მყოფ ბრილიანტებს, სადამდეც შეგვიძლია. ამისათვის გვჭირდება ისეთი +უჯრა სადაც შევინახავთ ამ ოპერაციების რაოდენობას. ეს იყოს მეოთხე უჯრა. ამ უჯრაზე ყოველი გამოკლების ოპერაციის შემდეგ დავდოთ ბრილიანტი. საბოლოოდ +ეს მოგვცემს შედეგს. +## პრობლემის გადაჭრის გზა +ჩვენი ამოცანა მოიცავს სამ ძირითად ნაწილს და აუცილებელია განვიხილოთ თითოეული წარმატების მისაღწევად. +* კარელი უნდა გადავიდეს მესამე უჯრაზე და დაიწყოს გამოკლების ოპერაცია მეორე და მესამე უჯრებისთვის. +* ყოველ ოპერაციაზე გავზარდოთ მეოთხე უჯრაზე დალაგებული ბრილიანტები რაც საბოლოოდ მოგვცემს შედეგს. +* დააბრუნოს მეხუთე უჯრაზე დალაგებული ბრილიანტები მესამე უჯრაზე მოქმედების თავიდან დაწყებისთვის. +* ამ 2 მოქმედების შემდეგ, ბრილიანტები იქნება დალაგებული მესამე და მეოთხე უჯრაზე, ჩვენ გვჭირდება რომ ავიღოთ ყველა ბრილიანტი მესამე უჯრიდან, რათა ამოცანის პირობა სრულყოფილად დავიცვათ. +--- +### გამოკლების ოპერაცია მეორე და მესამე უჯრებისთვის. +1. გამოვიყენოთ კარელისათვის ცნობილი `beepersPresent()` მეთოდი. +2. გამოვიყენოთ `while` ციკლი. +3. მესამე უჯრაზე დალაგებულ ბრილიანტების გამოკლების პარალელურად, მან მესამე უჯრაზე დაწყობილი ბრილიანტები უნდა შეინახოს მეხუთე უჯრაზე, რათა გამყოფი არ დაეკარგოს. როდესაც სრულად გამოაკლებს ბრილიანტებს,ამის შემდეგ მან შედეგი უნდა გაზარდოს ერთი ბრილიანტით მეოთხე უჯრაზე. ამას იმდენჯერ გააკეთებს რამდენჯერაც მოთავსდება m n-ში. (m-მესამე უჯრაზე დალაგებული ბრილიანტები, n-მეორე უჯრაზე დალაგებული ბრილიანტები) +შესაბამისად, მივიღებთ კოდს: +```java +while (beepersPresent()) { + subtractOperation(); +} +``` +```java +pickBeeper(); +turnAround(); +move(); +pickBeeper(); +turnAround(); +move(); +move(); +move(); +putBeeper(); +turnAround(); +move(); +move(); +turnAround(); +``` +> *როდესაც მესამე უჯრაზე აღარ აღმოჩნდება ბრილიანტები, `beepersPresent()` მეთოდი `while` ციკლს შეატყობინებს, რომ ამ უჯრაზე აღარ არის ბრილიანტები და კარელი გააკეთებს სხვა სვლას (ციკლი დასრულდება).* +--- +### საბოლოო შედეგის გაზრდა და თანდათანობითი გამოთვლა მეოთხე უჯრაზე. +1. ყოველი გამოკლების ოპერაციის შესრულების შემდეგ კარელმა ბრილიანტი უნდა დადოს მეოთხე უჯრაზე, +საბოლოო პასუხის გამოსათვლელად. +```java +move(); +putBeeper(); +move(); +``` +### მეხუთე უჯრაზე დალაგებული ბრილიანტების მესამე უჯრაზე დაბრუნება +ახლა,როდესაც კარელმა წარმატებით გამოაკლო მესამე უჯრაზე მყოფი ბრილიანტები მეორე უჯრაზე მყოფს, მან უნდა დაიწყოს ეს ოპერაცია თავიდან, გვახსოვდეს რომ ეს უნდა გაკეთდეს იმდენჯერ სანამ მეორე უჯრაზე მყოფი ბრილიანტები სრულიად არ დაიცლება. ამისათვის მეხუთე უჯრაზე შენახულ ბრილიანტებს დავაბრუნებთ მესამე უჯრაზე. +1. გამოვიყენოთ კარელისათვის ცნობილი `beepersPresent()` მეთოდი. +2. გამოვიყენოთ `while` ციკლი. +შესაბამისად, მივიღებთ კოდს: +```java +while (beepersPresent()) { + pickBeeper(); + turnAround(); + move(); + move(); + putBeeper(); + turnAround(); + move(); + move(); +} +``` +### დაბრუნდეთ მეორე უჯრაზე, რათა გამოკლების ოპერაცია თავიდან დავიწყოთ და ამოვწუროთ ამ უჯრაზე დალაგებული ბრილიანტების რაოდენობა +```java +turnAround(); +move(); +move(); +move(); +turnAround(); +``` +### მესამე უჯრაზე ბრილიანტების აღება და საბოლოო პასუხის დაფიქსირება +ამ ეტაპისთვის ჩვენ უკვე დავალაგეთ მეოთხე უჯრაზე ბიპერების ის რაოდენობა, რომელიც სწორ პასუხს შეესაბამება, რადგან ჩვენ ზუსტად იმდენჯერ გამოვაკელით მეორე უჯრაზე მყოფ ბრილიანტებს, მესამე უჯრაზე მყოფი, რამდენჯერაც მოთავსდა. საბოლოო პასუხის დასაფიქსირებლად გვჭირდება, მესამე უჯრიდან ავკრიფოთ დარჩენილი ბრილიანტები, რათა **მხოლოდ მეოთხეზე** დარჩეს სწორი პასუხი. +1. გამოვიყენოთ კარელისათვის ცნობილი `beepersPresent()` მეთოდი. +2. გამოვიყენოთ `while` ციკლი. +შესაბამისად, მივიღებთ კოდს: +```java +move(); +while (beepersPresent()) { + pickBeeper(); +} +``` +## რატომ დაგვჭირდა ამდენი მოქმედება მხოლოდ ერთი გამოკლების ოპერაციისთვის? +* ამოცანას ართულებს ის ფაქტი, რომ ჩვენ ჩანთაში უსასრულო რაოდენობის ბიპერები გვაქვს, და ვერ შეძლებს ჩვენი რობოტი კარელი, ზუსტად დაითვალოს, რამდენი ბრილიანტი აიღო ან დადო გარკვეულ უჯრაზე. ამისათვის დაგვჭირდა მეხუთე უჯრაზე ბრილიანტების შენახვის ოპერაცია, რომელიც ჩემი აზრით ერთ-ერთი საკვანძო მოქმედებაა ამ ამოცანაში. +--- +## შესაძლო ხარვეზები ამოხსნის იმპლემენტაციისას +პირველ რიგში, მინდა მოგილოცოთ პროგრამის წარმატებით დასრულება და იმპლემენტაცია. რა თქმა უნდა თითოეულ ჩვენგანს შეუძლია ამ ამოცანის ამოხსნის ლოგიკის პოვნა, თუმცა მნიშვნელოვანია არ აგვერიოს თუ სად დგას და საით იყურება კარელი თითოეული მოქმედების დასრულების შემდეგ. ეს მნიშვნელოვანია,რადგან ციკლებმა გამართულად იმუშაოს. + + diff --git a/problem-set/NumberOfNames.java b/problem-set/NumberOfNames.java new file mode 100644 index 0000000..c6fd814 --- /dev/null +++ b/problem-set/NumberOfNames.java @@ -0,0 +1,33 @@ +import java.util.HashMap; + +import acm.program.ConsoleProgram; +import stanford.karel.SuperKarel; + +public class NumberOfNames extends ConsoleProgram { + public void run() { + HashMap myHashMap = new HashMap<>(); + buildHashMap(myHashMap); + writeStatistics(myHashMap); + } + + private void buildHashMap(HashMap myHashMap) { + while (true) { + String str = readLine("Enter a word: "); + if (str.equals("")) + break; + if (myHashMap.containsKey(str)) { + int frequency = myHashMap.get(str); + frequency += 1; + myHashMap.put(str, frequency); + } else { + myHashMap.put(str, 1); + } + } + } + + private void writeStatistics(HashMap myHashMap) { + for (String word : myHashMap.keySet()) { + println(word + " occurs " + myHashMap.get(word) + " times."); + } + } +} \ No newline at end of file diff --git a/problem-set/NumberOfNames.md b/problem-set/NumberOfNames.md new file mode 100644 index 0000000..b683969 --- /dev/null +++ b/problem-set/NumberOfNames.md @@ -0,0 +1,43 @@ +# NumberOfNames +პრობლემა: +``` +კონსოლიდან შეგვყავს სახელები, მანამ სანამ არ შევიყვანთ ცარიელ სტრინგს. დაბეჭდეთ +სახელი და მის გასწვრივ რაოდენობა რამდენჯერ შევიყვანეთ ეს სახელი. +``` +## პრობლემის გადაჭრის გზა +ჩვენი ამოცანა მოიცავს ორ ძირითად ნაწილს და აუცილებელია განვიხილოთ თითოეული წარმატების მისაღწევად. +* ჩვენთვის ნაცნობი სტრუქტურის `HashMap`-ის აგება და სიტყვების დათვლა. +* გამოვიტანოთ თითოეული სიტყვის სტატისტიკა, თუ რამდენჯერ გვხვდება თითოეული სიტყვა. +--- +## პრობლემის გადაჭრის ალგორითმი +* ჩვენი ამოცანის წარმატებით გადასაჭრელად გვეხმარება ნაცნობი სტრუქტურა `HashMap` და მისი მძლავრი მეთოდი `containsKey()`. ამოცანის თანახმად +შევიყვანთ სიტყვებს, მანამდე სანამ მომხმარებელი არ შეიყვანს ცარიელ სტრინგს. ამ მეთოდის დახმარებით, მოვახერხებთ მივხვდეთ, ეს სიტყვა უკვე შევიყვანეთ თუ არა. თუ უკვე შევინახეთ, მაშინ ამოვიღოთ ის რაოდენობა, რომელიც გვიჩვენებს, თუ რამდენჯერ შეგვხვდა ის სიტყვა აქამდე, გავზარდოთ ერთით და ისევ ჩავამატოთ. +წინააღმდეგ შემთხვევაში ჩავაგდოთ სიტყვა სტრუქტურაში რაოდენობით ერთი. +--- +### ნაცნობი სტრუქტურის `HashMap`-ის აგება და რაოდენობების დათვლა +1. გავაკეთოთ `HashMap` ინიციალიზაცია და გამოვიყენოთ მისი ფუნქცია:`containsKey()` +2. გამოვიყენოთ `while` ციკლი. +3.`while` და მეთოდი `containsKey()`, ზუსტად შეგვიდგენს ამოცანისთვის საჭირო სტრუქტურას,რომელსაც შემდგომში გამოვიტანთ. ციკლი იქამდე იმუშავებს სანამ მომხმარებელი არ შეიყვანს ცარიელ სიტყვას. რადგან `HashMap` სტრუქტურა ინახავს უნიკალურ სიტყვებს, ერთი და იგივე სიტყვას არ ჩააგდებს ორჯერ, ის მხოლოდ რაოდენობას გაზრდის. ქვემოთ ნაჩვენები კოდი, ხსნის ამოცანის მთავარ ალგორითმს. +```java +if (myHashMap.containsKey(str)) { + int frequency = myHashMap.get(str); + frequency += 1; + myHashMap.put(str, frequency); +} else { + myHashMap.put(str, 1); +} +``` +--- +### გამოვიტანოთ თითოეული სიტყვის სტატისტიკა, თუ რამდენჯერ გვხვდება თითოეული სიტყვა. +1. სიტყვების გადაყოლა ხდება მეთოდით `foreach` ციკლით, რომელიც გვეხმარება გადავუყვეთ პირდაპირ სტრუქტურაში ჩამატებულ სიტყვებს.`get` მეთოდი +კი გვეხმარება ამოვიღოთ ამ სიტყვის შესაბამისი რაოდენობა. შემდეგ ის დავბეჭდოთ. +```java +for (String word : myHashMap.keySet()) { + println(word + " occurs " + myHashMap.get(word) + " times."); +} +``` +## რატომ არის მნიშვნელოვანი ჰეშმეპის სტრუქტურის გამოყენება? +* ეს სტრუქტურა რომ არ არსებობდეს, ჩვენ გაგვიჭირდებოდა ამოცანის მარტივად ამოხსნა. ამ სტრუქტურას აქვს თვისება, შეინახოს უნიკალური ინფორმაცია, და თანაც +მას შეუსაბამოს ჩვენთვის საჭირო მნიშვნელობა. ჩვენ შემთხვევაში იყო სიტყვები და მათი შეყვანის რაოდენობა. + + diff --git a/problem-set/NumberOfWords.java b/problem-set/NumberOfWords.java new file mode 100644 index 0000000..4fc661a --- /dev/null +++ b/problem-set/NumberOfWords.java @@ -0,0 +1,20 @@ +import java.util.StringTokenizer; + +import acm.program.ConsoleProgram; + +public class NumberOfWords extends ConsoleProgram { + public void run() { + String userWord = readLine(); + println(getWordNum(userWord)); + } + + private int getWordNum(String userWord) { + StringTokenizer tok = new StringTokenizer(userWord); + int result = 0; + while(tok.hasMoreTokens()) { + tok.nextToken(); + result++; + } + return result; + } +} \ No newline at end of file diff --git a/problem-set/NumberOfWords.md b/problem-set/NumberOfWords.md new file mode 100644 index 0000000..04cb834 --- /dev/null +++ b/problem-set/NumberOfWords.md @@ -0,0 +1,40 @@ +# NumberOfWords +პრობლემა: +``` +შეყვანილ ტექსტში დათვალეთ სიტვყების რაოდენობა, ტოკენაიზერის საშუალებით. +``` +## პრობლემის გადაჭრის გზა +ჩვენი ამოცანა მოიცავს ორ ძირითად ნაწილს და აუცილებელია განვიხილოთ თითოეული წარმატების მისაღწევად. +* ტოკენაიზერის და ტოკენაიზერის ფუნქციის სწორად გამოყენება +* სიტყვების დათვლა +--- +### ტოკენაიზერის და ტოკენაიზერის ფუნქციის სწორად გამოყენება. +1. გავაკეთოთ ტოკენაიზერ კლასის ინიციალიზაცია და გამოვიყენოთ მისი ფუნქცია:`hasMoreTokens()` +2. გამოვიყენოთ `while` ციკლი. +3.`while` და მეთოდი `hasMoreTokens`, ზუსტად იპოვის ჩვენი ამოცანის საბოლოო პასუხს. ციკლი იქამდე იმუშავებს სანამ გვაქვს ტოკენები. უფრო +მარტივად რომ ვთქვათ, ტოკენაიზერისთვის ტოკენი ნიშნავს სიტყვას და ის მხოლოდ სიტყვებს გადაუყვება ჩვენ წინადადებაში.`hasMoreTokens`-აბრუნებს `true` მნიშვნელობას თუ ტექსტში დარჩა რაიმე სიტყვა, წინააღმდეგ შემთხვევაში აბრუნებს `false`. +```java +while(tok.hasMoreTokens()) { + tok.nextToken(); + result++; +} +``` +--- +### სიტყვების დათვლა `StringTokenizer`-ის მეთოდის დახმარებით. +1. სიტყვების გადაყოლა ხდება მეთოდით `nextToken()`, რაც ჩვენ ტოკენაიზერს მომდევნო სიტყვაზე გადაიყვანს. ჩვენ მხოლოდ გვჭირდება `int` ცვლადი, რასაც ყოველი ციკლის იტერაციის დროს გავზრდით და საბოლოოდ დავაბრუნებთ პასუხს. +```java +int result = 0; +while(tok.hasMoreTokens()) { + tok.nextToken(); + result++; +} +``` +## რატომ არის მნიშვნელოვანი ტოკენაიზერ კლასის გამოყენება? +* ეს კლასი რომ არ არსებობდეს ჩვენ დაგვჭირდებოდა ტექსტში, ჩვენით(მექანიკურად) გამოგვეყო ერთმანეთისგან სიტყვები და დაგვეთვალა ისინი. ჩვენს მაგივრად +ამას კლასში ჩაშენებული მეთოდი აკეთებს. +--- +## შესაძლო ხარვეზები ამოხსნის იმპლემენტაციისას +პირველ რიგში,როდესაც ვიყენებთ მეთოდს `hasMoreTokens`, აუცილებელია ციკლში დავწეროთ ამ კლასის ერთი მნიშვნელოვანი მეთოდი, რადგან ტოკენაიზერმა +სვლა განაგრძოს ჩვენ წინადადებაში. ეს ხშირად ავიწყდებათ, რის გამოც ჩვენ აუცილებლად დავაბრუნებთ არასწორ პასუხს. + + diff --git a/problem-set/Sum1N.java b/problem-set/Sum1N.java new file mode 100644 index 0000000..cc72600 --- /dev/null +++ b/problem-set/Sum1N.java @@ -0,0 +1,18 @@ +import acm.program.ConsoleProgram; +/* + * File: Sum1N.java + * ----------------- + * In this problem, we read a number and then calculate the sum from 1 to n. + * Problem review: read an integer N, then print the sum of the numbers from 1 to n. + */ + +public class Sum1N extends ConsoleProgram { + public void run() { + int n = readInt(); // user inputs an integer n. + int sum = 0; // define variable which will store result. + for (int i = 1; i < n; i++) { + sum += i; // start from 1 to n, add each number in variable sum. + } + println(sum); + } +} diff --git a/problem-set/Sum1N.md b/problem-set/Sum1N.md new file mode 100644 index 0000000..86c578f --- /dev/null +++ b/problem-set/Sum1N.md @@ -0,0 +1,31 @@ +# Sum1N +პრობლემა: +``` +მომხმარებელს შეყავს მთელი რიცხვი n, პროგრამამ უნდა დაბეჭდოს 1 დან n მდე რიცხვების +ჯამი +``` +## პრობლემის გადაჭრის გზა +პირველ რიგში ჩვენი პრობლემა დავყოთ ორ ნაწილად +* შევქმნათ ცვლადი რომელიც შეინახავს რიცხვების ჯამს და საბოლოოდ მაგ ცვლადში არსებულ მნიშვნელობას დავბეჭდავთ. +* ჩვენთვის ნაცნობი `for` ციკლით, გადავუყვეთ 1-დან n-მდე ყველა რიცხვს და დავუმატოთ უკვე არსებულ ცვლადში, რომელსაც საბოლოოდ დავბეჭდავთ. +--- +### რიცხვის წაკითხვა და ცვლადის შექმნა რომელიც შეინახავს საბოლოო ჯამის მნიშვნელობას. +1. `readInt` ფუნქციის მეშვეობით წავიკითხოთ რიცხვი და ჩავწეროთ ის `int` ცვლადში. +2. შევქმნათ `int` ცვლადი, რომელსაც მივანიჭებთ თავდაპირველ მნიშვნელობას 0-ს. +```java +int n = readInt(); +int sum = 0; +``` +--- +### მთავარი ოპერაცია, რიცხვების გადაყოლა 1 დან იმ რიცხვამდე, რომელიც ჩვენ წავიკითხეთ. ვზარდოთ ყოველჯერზე ცვლადის მნიშვნელობა. +```java +for (int i = 1; i < n; i++) { + sum += i; +} +``` +### მონაცემების დაბეჭდვა და ამოცანის დასრულება +```java +println(sum); +``` +ამ ეტაპისთვის ამოცანა სრულიად წარმატებით მუშაობს. ერთადერთი გაუმჯობესება რაც შეიძლება მოვიფიქროთ არის ის რომ,`for` ციკლი უნდა დავიწყოთ 1 დან. ძირითად შემთხვევებში ციკლი 0-დან იწყება. ამ შემთხვევაში 0-დან დაწყება საბოლოო პასუხში არაფერს არ შეცვლის და ამიტომ ჩვენ ერთით ზედმეტ ოპერაციას შევასრულებთ. +