diff --git a/src/lesson1/task1/Simple.kt b/src/lesson1/task1/Simple.kt index 161e9a5cc..c73bfaa7f 100644 --- a/src/lesson1/task1/Simple.kt +++ b/src/lesson1/task1/Simple.kt @@ -51,7 +51,7 @@ fun main(args: Array) { * Пользователь задает время в часах, минутах и секундах, например, 8:20:35. * Рассчитать время в секундах, прошедшее с начала суток (30035 в данном случае). */ -fun seconds(hours: Int, minutes: Int, seconds: Int): Int = TODO() +fun seconds(hours: Int, minutes: Int, seconds: Int): Int = hours * 3600 + minutes * 60 + seconds /** * Тривиальная @@ -60,7 +60,7 @@ fun seconds(hours: Int, minutes: Int, seconds: Int): Int = TODO() * Определить длину того же отрезка в метрах (в данном случае 18.98). * 1 сажень = 3 аршина = 48 вершков, 1 вершок = 4.445 см. */ -fun lengthInMeters(sagenes: Int, arshins: Int, vershoks: Int): Double = TODO() +fun lengthInMeters(sagenes: Int, arshins: Int, vershoks: Int): Double = (sagenes * 48 + arshins * 16 + vershoks) * 4.445 / 100 /** * Тривиальная @@ -68,7 +68,7 @@ fun lengthInMeters(sagenes: Int, arshins: Int, vershoks: Int): Double = TODO() * Пользователь задает угол в градусах, минутах и секундах (например, 36 градусов 14 минут 35 секунд). * Вывести значение того же угла в радианах (например, 0.63256). */ -fun angleInRadian(grad: Int, min: Int, sec: Int): Double = TODO() +fun angleInRadian(grad: Int, min: Int, sec: Int): Double = (grad + min / 60.0 + sec / 3600.0) * PI / 180 /** * Тривиальная @@ -76,7 +76,7 @@ fun angleInRadian(grad: Int, min: Int, sec: Int): Double = TODO() * Найти длину отрезка, соединяющего точки на плоскости с координатами (x1, y1) и (x2, y2). * Например, расстояние между (3, 0) и (0, 4) равно 5 */ -fun trackLength(x1: Double, y1: Double, x2: Double, y2: Double): Double = TODO() +fun trackLength(x1: Double, y1: Double, x2: Double, y2: Double): Double = sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) /** * Простая @@ -84,7 +84,7 @@ fun trackLength(x1: Double, y1: Double, x2: Double, y2: Double): Double = TODO() * Пользователь задает целое число, большее 100 (например, 3801). * Определить третью цифру справа в этом числе (в данном случае 8). */ -fun thirdDigit(number: Int): Int = TODO() +fun thirdDigit(number: Int): Int = (number % 1000 - number % 100) / 100 /** * Простая @@ -93,7 +93,9 @@ fun thirdDigit(number: Int): Int = TODO() * прибыл на станцию назначения в h2 часов m2 минут того же дня (например в 13:01). * Определите время поезда в пути в минутах (в данном случае 216). */ -fun travelMinutes(hoursDepart: Int, minutesDepart: Int, hoursArrive: Int, minutesArrive: Int): Int = TODO() +fun travelMinutes(hoursDepart: Int, minutesDepart: Int, hoursArrive: Int, minutesArrive: Int): Int = + (hoursArrive * 60 + minutesArrive) - (hoursDepart * 60 + minutesDepart) + /** * Простая @@ -102,7 +104,10 @@ fun travelMinutes(hoursDepart: Int, minutesDepart: Int, hoursArrive: Int, minute * Сколько денег будет на счету через 3 года (с учётом сложных процентов)? * Например, 100 рублей под 10% годовых превратятся в 133.1 рубля */ -fun accountInThreeYears(initial: Int, percent: Int): Double = TODO() +fun accountInThreeYears(initial: Int, percent: Int): Double { + val per = 1 + percent/ 100.0 + return initial * per * per * per +} /** * Простая @@ -110,4 +115,12 @@ fun accountInThreeYears(initial: Int, percent: Int): Double = TODO() * Пользователь задает целое трехзначное число (например, 478). *Необходимо вывести число, полученное из заданного перестановкой цифр в обратном порядке (например, 874). */ -fun numberRevert(number: Int): Int = TODO() +fun numberRevert(number: Int): Int { + var n = number + var result = 0 + while (n > 0) { + result = result * 10 + n % 10 + n /= 10 + } + return result +} diff --git a/src/lesson2/task1/IfElse.kt b/src/lesson2/task1/IfElse.kt index 10664b8b4..a35421005 100644 --- a/src/lesson2/task1/IfElse.kt +++ b/src/lesson2/task1/IfElse.kt @@ -2,6 +2,8 @@ package lesson2.task1 import lesson1.task1.discriminant +import lesson1.task1.sqr +import java.lang.Math.* /** * Пример @@ -33,7 +35,15 @@ fun minBiRoot(a: Double, b: Double, c: Double): Double { * Мой возраст. Для заданного 0 < n < 200, рассматриваемого как возраст человека, * вернуть строку вида: «21 год», «32 года», «12 лет». */ -fun ageDescription(age: Int): String = TODO() +fun ageDescription(age: Int): String = + when { + age % 100 in 5..20 -> "$age лет" + age % 10 == 0 -> "$age лет" + age % 10 > 4 -> "$age лет" + age % 10 == 1 -> "$age год" + else -> "$age года" + } + /** * Простая @@ -44,7 +54,17 @@ fun ageDescription(age: Int): String = TODO() */ fun timeForHalfWay(t1: Double, v1: Double, t2: Double, v2: Double, - t3: Double, v3: Double): Double = TODO() + t3: Double, v3: Double): Double { + val first = t1 * v1 + val sec = t2 * v2 + val third = t3 * v3 + val path = (first + sec + third) / 2 + return when { + first >= path -> path / v1 + first + sec >= path -> t1 + (path - first) / v2 + else -> t1 + t2 + (path - first - sec) / v3 + } +} /** * Простая @@ -56,7 +76,16 @@ fun timeForHalfWay(t1: Double, v1: Double, */ fun whichRookThreatens(kingX: Int, kingY: Int, rookX1: Int, rookY1: Int, - rookX2: Int, rookY2: Int): Int = TODO() + rookX2: Int, rookY2: Int): Int { + val rook1 = (rookX1==kingX || rookY1==kingY) + val rook2 = (rookX2==kingX || rookY2==kingY) + return when { + (rook1 && rook2) -> 3 + rook2 -> 2 + rook1 -> 1 + else -> 0 + } +} /** * Простая @@ -69,7 +98,15 @@ fun whichRookThreatens(kingX: Int, kingY: Int, */ fun rookOrBishopThreatens(kingX: Int, kingY: Int, rookX: Int, rookY: Int, - bishopX: Int, bishopY: Int): Int = TODO() + bishopX: Int, bishopY: Int): Int { + val rook = (kingX == rookX || kingY == rookY) + val bish = (abs(kingX - bishopX) == abs(kingY - bishopY)) + return when { + rook && bish -> 3 + bish -> 2 + rook -> 1 + else -> 0 } +} /** * Простая @@ -79,7 +116,18 @@ fun rookOrBishopThreatens(kingX: Int, kingY: Int, * прямоугольным (вернуть 1) или тупоугольным (вернуть 2). * Если такой треугольник не существует, вернуть -1. */ -fun triangleKind(a: Double, b: Double, c: Double): Int = TODO() + +fun triangleKind(a: Double, b: Double, c: Double): Int { + val arr = doubleArrayOf(a,b,c).sorted() + if (arr[2] <= arr[1] + arr[0]) { + val d = sqr(arr[2]) - (sqr(arr[1]) + sqr(arr[0])) + when { + d < 0 -> return 0 + d > 0 -> return 2 + else -> return 1 + } + } else return -1 +} /** * Средняя @@ -89,4 +137,12 @@ fun triangleKind(a: Double, b: Double, c: Double): Int = TODO() * Найти длину пересечения отрезков AB и CD. * Если пересечения нет, вернуть -1. */ -fun segmentLength(a: Int, b: Int, c: Int, d: Int): Int = TODO() \ No newline at end of file +fun segmentLength(a: Int, b: Int, c: Int, d: Int): Int = + when { + c <= a && d >= a && d <= b -> d - a + c <= a && d >= b -> b - a + c >= a && d <= b -> d - c + c <= b && c >= a && d >= b -> b - c + else -> -1 + + } diff --git a/src/lesson2/task2/Logical.kt b/src/lesson2/task2/Logical.kt index 209f0f39c..750a4701b 100644 --- a/src/lesson2/task2/Logical.kt +++ b/src/lesson2/task2/Logical.kt @@ -2,6 +2,7 @@ package lesson2.task2 import lesson1.task1.sqr +import java.lang.Math.* /** * Пример @@ -17,7 +18,10 @@ fun pointInsideCircle(x: Double, y: Double, x0: Double, y0: Double, r: Double) = * Четырехзначное число назовем счастливым, если сумма первых двух ее цифр равна сумме двух последних. * Определить, счастливое ли заданное число, вернуть true, если это так. */ -fun isNumberHappy(number: Int): Boolean = TODO() +fun isNumberHappy(number: Int): Boolean { + val str = number.toString() + return str[0].toInt() + str[1].toInt() == str[2].toInt() + str[3].toInt() +} /** * Простая @@ -25,7 +29,7 @@ fun isNumberHappy(number: Int): Boolean = TODO() * На шахматной доске стоят два ферзя (ферзь бьет по вертикали, горизонтали и диагоналям). * Определить, угрожают ли они друг другу. Вернуть true, если угрожают. */ -fun queenThreatens(x1: Int, y1: Int, x2: Int, y2: Int): Boolean = TODO() +fun queenThreatens(x1: Int, y1: Int, x2: Int, y2: Int): Boolean = (x1 == x2) || (y1 == y2) || (abs(y2 - y1) == abs((x2 - x1))) /** * Средняя @@ -35,7 +39,8 @@ fun queenThreatens(x1: Int, y1: Int, x2: Int, y2: Int): Boolean = TODO() * Вернуть true, если утверждение верно */ fun circleInside(x1: Double, y1: Double, r1: Double, - x2: Double, y2: Double, r2: Double): Boolean = TODO() + x2: Double, y2: Double, r2: Double): Boolean = sqrt(sqr(x2-x1) + sqr(y2-y1)) + r1 <= r2 + /** * Средняя @@ -46,4 +51,7 @@ fun circleInside(x1: Double, y1: Double, r1: Double, * кирпич 4 х 4 х 4 пройдёт через отверстие 4 х 4. * Вернуть true, если кирпич пройдёт */ -fun brickPasses(a: Int, b: Int, c: Int, r: Int, s: Int): Boolean = TODO() +fun brickPasses(a: Int, b: Int, c: Int, r: Int, s: Int): Boolean { + val values = intArrayOf(a,b,c).sorted() + return (values[0] <= min(r,s) && values[1] <= max(r,s)) +} \ No newline at end of file diff --git a/src/lesson3/task1/Loop.kt b/src/lesson3/task1/Loop.kt index a39673edf..4039dd463 100644 --- a/src/lesson3/task1/Loop.kt +++ b/src/lesson3/task1/Loop.kt @@ -1,6 +1,8 @@ @file:Suppress("UNUSED_PARAMETER") package lesson3.task1 +import java.lang.Math.* + /** * Пример * @@ -21,7 +23,7 @@ fun factorial(n: Int): Double { */ fun isPrime(n: Int): Boolean { if (n < 2) return false - for (m in 2..Math.sqrt(n.toDouble()).toInt()) { + for (m in 2..sqrt(n.toDouble()).toInt()) { if (n % m == 0) return false } return true @@ -57,15 +59,35 @@ fun digitCountInNumber(n: Int, m: Int): Int = * Найти количество цифр в заданном числе n. * Например, число 1 содержит 1 цифру, 456 -- 3 цифры, 65536 -- 5 цифр. */ -fun digitNumber(n: Int): Int = TODO() - +fun digitNumber(n: Int): Int { + if (n == 0) return 1 + else { + var num = n + var count = 0 + while (num != 0) { + num /= 10 + count ++ + } + return count + } +} /** * Простая * * Найти число Фибоначчи из ряда 1, 1, 2, 3, 5, 8, 13, 21, ... с номером n. * Ряд Фибоначчи определён следующим образом: fib(1) = 1, fib(2) = 1, fib(n+2) = fib(n) + fib(n+1) */ -fun fib(n: Int): Int = TODO() +fun fib(n: Int): Int { + var beforePrevious = 1 + var previous = 0 + var num = 0 + for (i in 1..n) { + num = beforePrevious + previous + beforePrevious = previous + previous = num + } + return num +} /** * Простая @@ -73,21 +95,49 @@ fun fib(n: Int): Int = TODO() * Для заданных чисел m и n найти наименьшее общее кратное, то есть, * минимальное число k, которое делится и на m и на n без остатка */ -fun lcm(m: Int, n: Int): Int = TODO() +//Нахождение НОД, для дальнейшего поиска НОК +fun nod(m: Int, n: Int): Int { + var a = m + var b = n + while (b != 0) { + val tmp = a % b + a = b + b = tmp + } + return a +} + +fun lcm(m: Int, n: Int): Int = n * m / nod(m, n) + /** * Простая * * Для заданного числа n > 1 найти минимальный делитель, превышающий 1 */ -fun minDivisor(n: Int): Int = TODO() +fun minDivisor(n: Int): Int { + //Не совсем понял, какая тут более точная граница? + for (i in 2..sqrt(n.toDouble()).toInt()) { + if (n%i == 0) { + return i + } + } + return n +} /** * Простая * * Для заданного числа n > 1 найти максимальный делитель, меньший n */ -fun maxDivisor(n: Int): Int = TODO() +fun maxDivisor(n: Int): Int { + for (i in n/2 downTo sqrt(n.toDouble()).toInt()) { + if (n%i == 0) { + return i + } + } + return 1 +} /** * Простая @@ -96,7 +146,7 @@ fun maxDivisor(n: Int): Int = TODO() * Взаимно простые числа не имеют общих делителей, кроме 1. * Например, 25 и 49 взаимно простые, а 6 и 8 -- нет. */ -fun isCoPrime(m: Int, n: Int): Boolean = TODO() +fun isCoPrime(m: Int, n: Int): Boolean = nod(m,n) == 1 /** * Простая @@ -105,7 +155,12 @@ fun isCoPrime(m: Int, n: Int): Boolean = TODO() * то есть, существует ли такое целое k, что m <= k*k <= n. * Например, для интервала 21..28 21 <= 5*5 <= 28, а для интервала 51..61 квадрата не существует. */ -fun squareBetweenExists(m: Int, n: Int): Boolean = TODO() +fun squareBetweenExists(m: Int, n: Int): Boolean { + var i = ceil(sqrt(m.toDouble())) + i *= i + return i >= m && i <= n + +} /** * Простая @@ -114,7 +169,21 @@ fun squareBetweenExists(m: Int, n: Int): Boolean = TODO() * sin(x) = x - x^3 / 3! + x^5 / 5! - x^7 / 7! + ... * Нужную точность считать достигнутой, если очередной член ряда меньше eps по модулю */ -fun sin(x: Double, eps: Double): Double = TODO() +fun sin(x: Double, eps: Double): Double { + var i = 1 + val xn = x % (2 * PI) + var sin = x * x * x / 6 + var element = x + while (element > eps) { + if (i%2 == 1) + sin -= element + else + sin += element + i++ + element = pow(xn,(1 + i * 2.0)) / factorial( 1 + i * 2) + } + return sin +} /** * Простая @@ -123,7 +192,21 @@ fun sin(x: Double, eps: Double): Double = TODO() * cos(x) = 1 - x^2 / 2! + x^4 / 4! - x^6 / 6! + ... * Нужную точность считать достигнутой, если очередной член ряда меньше eps по модулю */ -fun cos(x: Double, eps: Double): Double = TODO() +fun cos(x: Double, eps: Double): Double { + var i = 1 + val xn = x % (2 * PI) + var cos = 1.0 + var element = x * x / 2 + while (element > eps) { + if (i%2 == 1) + cos -= element + else + cos += element + i++ + element = pow(xn,(1 + i * 2.0)) / factorial( 1 + i * 2) + } + return cos +} /** * Средняя @@ -131,7 +214,16 @@ fun cos(x: Double, eps: Double): Double = TODO() * Поменять порядок цифр заданного числа n на обратный: 13478 -> 87431. * Не использовать строки при решении задачи. */ -fun revert(n: Int): Int = TODO() +fun revert(n: Int): Int { + var new = 0 + var number = n + while (number > 0) { + new *= 10 + new += number%10 + number /= 10 + } + return new +} /** * Средняя @@ -140,7 +232,8 @@ fun revert(n: Int): Int = TODO() * первая цифра равна последней, вторая -- предпоследней и так далее. * 15751 -- палиндром, 3653 -- нет. */ -fun isPalindrome(n: Int): Boolean = TODO() +fun isPalindrome(n: Int): Boolean = n == revert(n) + /** * Средняя @@ -148,7 +241,18 @@ fun isPalindrome(n: Int): Boolean = TODO() * Для заданного числа n определить, содержит ли оно различающиеся цифры. * Например, 54 и 323 состоят из разных цифр, а 111 и 0 из одинаковых. */ -fun hasDifferentDigits(n: Int): Boolean = TODO() +fun hasDifferentDigits(n: Int): Boolean { + var num = n + val lastNum = num % 10 + while (num != 0){ + if (lastNum != num % 10) { + return true + } + num /= 10 + } + return false + +} /** * Сложная @@ -157,7 +261,19 @@ fun hasDifferentDigits(n: Int): Boolean = TODO() * 149162536496481100121144... * Например, 2-я цифра равна 4, 7-я 5, 12-я 6. */ -fun squareSequenceDigit(n: Int): Int = TODO() +fun squareSequenceDigit(n: Int): Int { + var i = 1 + var pointer = 0 + while (pointer < n){ + val iSqr = i*i + val currentLength = pointer + digitNumber(iSqr) + if (currentLength >= n) + return (iSqr).toString()[n-pointer-1] - '0' + pointer = currentLength + i++ + } + return 0 +} /** * Сложная @@ -166,4 +282,16 @@ fun squareSequenceDigit(n: Int): Int = TODO() * 1123581321345589144... * Например, 2-я цифра равна 1, 9-я 2, 14-я 5. */ -fun fibSequenceDigit(n: Int): Int = TODO() +fun fibSequenceDigit(n: Int): Int { + var i = 1 + var pointer = 0 + while (pointer < n){ + val fib = fib(i) + val currentLength = pointer + digitNumber(fib) + if (currentLength >= n) + return fib.toString()[n-pointer-1] - '0' + pointer = currentLength + i++ + } + return 0 +} \ No newline at end of file diff --git a/src/lesson4/task1/List.kt b/src/lesson4/task1/List.kt index c7dee32da..761d6819c 100644 --- a/src/lesson4/task1/List.kt +++ b/src/lesson4/task1/List.kt @@ -2,12 +2,28 @@ package lesson4.task1 import lesson1.task1.discriminant +import java.lang.Math.* +val chars = "0123456789abcdefghijklmnopqrstuvwxyz" + +fun pow (x: Int, n: Int): Int { + var num = 1 + var ink = x + var power = n + while (power != 0) { + if (power%2 == 1) + num *= ink + ink *= ink + power = power.shr(1) + } + return num +} /** * Пример * * Найти все корни уравнения x^2 = y */ + fun sqRoots(y: Double) = if (y < 0) listOf() else if (y == 0.0) listOf(0.0) @@ -104,14 +120,16 @@ fun buildSumExample(list: List) = list.joinToString(separator = " + ", post * по формуле abs = sqrt(a1^2 + a2^2 + ... + aN^2). * Модуль пустого вектора считать равным 0.0. */ -fun abs(v: List): Double = TODO() +fun abs(v: List): Double = sqrt(v.sumByDouble{it*it}) /** * Простая * * Рассчитать среднее арифметическое элементов списка list. Вернуть 0.0, если список пуст */ -fun mean(list: List): Double = TODO() +fun mean(list: List): Double = + if (list.isEmpty()) 0.0 + else list.sum()/list.count() /** * Средняя @@ -119,8 +137,11 @@ fun mean(list: List): Double = TODO() * Центрировать заданный список list, уменьшив каждый элемент на среднее арифметическое всех элементов. * Если список пуст, не делать ничего. Вернуть изменённый список. */ -fun center(list: MutableList): MutableList = TODO() - +fun center(list: MutableList): MutableList { + val c = list.sum() / list.count() + list.forEachIndexed { i, d -> list[i] -= c } + return list +} /** * Средняя * @@ -128,7 +149,7 @@ fun center(list: MutableList): MutableList = TODO() * представленные в виде списков a и b. Скалярное произведение считать по формуле: * C = a1b1 + a2b2 + ... + aNbN. Произведение пустых векторов считать равным 0.0. */ -fun times(a: List, b: List): Double = TODO() +fun times(a: List, b: List): Double = a.zip(b, { R,T -> R * T }).sum() /** * Средняя @@ -138,7 +159,7 @@ fun times(a: List, b: List): Double = TODO() * Коэффициенты многочлена заданы списком p: (p0, p1, p2, p3, ..., pN). * Значение пустого многочлена равно 0.0 при любом x. */ -fun polynom(p: List, x: Double): Double = TODO() +fun polynom(p: List, x: Double): Double = p.mapIndexed { i, d -> d * pow(x, i.toDouble()) }.sum() /** * Средняя @@ -148,7 +169,10 @@ fun polynom(p: List, x: Double): Double = TODO() * Например: 1, 2, 3, 4 -> 1, 3, 6, 10. * Пустой список не следует изменять. Вернуть изменённый список. */ -fun accumulate(list: MutableList): MutableList = TODO() +fun accumulate(list: MutableList): MutableList { + if (list.size > 1) list.take(list.size - 1).forEachIndexed { i, d -> list[i + 1] += list[i] } + return list +} /** * Средняя @@ -157,7 +181,16 @@ fun accumulate(list: MutableList): MutableList = TODO() * Результат разложения вернуть в виде списка множителей, например 75 -> (3, 5, 5). * Множители в списке должны располагаться по возрастанию. */ -fun factorize(n: Int): List = TODO() +fun factorize(n: Int): List { + val list = mutableListOf() + var num = n + while (num > 1) { + val min = lesson3.task1.minDivisor(num) + list.add(min) + num /= min + } + return list +} /** * Сложная @@ -165,7 +198,7 @@ fun factorize(n: Int): List = TODO() * Разложить заданное натуральное число n > 1 на простые множители. * Результат разложения вернуть в виде строки, например 75 -> 3*5*5 */ -fun factorizeToString(n: Int): String = TODO() +fun factorizeToString(n: Int): String = factorize(n).joinToString (separator = "*") /** * Средняя @@ -174,7 +207,16 @@ fun factorizeToString(n: Int): String = TODO() * Результат перевода вернуть в виде списка цифр в base-ичной системе от старшей к младшей, * например: n = 100, base = 4 -> (1, 2, 1, 0) или n = 250, base = 14 -> (1, 3, 12) */ -fun convert(n: Int, base: Int): List = TODO() +fun convert(n: Int, base: Int): List { + var num: Int = n + val list = mutableListOf() + while (num >= base) { + list.add(num % base) + num /= base + } + list.add(num) + return list.reversed() +} /** * Сложная @@ -184,7 +226,7 @@ fun convert(n: Int, base: Int): List = TODO() * строчными буквами: 10 -> a, 11 -> b, 12 -> c и так далее. * Например: n = 100, base = 4 -> 1210, n = 250, base = 14 -> 13c */ -fun convertToString(n: Int, base: Int): String = TODO() +fun convertToString(n: Int, base: Int): String = convert(n, base).joinToString(separator="", transform = { chars[it].toString() }) /** * Средняя @@ -193,10 +235,9 @@ fun convertToString(n: Int, base: Int): String = TODO() * из системы счисления с основанием base в десятичную. * Например: digits = (1, 3, 12), base = 14 -> 250 */ -fun decimal(digits: List, base: Int): Int = TODO() +fun decimal(digits: List, base: Int): Int = digits.reversed().mapIndexed { i, d -> d*pow(base, i) }.sum() -/** - * Сложная +/** * Сложная * * Перевести число, представленное цифровой строкой str, * из системы счисления с основанием base в десятичную. @@ -204,7 +245,8 @@ fun decimal(digits: List, base: Int): Int = TODO() * 10 -> a, 11 -> b, 12 -> c и так далее. * Например: str = "13c", base = 14 -> 250 */ -fun decimalFromString(str: String, base: Int): Int = TODO() +fun decimalFromString(str: String, base: Int): Int = str.reversed().mapIndexed { i, c -> chars.indexOf(c) * pow(base, i)}.sum() + /** * Сложная @@ -214,7 +256,24 @@ fun decimalFromString(str: String, base: Int): Int = TODO() * 90 = XC, 100 = C, 400 = CD, 500 = D, 900 = CM, 1000 = M. * Например: 23 = XXIII, 44 = XLIV, 100 = C */ -fun roman(n: Int): String = TODO() +fun roman(n: Int): String { + val symbols = sortedMapOf(1 to "I", 4 to "IV", 5 to "V", 9 to "IX", 10 to "X", 40 to "XL", 50 to "L", + 90 to "XC", 100 to "C", 400 to "CD", 500 to "D", 900 to "CM", 1000 to "M") + var decValue = n + val str = StringBuilder() + while (decValue > 0){ + print("$decValue ") + val key = symbols.keys.last() //Последний ключ (самое большое значение числа) в ассоц. массиве + println(key) + if (decValue >= key) { + str.append(symbols[key]) + decValue -= key + } else { + symbols.remove(key) + } + } + return str.toString() +} /** * Очень сложная @@ -223,4 +282,72 @@ fun roman(n: Int): String = TODO() * Например, 375 = "триста семьдесят пять", * 23964 = "двадцать три тысячи девятьсот шестьдесят четыре" */ -fun russian(n: Int): String = TODO() \ No newline at end of file +fun points(n: Int, female: Boolean): String = + when (n) { + 1 -> if (!female) "один" else "одна" + 2 -> if (!female) "два" else "две" + 3 -> "три" + 4 -> "четыре" + 5 -> "пять" + 6 -> "шесть" + 7 -> "семь" + 8 -> "восемь" + 9 -> "девять" + else -> "" + } +fun tens(n: Int): String = + when (n) { + 10 -> "десять" + 11 -> "одиннадцать" + 12 -> "двенадцать" + 13 -> "тринадцать" + 14 -> "четырнадцать" + 15 -> "пятнадцать" + 16 -> "шестнадцать" + 17 -> "семнадцать" + 18 -> "восемнадцать" + 19 -> "девятнадцать" + in 20..29 -> "двадцать" + in 30..39 -> "тридцать" + in 40..49 -> "сорок" + in 50..59 -> "пятьдесят" + in 60..69 -> "шестьдесят" + in 70..79 -> "семьдесят" + in 80..89 -> "восемьдесят" + in 90..99 -> "девяносто" + else -> "" + } + +fun hundreds(n: Int): String = + when(n) { + 1 -> "сто" + 2 -> "двести" + 3 -> "триста" + 4 -> "четыреста" + in 5..9 -> "${points(n, false)}сот" + else -> "" + } +fun keyword(n: Int): String = + when { + n == 0 -> "" + ((n%100 in 4..20) || n%10 == 0 || n%10 > 4) -> "тысяч" + n%10 == 1 -> "тысяча" + else -> "тысячи" + } + +fun russian(n: Int): String { + val list: MutableList = mutableListOf() + val thousands = n / 1000 + val thTens = thousands % 100 + val remainder = n % 1000 + val remTens = remainder % 100 + + list.add(hundreds(thousands / 100)) + list.add(tens(thTens)) + if (thTens !in 11..19) list.add(points(thousands % 10, true)) + list.add(keyword(thousands)) + list.add(hundreds(remainder / 100)) + list.add(tens(remTens)) + if (remTens !in 11..19) list.add(points(remainder % 10, false)) + return list.filter { it != "" }.joinToString (separator = " ") +} \ No newline at end of file diff --git a/src/lesson5/task1/Parse.kt b/src/lesson5/task1/Parse.kt index 15e3b8624..8b15681fb 100644 --- a/src/lesson5/task1/Parse.kt +++ b/src/lesson5/task1/Parse.kt @@ -1,6 +1,9 @@ @file:Suppress("UNUSED_PARAMETER") package lesson5.task1 + +import java.util.* + /** * Пример * @@ -60,7 +63,31 @@ fun main(args: Array) { * День и месяц всегда представлять двумя цифрами, например: 03.04.2011. * При неверном формате входной строки вернуть пустую строку */ -fun dateStrToDigit(str: String): String = TODO() +fun dateStrToDigit(str: String): String { + if (str.matches(Regex("""[0-9]+\s[а-яА-Я]+\s[0-9]+"""))) { + val parts = str.split(' ') + val day = parts[0].toInt() + val year = parts[2].toInt() + val month = when (parts[1]) { + "января" -> 1 + "февраля" -> 2 + "марта" -> 3 + "апреля" -> 4 + "мая" -> 5 + "июня" -> 6 + "июля" -> 7 + "августа" -> 8 + "сентября" -> 9 + "октября" -> 10 + "ноября" -> 11 + "декабря" -> 12 + else -> 0 + } + if (month != 0) + return String.format("%02d.%02d.%d", day, month, year) + else return "" + } else return "" +} /** * Средняя @@ -69,7 +96,31 @@ fun dateStrToDigit(str: String): String = TODO() * Перевести её в строковый формат вида "15 июля 2016". * При неверном формате входной строки вернуть пустую строку */ -fun dateDigitToStr(digital: String): String = TODO() +fun dateDigitToStr(digital: String): String { + if (digital.matches(Regex("[0-9]{2}.[0-9]{2}.[0-9]+"))) { + val parts = digital.split('.') + val day = parts[0].toInt() + val year = parts[2].toInt() + val month = when (parts[1].toInt()) { + 1 -> "января" + 2 -> "февраля" + 3 -> "марта" + 4 -> "апреля" + 5 -> "мая" + 6 -> "июня" + 7 -> "июля" + 8 -> "августа" + 9 -> "сентября" + 10 -> "октября" + 11 -> "ноября" + 12 -> "декабря" + else -> "" + } + if (month != "") + return String.format("%d %s %d", day, month, year) + else return "" + } else return "" +} /** * Сложная @@ -83,7 +134,10 @@ fun dateDigitToStr(digital: String): String = TODO() * Все символы в номере, кроме цифр, пробелов и +-(), считать недопустимыми. * При неверном формате вернуть пустую строку */ -fun flattenPhoneNumber(phone: String): String = TODO() +fun flattenPhoneNumber(phone: String): String = + if (phone.matches(Regex("""^\+?[-()0-9 ]+"""))){ + phone.replace(Regex("[-() ]+"), "") + } else "" /** * Средняя @@ -95,7 +149,10 @@ fun flattenPhoneNumber(phone: String): String = TODO() * Прочитать строку и вернуть максимальное присутствующее в ней число (717 в примере). * При нарушении формата входной строки или при отсутствии в ней чисел, вернуть -1. */ -fun bestLongJump(jumps: String): Int = TODO() +fun bestLongJump(jumps: String): Int = + if(jumps.matches(Regex("[-%0-9 ]+"))){ + Regex("[0-9]+").findAll(jumps).map { it.value.toInt() }.max() ?: -1 + } else -1 /** * Сложная @@ -107,7 +164,10 @@ fun bestLongJump(jumps: String): Int = TODO() * Прочитать строку и вернуть максимальную взятую высоту (230 в примере). * При нарушении формата входной строки вернуть -1. */ -fun bestHighJump(jumps: String): Int = TODO() +fun bestHighJump(jumps: String): Int = + if (jumps.matches(Regex("[-+%[0-9] ]+"))){ + Regex("([0-9]+) [%-]*[+]").findAll(jumps).map { it.groupValues[1].toInt() }.max() ?: -1 + } else -1 /** * Сложная @@ -118,7 +178,14 @@ fun bestHighJump(jumps: String): Int = TODO() * Вернуть значение выражения (6 для примера). * Про нарушении формата входной строки бросить исключение IllegalArgumentException */ -fun plusMinus(expression: String): Int = TODO() +fun plusMinus(expression: String): Int { + //Пробелы я убираю, чтобы правильно парсить число. + //Как вообще работает метод trim()? Почему, когда я применяю его к строке, ничего не происходит? + //По идее он же должен убирать все пробельные символы. + if (expression.matches(Regex("""^(?:[0-9]+)(?:\s+[-+]\s+[0-9]+)*"""))) { + return Regex("[-+]?[0-9]+").findAll(expression.replace(" ","")).sumBy { it.value.toInt() } + } else throw java.lang.IllegalArgumentException() +} /** * Сложная @@ -129,7 +196,13 @@ fun plusMinus(expression: String): Int = TODO() * Вернуть индекс начала первого повторяющегося слова, или -1, если повторов нет. * Пример: "Он пошёл в в школу" => результат 9 (индекс первого 'в') */ -fun firstDuplicateIndex(str: String): Int = TODO() +fun firstDuplicateIndex(str: String): Int { + val low = str.toLowerCase() + val duplicated = Regex("""(? value) { + most = name + value = price.toDouble() + } + } + } + return most +} /** * Сложная @@ -155,7 +243,71 @@ fun mostExpensive(description: String): String = TODO() * * Вернуть -1, если roman не является корректным римским числом */ -fun fromRoman(roman: String): Int = TODO() +fun fromRoman(roman: String): Int { + var count = roman.length-1 + var num: Int = 0 + while (count >= 0) { + when (roman[count]) { + 'I' -> {num++ ; count--} + 'V' -> { + if (count != 0 && roman[count-1] == 'I') { + num += 4 + count -= 2 + } else { + num += 5 + count-- + } + } + 'X' -> { + if (count != 0 && roman[count-1] == 'I') { + num += 9 + count -= 2 + } else { + num += 10 + count-- + } + } + 'L' -> { + if (count != 0 && roman[count-1] == 'X') { + num += 40 + count -= 2 + } else { + num += 50 + count-- + } + } + 'C' -> { + if (count != 0 && roman[count-1] == 'X') { + num += 90 + count -= 2 + } else { + num += 100 + count-- + } + } + 'D' -> { + if (count != 0 && roman[count-1] == 'C') { + num += 400 + count -= 2 + } else { + num += 500 + count-- + } + } + 'M' -> { + if (count != 0 && roman[count-1] == 'C') { + num += 900 + count -= 2 + } else { + num += 1000 + count-- + } + } + else -> {count = -1; num = -1} + } + } + return num +} /** * Сложная @@ -187,4 +339,113 @@ fun fromRoman(roman: String): Int = TODO() * Вернуть список размера cells, содержащий элементы ячеек устройства после выполнения всех команд. * Например, для 10 ячеек и командной строки +>+>+>+>+ результат должен быть 0,0,0,0,0,1,1,1,1,1 */ -fun computeDeviceCells(cells: Int, commands: String): List = TODO() \ No newline at end of file +fun findCycles(commands: String, open: Char, close: Char): MutableMap { + //Ассоциативный массив для результатов + val map = mutableMapOf() + //Лист точек открывающих знаков цикла, для того, чтобы учесть вложенность + val openPointQueue = ArrayDeque() + // + for (i in 0..commands.length-1) { + when (commands[i]) { + //При нахождении открывающего знака, добавляем в очередь + open -> { + openPointQueue.addFirst(i) + } + close -> { + //Если нет ни одного открывающего знака в очередь, выбрасываем ошибку, так как цикл будет непарным + if (openPointQueue.isEmpty()) throw IllegalStateException("No pair for bracket") + //Если же хотя бы одна точка есть, то создаем две пары, чтобы можно было найти конец по началу + //и наоборот. Сохраняем в ассоциативный массив и удаляем последний элемент в списке + else { + val openPoint = openPointQueue.poll() + map.put(openPoint, i) + map.put(i, openPoint) + } + } + } + } + return map +} +fun computeDeviceCells(cells: Int, commands: String): List { + //Первая часть проверки на парность циклов, вторая проходит уже при поиске пары для каждого + if (commands.count { it=='[' } == commands.count { it==']' } && + commands.count { it=='{' } == commands.count { it=='}' } ) { + //Если ноль ячеек сразу возвращаем ответ + if (cells == 0) return listOf() + //Создаем массив размером cells и заполняем его нулями + val cellsArr = Array(cells, {i -> 0}) + //Начальная точка + var point = cells/2 + //Указатель на текущую команду + var commandPoint = 0 + //Длина строки команд + val commandLength = commands.length + //Находим все циклы + val cycleOne = findCycles(commands,'[',']') + val cycleTwo = findCycles(commands,'{','}') + //Выполняем пока не конец командной строки + while (commandPoint < commandLength) { + when (commands[commandPoint]) { + ' ' -> commandPoint++ //Пустая команда, просто сдвигаем указатель + '>' -> { + //Сдвигаем ячейку + point++ + //Выдаем ошибку, если выходим за границы + if (point > cells-1) throw java.lang.IllegalStateException() + //Сдвигаем указатель + commandPoint++ + } + '<' -> { + //Аналогично ">" + point-- + if (point < 0) throw java.lang.IllegalStateException() + commandPoint++ + } + '+' -> { + //Увеличиваем значение в ячейке и сдвигаем указатель + cellsArr[point]++ + commandPoint++ + } + '-' -> { + //Аналогично "-" + cellsArr[point]-- + commandPoint++ + } + '[' -> { + if (cellsArr[point] == 0) + //Если значение в ячейке 0, то выходим из цикла + commandPoint = (cycleOne[commandPoint] ?: 0) + 1 + else + //Иначе просто сдвигаем указатель + commandPoint++ + } + ']' -> { + if (cellsArr[point] != 0) { + //Если значение в ячейке не равно 0, возвращаемся в начало цикла + commandPoint = (cycleOne[commandPoint] ?: 0) + 1 + } else { + //Сдивагаем указатель и выходи из цикла + commandPoint++ + } + } + //Аналогично прошлому циклу + '{' -> { + if (cellsArr[point] == 0) + commandPoint = (cycleTwo[commandPoint] ?: 0) + 1 + else + commandPoint++ + } + '}' -> { + if (cellsArr[point] != 0) { + commandPoint = (cycleTwo[commandPoint] ?: 0) + 1 + } else { + commandPoint++ + } + } + //Если сивол не предусмотрен выдаем ошибку + else -> throw java.lang.IllegalArgumentException() + } + } + return cellsArr.toList() + } else throw IllegalAccessException() +} \ No newline at end of file diff --git a/src/lesson6/task1/Geometry.kt b/src/lesson6/task1/Geometry.kt index 097b7424c..b9a491cff 100644 --- a/src/lesson6/task1/Geometry.kt +++ b/src/lesson6/task1/Geometry.kt @@ -6,6 +6,7 @@ import lesson1.task1.sqr /** * Точка на плоскости */ + data class Point(val x: Double, val y: Double) { /** * Пример @@ -55,14 +56,17 @@ data class Circle(val center: Point, val radius: Double) { * расстояние между их центрами минус сумма их радиусов. * Расстояние между пересекающимися окружностями считать равным 0.0. */ - fun distance(other: Circle): Double = TODO() + fun distance(other: Circle): Double { + val s = center.distance(other.center) - (radius+other.radius) + return if (s <= 0.0) 0.0 else s + } /** * Тривиальная * * Вернуть true, если и только если окружность содержит данную точку НА себе или ВНУТРИ себя */ - fun contains(p: Point): Boolean = TODO() + fun contains(p: Point): Boolean = p.distance(center) <= radius } /** @@ -76,7 +80,16 @@ data class Segment(val begin: Point, val end: Point) * Дано множество точек. Вернуть отрезок, соединяющий две наиболее удалённые из них. * Если в множестве менее двух точек, бросить IllegalArgumentException */ -fun diameter(vararg points: Point): Segment = TODO() +fun diameter(vararg points: Point): Segment { + if (points.count() > 1) { + var max = Segment(points[0], points[1]) + for (i in 0..points.size - 2) + for (j in i + 1..points.size - 1) + if (points[i].distance(points[j]) > max.begin.distance(max.end)) + max = Segment(points[i], points[j]) + return max + } else throw java.lang.IllegalArgumentException() +} /** * Простая @@ -84,7 +97,12 @@ fun diameter(vararg points: Point): Segment = TODO() * Построить окружность по её диаметру, заданному двумя точками * Центр её должен находиться посередине между точками, а радиус составлять половину расстояния между ними */ -fun circleByDiameter(diameter: Segment): Circle = TODO() +fun circleByDiameter(diameter: Segment): Circle { + val centerX = diameter.begin.x + (diameter.end.x - diameter.begin.x) / 2 + val centerY = diameter.begin.y + (diameter.end.y - diameter.begin.y) / 2 + val center = Point(centerX, centerY) + return Circle(center, center.distance(diameter.begin)) +} /** * Прямая, заданная точкой и углом наклона (в радианах) по отношению к оси X. @@ -97,7 +115,20 @@ data class Line(val point: Point, val angle: Double) { * Найти точку пересечения с другой линией. * Для этого необходимо составить и решить систему из двух уравнений (каждое для своей прямой) */ - fun crossPoint(other: Line): Point = TODO() + fun crossPoint(other: Line): Point { + val k1 = Math.tan(this.angle) + val b1 = -1 * (this.point.x * k1) + this.point.y + val k2 = Math.tan(other.angle) + val b2 = -1 * (other.point.x * k2) + other.point.y + val x = (b2 - b1) / (k1 - k2) + val y = + when { + (this.angle == Math.PI / 2 || this.angle == Math.PI / -2) -> other.point.y + (other.angle == Math.PI / 2 || other.angle == Math.PI / -2) -> this.point.y + else -> (x - this.point.x) * k1 + this.point.y + } + return Point(x, y) + } } /** @@ -105,21 +136,26 @@ data class Line(val point: Point, val angle: Double) { * * Построить прямую по отрезку */ -fun lineBySegment(s: Segment): Line = TODO() +fun lineBySegment(s: Segment): Line = Line(s.begin, Math.atan((s.end.y - s.begin.y) / (s.end.x - s.begin.x))) /** * Средняя * * Построить прямую по двум точкам */ -fun lineByPoints(a: Point, b: Point): Line = TODO() +fun lineByPoints(a: Point, b: Point): Line = lineBySegment(Segment(a, b)) /** * Сложная * * Построить серединный перпендикуляр по отрезку или по двум точкам */ -fun bisectorByPoints(a: Point, b: Point): Line = TODO() +fun bisectorByPoints(a: Point, b: Point): Line { + val segment = Segment(a, b) + val center = circleByDiameter(segment).center + val angle = lineBySegment(segment).angle + Math.PI / 2 + return Line(center, angle) +} /** * Средняя @@ -127,7 +163,25 @@ fun bisectorByPoints(a: Point, b: Point): Line = TODO() * Задан список из n окружностей на плоскости. Найти пару наименее удалённых из них. * Если в списке менее двух окружностей, бросить IllegalArgumentException */ -fun findNearestCirclePair(vararg circles: Circle): Pair = TODO() +fun findNearestCirclePair(vararg circles: Circle): Pair { + var minLength = Double.POSITIVE_INFINITY + var f = circles[0] + var s = circles[0] + if (circles.count() > 1) { + for (i in 0..circles.count() - 1) { + for (j in i + 1..circles.count() - 1) { + val dist = circles[i].distance(circles[j]) + if (dist < minLength) { + minLength = dist + f = circles[i] + s = circles[j] + } + } + } + return Pair(f,s) + } else throw IllegalArgumentException() + +} /** * Очень сложная @@ -138,7 +192,18 @@ fun findNearestCirclePair(vararg circles: Circle): Pair = TODO() * (построить окружность по трём точкам, или * построить окружность, описанную вокруг треугольника - эквивалентная задача). */ -fun circleByThreePoints(a: Point, b: Point, c: Point): Circle = TODO() +fun circleByThreePoints(a: Point, b: Point, c: Point): Circle { + //Если использовать решение через серединные перпендикуляры + val ma = (b.y - a.y) / (b.x - a.x) + val mb = (c.y - b.y) / (c.x - b.x) + val x = (ma * mb * (a.y - c.y) + mb * (a.x + b.x) - ma * (b.x + c.x)) / (2 * (mb - ma)) + val y = -1 / ma * (x - (a.x + b.x) / 2) + (a.y + b.y) / 2 + val p = Point(x,y) + //Если не выбирать максимум из расстояний до точек, то остается погрешность порядка 4E-16 + var r = Math.max(p.distance(a),p.distance(b)) + r = Math.max(r,p.distance(c)) + return Circle(p,r) +} /** * Очень сложная @@ -147,9 +212,21 @@ fun circleByThreePoints(a: Point, b: Point, c: Point): Circle = TODO() * содержащий все эти точки. Если множество пустое, бросить IllegalArgumentException. * Если множество содержит одну точку, вернуть круг нулевого радиуса с центром в данной точке. * - * Примечание: в зависимости от ситуации, такая окружность может либо проходить через какие-либо + * Примечание: в зависимости от с /* + val center = bisectorByPoints(a, b).crossPoint(bisectorByPoints(b, c)) + return Circle(center, center.distance(a)) + */итуации, такая окружность может либо проходить через какие-либо * три точки данного множества, либо иметь своим диаметром отрезок, * соединяющий две самые удалённые точки в данном множестве. */ -fun minContainingCircle(vararg points: Point): Circle = TODO() +fun minContainingCircle(vararg points: Point): Circle { + val d = diameter(*points) + var c = circleByDiameter(d) + for (p in points) { + if (!c.contains(p)) { + c = circleByThreePoints(d.begin, d.end, p) + } + } + return c +} diff --git a/src/lesson6/task2/Chess.kt b/src/lesson6/task2/Chess.kt index 3d44aae89..b29099b00 100644 --- a/src/lesson6/task2/Chess.kt +++ b/src/lesson6/task2/Chess.kt @@ -1,13 +1,14 @@ @file:Suppress("UNUSED_PARAMETER") package lesson6.task2 -import java.util.* - +import java.lang.Math.* +import lesson6.task3.* /** * Клетка шахматной доски. Шахматная доска квадратная и имеет 8 х 8 клеток. * Поэтому, обе координаты клетки (горизонталь row, вертикаль column) могут находиться в пределах от 1 до 8. * Горизонтали нумеруются снизу вверх, вертикали слева направо. */ +val chars = "abcdefgh" data class Square(val column: Int, val row: Int) { /** * Пример @@ -23,7 +24,9 @@ data class Square(val column: Int, val row: Int) { * В нотации, колонки обозначаются латинскими буквами от a до h, а ряды -- цифрами от 1 до 8. * Для клетки не в пределах доски вернуть пустую строку */ - fun notation(): String = TODO() + fun notation(): String { + return if (inside()) "${chars[this.column-1]}$row" else "" + } } /** @@ -33,7 +36,13 @@ data class Square(val column: Int, val row: Int) { * В нотации, колонки обозначаются латинскими буквами от a до h, а ряды -- цифрами от 1 до 8. * Если нотация некорректна, бросить IllegalArgumentException */ -fun square(notation: String): Square = TODO() +fun square(notation: String): Square { + val sq = Square(chars.indexOf(notation[0])+1, notation[1] - '0') + if (!sq.inside()) + throw IllegalAccessException() + else + return sq +} /** * Простая @@ -58,7 +67,14 @@ fun square(notation: String): Square = TODO() * Пример: rookMoveNumber(Square(3, 1), Square(6, 3)) = 2 * Ладья может пройти через клетку (3, 3) или через клетку (6, 1) к клетке (6, 3). */ -fun rookMoveNumber(start: Square, end: Square): Int = TODO() +fun rookMoveNumber(start: Square, end: Square): Int = + when { + !(start.inside() && end.inside()) -> throw IllegalArgumentException() + start.column != end.column && start.row != end.row -> 2 + start == end -> 0 + else -> 1 + } + /** * Средняя @@ -74,7 +90,12 @@ fun rookMoveNumber(start: Square, end: Square): Int = TODO() * rookTrajectory(Square(3, 5), Square(8, 5)) = listOf(Square(3, 5), Square(8, 5)) * Если возможно несколько вариантов самой быстрой траектории, вернуть любой из них. */ -fun rookTrajectory(start: Square, end: Square): List = TODO() +fun rookTrajectory(start: Square, end: Square): List = + when (rookMoveNumber(start,end)) { + 0 -> listOf(start) + 1 -> listOf(start,end) + else -> listOf(start,Square(start.column,end.row),end) + } /** * Простая @@ -99,7 +120,14 @@ fun rookTrajectory(start: Square, end: Square): List = TODO() * Примеры: bishopMoveNumber(Square(3, 1), Square(6, 3)) = -1; bishopMoveNumber(Square(3, 1), Square(3, 7)) = 2. * Слон может пройти через клетку (6, 4) к клетке (3, 7). */ -fun bishopMoveNumber(start: Square, end: Square): Int = TODO() +fun bishopMoveNumber(start: Square, end: Square): Int = + when { + !(start.inside() && end.inside()) -> throw IllegalArgumentException() + ((start.column * start.row) % 2 != (end.column * end.row) % 2) -> -1 + start == end -> 0 + (Math.abs(start.column - end.column) == Math.abs(start.row - end.row)) -> 1 + else -> 2 + } /** * Сложная @@ -119,7 +147,25 @@ fun bishopMoveNumber(start: Square, end: Square): Int = TODO() * bishopTrajectory(Square(1, 3), Square(6, 8)) = listOf(Square(1, 3), Square(6, 8)) * Если возможно несколько вариантов самой быстрой траектории, вернуть любой из них. */ -fun bishopTrajectory(start: Square, end: Square): List = TODO() +fun bishopTrajectory(start: Square, end: Square): List = + //В чем смысл последнего теста? И почему он не проходит всегда? + when (bishopMoveNumber(start, end)) { + -1 -> listOf() + 0 -> listOf(start) + 1 -> listOf(start, end) + else -> { + val delta = (abs(end.column - start.column) + abs(end.row - start.row)) / 2 + var Sq: Square + if (start.row < end.row) { + Sq = Square(start.column + delta, start.row + delta) + if(!Sq.inside()) Sq = Square(start.column - delta, start.row + delta) + } else { + Sq = Square(start.column - delta, start.row - delta) + if(!Sq.inside()) Sq = Square(start.column + delta, start.row - delta) + } + listOf(start, Sq, end) + } + } /** * Средняя @@ -141,7 +187,12 @@ fun bishopTrajectory(start: Square, end: Square): List = TODO() * Пример: kingMoveNumber(Square(3, 1), Square(6, 3)) = 3. * Король может последовательно пройти через клетки (4, 2) и (5, 2) к клетке (6, 3). */ -fun kingMoveNumber(start: Square, end: Square): Int = TODO() +fun kingMoveNumber(start: Square, end: Square): Int = + when { + !(start.inside() && end.inside()) -> throw IllegalArgumentException() + else -> max(abs(end.column - start.column), abs(end.row - start.row)) + } + /** * Сложная @@ -157,7 +208,27 @@ fun kingMoveNumber(start: Square, end: Square): Int = TODO() * kingTrajectory(Square(3, 5), Square(6, 2)) = listOf(Square(3, 5), Square(4, 4), Square(5, 3), Square(6, 2)) * Если возможно несколько вариантов самой быстрой траектории, вернуть любой из них. */ -fun kingTrajectory(start: Square, end: Square): List = TODO() +fun kingTrajectory(start: Square, end: Square): List { + val steps = mutableListOf(start) + val stepsValue = kingMoveNumber(start, end) + if (stepsValue > 0) { + val horizontal = end.column - start.column + val vertical = end.row - start.row + val horizontalStep = horizontal / abs(horizontal) + val verticalStep = vertical / abs(vertical) + val cross = min(abs(horizontal), abs(vertical)) + for (i in 1..cross) { + steps.add(Square(steps[i - 1].column + horizontalStep, steps[i - 1].row + verticalStep)) + } + for (i in cross + 1..stepsValue) { + if (abs(horizontal) > abs(vertical)) + steps.add(Square(steps[i - 1].column + horizontalStep, steps[i - 1].row)) + else + steps.add(Square(steps[i - 1].column, steps[i - 1].row + verticalStep)) + } + return steps + } else return listOf(start) +} /** * Сложная @@ -182,7 +253,47 @@ fun kingTrajectory(start: Square, end: Square): List = TODO() * Пример: knightMoveNumber(Square(3, 1), Square(6, 3)) = 3. * Конь может последовательно пройти через клетки (5, 2) и (4, 4) к клетке (6, 3). */ -fun knightMoveNumber(start: Square, end: Square): Int = TODO() +fun findNeigbhors(point: Square): List { + val list = mutableListOf() + for (i in 1..2) { + for (j in 1..2) { + val hz = if (i%2==0) -1 else 1 + val vz = if (j%2==0) -1 else 1 + val sq = Square(point.column + (2*hz), point.row + (1*vz)) + if(sq.inside()) list.add(sq) + } + } + for (i in 1..2) { + for (j in 1..2) { + val hz = if (i%2==0) -1 else 1 + val vz = if (j%2==0) -1 else 1 + val sq = Square(point.column + (1*hz), point.row + (2*vz)) + if(sq.inside()) list.add(sq) + } + } + return list +} +fun knightMoveNumber(start: Square, end: Square): Int { + if (!start.inside() || !end.inside()) throw IllegalArgumentException() + //Иного решения, кроме как графом - я не придумал + val desk: Graph = Graph() + //Строим граф по его вершинам + for (i in 1..8) { + for (j in 1..8) { + val Sq = Square(i,j) + desk.addVertex(Sq.notation()) + } + } + //Строим ребра, каждое с весом 1 (а по-другоу и нельзя) + for (i in 1..8) { + for (j in 1..8) { + val Sq = Square(i,j) + findNeigbhors(Sq).forEach { desk.connect(Sq.notation(),it.notation()) } + } + } + //С помощью поиска в ширину находим кратчайщее расстояние + return desk.bfs(start.notation(),end.notation()) +} /** * Очень сложная @@ -204,4 +315,28 @@ fun knightMoveNumber(start: Square, end: Square): Int = TODO() * * Если возможно несколько вариантов самой быстрой траектории, вернуть любой из них. */ -fun knightTrajectory(start: Square, end: Square): List = TODO() +fun knightTrajectory(start: Square, end: Square): List { + if (!start.inside() || !end.inside()) throw IllegalArgumentException() + //Иного решения, кроме как графом - я не придумал + val desk: Graph = Graph() + //Строим граф по его вершинам + for (i in 1..8) { + for (j in 1..8) { + val Sq = Square(i,j) + desk.addVertex(Sq.notation()) + } + } + //Строим ребра, каждое с весо 1 (а по-другоу и нельзя) + for (i in 1..8) { + for (j in 1..8) { + val Sq = Square(i,j) + findNeigbhors(Sq).forEach { desk.connect(Sq.notation(),it.notation()) } + } + } + //С помощью поиска в ширину находим кратчайщее расстояние + val path = desk.bfsPath(start.notation(), end.notation()).toMutableList() + path.add(end.notation()) + return path.map { square(it) } +} + + diff --git a/src/lesson6/task3/Graph.kt b/src/lesson6/task3/Graph.kt index 32ff34571..268311a82 100644 --- a/src/lesson6/task3/Graph.kt +++ b/src/lesson6/task3/Graph.kt @@ -32,6 +32,10 @@ class Graph { */ fun bfs(start: String, finish: String) = bfs(this[start], this[finish]) + // + fun bfsPath(start: String, finish: String) = bfsPath(this[start], this[finish]) + // + private fun bfs(start: Vertex, finish: Vertex): Int { val queue = ArrayDeque() queue.add(start) @@ -48,6 +52,30 @@ class Graph { } return -1 } + // + //Алгоритм аналагичный реализованному вами поиску в ширину, только возвращающий путь, в качестве результата + private fun bfsPath(start: Vertex, finish: Vertex): List { + val queue = ArrayDeque() + //Предыдущая обработанная вершина + queue.add(start) + val visited = mutableMapOf>() + while (queue.isNotEmpty()) { + val next = queue.poll() + if (next == finish) return visited[next] ?: listOf() + for (neighbor in next.neighbors) { + if (neighbor in visited) continue + //Сохраняем путь до вершины + //Довольно интересно было на практике, при поиске ошибки, узнать, что в Котлине, + //как и в C# листы не копируются через оператор "=" напряую, а копируется лишь сслыка на них + val path = visited[next]?.take(visited[next]?.size ?: 0)?.toMutableList() ?: mutableListOf() + path.add(next.name) + visited.put(neighbor, path) + queue.add(neighbor) + } + } + return listOf() + } + // /** * Пример diff --git a/src/lesson7/task1/Matrix.kt b/src/lesson7/task1/Matrix.kt index 0c4bf5c55..9a0f18502 100644 --- a/src/lesson7/task1/Matrix.kt +++ b/src/lesson7/task1/Matrix.kt @@ -1,6 +1,8 @@ @file:Suppress("UNUSED_PARAMETER", "unused") package lesson7.task1 + + /** * Ячейка матрицы: row = ряд, column = колонка */ @@ -38,7 +40,7 @@ interface Matrix { * height = высота, width = ширина, e = чем заполнить элементы. * Бросить исключение IllegalArgumentException, если height или width <= 0. */ -fun createMatrix(height: Int, width: Int, e: E): Matrix = TODO() +fun createMatrix(height: Int, width: Int, e: E): Matrix = MatrixImpl(height, width, e) /** * Средняя сложность @@ -46,24 +48,72 @@ fun createMatrix(height: Int, width: Int, e: E): Matrix = TODO() * Реализация интерфейса "матрица" */ class MatrixImpl : Matrix { - override val height: Int = TODO() - override val width: Int = TODO() + override val height: Int + override val width: Int + + private val cells: MutableList> + + constructor(height: Int, width: Int, e: E) { + if (height > 0 && width > 0) { + this.height = height + this.width = width + } else + throw IllegalArgumentException("Index is below 0") - override fun get(row: Int, column: Int): E = TODO() + //Можно проще создать двумерный массив? Если да, то как? + this.cells = (1..height).map{(1..width).map { e }.toMutableList()}.toMutableList() - override fun get(cell: Cell): E = TODO() + } + + private fun check(row: Int, column: Int) { + if (height !in 0..this.height && width !in 0..this.width) + throw IllegalArgumentException("Index out of bounds: [$row;$column]") + } + + override fun get(row: Int, column: Int): E { + check(row,column) + return this.cells[row][column] + } + + override fun get(cell: Cell): E = get(cell.row, cell.column) override fun set(row: Int, column: Int, value: E) { - TODO() + check(row, column) + this.cells[row][column] = value } override fun set(cell: Cell, value: E) { - TODO() + set(cell.row, cell.column, value) } - override fun equals(other: Any?) = TODO() - override fun toString(): String = TODO() + + override fun equals(other: Any?) = other is MatrixImpl<*> && other.height == this.height && + other.width == this.width && other.cells == this.cells + + override fun hashCode(): Int { + val primal = 7 + var result = 1 + result = result * primal + height + result = result * primal + width + for (i in 0..height - 1) + for (j in 0..width - 1) + result += (cells[i][j]?.hashCode() ?: 0) * ((i + 1) * width + j + 1) + return result + } + + override fun toString(): String { + val str: StringBuilder = StringBuilder() + str.appendln() + cells.forEachIndexed { i, list -> + str.append("Row $i: ") + list.forEach { + str.append("\t$it") + } + str.appendln() + } + return str.toString() + } } diff --git a/src/lesson7/task2/Matrices.kt b/src/lesson7/task2/Matrices.kt index c6a534aa5..43d8fe6fc 100644 --- a/src/lesson7/task2/Matrices.kt +++ b/src/lesson7/task2/Matrices.kt @@ -1,11 +1,81 @@ @file:Suppress("UNUSED_PARAMETER") package lesson7.task2 +import lesson7.task1.Cell import lesson7.task1.Matrix import lesson7.task1.createMatrix +import java.lang.Math.* + // Все задачи в этом файле требуют наличия реализации интерфейса "Матрица" в Matrix.kt +//Extensions of Cell data class +// По-нормальноу это должен быть статический параметр класса, но са класс Cell я менять не могу +val NOT_EXISTS = Cell(-1, -1) + +fun Cell.near(other: Cell): Boolean = + if (this == other) throw IllegalArgumentException("Cells are the same") + else ((this.row - other.row) == 0 && abs(this.column - other.column) == 1) || + (abs(this.row - other.row) == 1 && this.column - other.column == 0) + + +fun createFilledMatrix(height: Int, width: Int, values: List>): Matrix { + val matrix = createMatrix(height, width, values[0][0]) + for (row in 0..height - 1) { + for (column in 0..width - 1) { + matrix[row, column] = values[row][column] + } + } + return matrix +} + +//Extensions of Matrix class +fun Matrix.getRow(row: Int): List = + if (row in 0..height - 1) (0..width - 1).map { this[row, it] } else throw IllegalArgumentException("Index out of bounds: $row") + +fun Matrix.getColumn(column: Int): List = + if (column in 0..width - 1) (0..height - 1).map { this[it, column] } else throw IllegalArgumentException("Index out of bounds: $column") + +fun Matrix.contains(row: Int, column: Int): Boolean = row in 0..this.height - 1 && column in 0..this.width - 1 + +fun Matrix.contains(cell: Cell): Boolean = this.contains(cell.row, cell.column) + +fun Matrix.subMatrix(height: Int, width: Int, heightShift: Int, widthShift: Int): Matrix { + if (this.height < height + heightShift || this.width < width + widthShift) + throw IllegalArgumentException("Sub Matrix is out of bounds of original") + else { + val m = createMatrix(height, width, this[0,0]) + for (i in 0..height - 1) + for (j in 0..width - 1) + m[i,j] = this[i + heightShift, j + widthShift] + return m + } +} + +fun Matrix.indexOf(element: E): Cell { + for (i in 0..height - 1) + for (j in 0..width - 1) + if (this[i,j] == element) + return Cell(i, j) + return NOT_EXISTS +} + +fun Matrix.swap(first: Cell, second: Cell) { + if (this.contains(first) && this.contains(second)) { + val tmp = this[first] + this[first] = this[second] + this[second] = tmp + } else throw IllegalArgumentException("No suck Cells in Matrix [${first.toString()}] - [${second.toString()}]") +} +fun Matrix.findMoves(cell: Cell): List { + val list = mutableListOf() + (-1..0).forEach { + if (this.contains(cell.row + it, cell.column + it + 1)) list.add(Cell(cell.row + it, cell.column + it + 1)) + if (this.contains(cell.row + it + 1, cell.column + it)) list.add(Cell(cell.row + it + 1, cell.column + it)) + } + return list +} +fun Matrix.copyN(): Matrix = this.subMatrix(this.height, this.width, 0, 0) /** * Пример * @@ -59,7 +129,35 @@ operator fun Matrix.plus(other: Matrix): Matrix { * 10 11 12 5 * 9 8 7 6 */ -fun generateSpiral(height: Int, width: Int): Matrix = TODO() +fun generateSpiral(height: Int, width: Int): Matrix { + val m = createMatrix(height, width, 0) + //Создаем лист с максимальными значениями каждого "кольца", считаем по формуле, а потом проходимся по нему функцией, + //аналогичной accumulate (для матрицы 4х4 получим значения 0, 12, 16) + val squareEndValue: MutableList = mutableListOf(0) + (1..ceil(min(width, height) / 2.0).toInt()).forEach { + val space = 2 * ((width + height) - (2 + 4 * (it - 1))) + squareEndValue.add((if (space != 0) space else 1) + if (it > 1) squareEndValue[it-1] else 0) + } + //Проходимся по каждому "row" матрицы и считаем значения + for (i in 0..height-1) { + for (j in 0..width-1) { + //Значения обратные i,j соответсвенно + val revertI = height-i-1 + val revertJ = width-j-1 + //Находим, в каком "кольце" находится ячейка и от этого рассчиываем ее значение + val inside = min(if (i >= (height/2.0)) revertI else i, if (j >= (width/2.0)) revertJ else j) + //Правая верхняя часть матрицы + if (i == inside || revertJ == inside) { + m[i,j] = squareEndValue[inside] + ((width - revertJ + height - revertI) - (2 * inside) - 1) + //Левая нижняя часть матрицы + } else { + m[i,j] = squareEndValue[inside+1] - (width - revertJ + height - revertI - (2 * inside) - 3) + } + + } + } + return m +} /** * Сложная @@ -75,7 +173,16 @@ fun generateSpiral(height: Int, width: Int): Matrix = TODO() * 1 2 2 2 2 1 * 1 1 1 1 1 1 */ -fun generateRectangles(height: Int, width: Int): Matrix = TODO() +fun generateRectangles(height: Int, width: Int): Matrix { + val m = createMatrix(height, width, 0) + for (i in 0..height-1) { + for (j in 0..width-1) { + val inside = min(if (i >= (height/2.0)) height-i-1 else i, if (j >= (width/2.0)) width-j-1 else j) + m[i,j] = inside+1 + } + } + return m +} /** * Сложная @@ -90,7 +197,14 @@ fun generateRectangles(height: Int, width: Int): Matrix = TODO() * 10 13 16 18 * 14 17 19 20 */ -fun generateSnake(height: Int, width: Int): Matrix = TODO() +fun generateSnake(height: Int, width: Int): Matrix { + val m = createMatrix(height, width, 0) + for (i in 0..height - 1) + for (j in 0..width - 1) + m[i,j] = 1 + if (i > 0 && (j < width - 1 || j == 0)) m[i - 1,j + min(width - 1,1)] + else if (j > 0) m[i,j - 1] + min(j - 1, height - 1 - i) else 0 + return m +} /** * Средняя @@ -103,7 +217,15 @@ fun generateSnake(height: Int, width: Int): Matrix = TODO() * 4 5 6 8 5 2 * 7 8 9 9 6 3 */ -fun rotate(matrix: Matrix): Matrix = TODO() +fun rotate(matrix: Matrix): Matrix { + if (matrix.height != matrix.width) throw IllegalAccessException("Height and width isn't equals") + val m = createMatrix(matrix.width, matrix.height, matrix[0,0]) + for (i in 0..matrix.height - 1) { + for (j in 0..matrix.width - 1) + m[i, j] = matrix[matrix.width-j-1, i] + } + return m +} /** * Сложная @@ -118,8 +240,15 @@ fun rotate(matrix: Matrix): Matrix = TODO() * 1 2 3 * 3 1 2 */ -fun isLatinSquare(matrix: Matrix): Boolean = TODO() - +fun isLatinSquare(matrix: Matrix): Boolean { + if (matrix.width == matrix.height) { + val list = (1..matrix.width).toList() + (0..matrix.height - 1).forEach { + if (matrix.getRow(it).sorted() != list || matrix.getColumn(it).sorted() != list) return false + } + return true + } else return false +} /** * Средняя * @@ -137,7 +266,18 @@ fun isLatinSquare(matrix: Matrix): Boolean = TODO() * * 42 ===> 0 */ -fun sumNeighbours(matrix: Matrix): Matrix = TODO() +fun sumNeighbours(matrix: Matrix): Matrix { + val m = createMatrix(matrix.height, matrix.width, 0) + for (i in 0..matrix.height - 1) + for (j in 0..matrix.width - 1) { + m[i,j] = -matrix[i,j] + for (k in -1..1) + for (l in -1..1) + if (m.contains(i + k, j + l)) + m[i,j] += matrix[i + k, j + l] + } + return m +} /** * Средняя @@ -154,7 +294,9 @@ fun sumNeighbours(matrix: Matrix): Matrix = TODO() * 0 0 1 0 * 0 0 0 0 */ -fun findHoles(matrix: Matrix): Holes = TODO() +fun findHoles(matrix: Matrix): Holes = + Holes((0..matrix.height - 1).filter { matrix.getRow(it).sum() == 0 }, (0..matrix.width - 1).filter { matrix.getColumn(it).sum() == 0 }) + /** * Класс для описания местонахождения "дырок" в матрице @@ -175,7 +317,18 @@ data class Holes(val rows: List, val columns: List) * * К примеру, центральный элемент 12 = 1 + 2 + 4 + 5, элемент в левом нижнем углу 12 = 1 + 4 + 7 и так далее. */ -fun sumSubMatrix(matrix: Matrix): Matrix = TODO() +fun sumSubMatrix(matrix: Matrix): Matrix { + val m = createMatrix(matrix.height, matrix.width, 0) + for (i in 0..matrix.height - 1) + for (j in 0..matrix.width - 1) { + m[i,j] = 0 + for (k in -i..0) + for (l in -j..0) + if (m.contains(i + k, j + l)) + m[i,j] += matrix[i + k, j + l] + } + return m +} /** * Сложная @@ -197,7 +350,18 @@ fun sumSubMatrix(matrix: Matrix): Matrix = TODO() * Вернуть тройку (Triple) -- (да/нет, требуемый сдвиг по высоте, требуемый сдвиг по ширине). * Если наложение невозможно, то первый элемент тройки "нет" и сдвиги могут быть любыми. */ -fun canOpenLock(key: Matrix, lock: Matrix): Triple = TODO() +fun canOpenLock(key: Matrix, lock: Matrix): Triple { + if (key.height > lock.height || key.width > lock.width) + return Triple(false, 0, 0) + else { + val unlocked = createMatrix(key.height, key.width, 1) + for (i in 0..lock.height - key.height) + for (j in 0..lock.width - key.width) + if (lock.subMatrix(key.height, key.width, i, j) + key == unlocked) + return Triple(true, i, j) + return Triple(false, 0, 0) + } +} /** * Простая @@ -205,7 +369,12 @@ fun canOpenLock(key: Matrix, lock: Matrix): Triple * Инвертировать заданную матрицу. * При инвертировании знак каждого элемента матрицы следует заменить на обратный */ -operator fun Matrix.unaryMinus(): Matrix = TODO(this.toString()) +operator fun Matrix.unaryMinus(): Matrix { + for (i in 0..height - 1) + for (j in 0..width - 1) + this[i,j] *= -1 + return this +} /** * Средняя @@ -215,7 +384,16 @@ operator fun Matrix.unaryMinus(): Matrix = TODO(this.toString()) * В противном случае бросить IllegalArgumentException. * Подробно про порядок умножения см. статью Википедии "Умножение матриц". */ -operator fun Matrix.times(other: Matrix): Matrix = TODO(this.toString()) +operator fun Matrix.times(other: Matrix): Matrix { + if (this.width != other.height) throw IllegalArgumentException("Matrixes can't be multiplied") + val matrixes = if (this.width > other.width) Pair(this, other) else Pair(other, this) + val min = matrixes.first.height + val m = createMatrix(min, min, 0) + for (i in 0..min - 1) + for (j in 0..min - 1) + m[i, j] = matrixes.first.getRow(i).zip(matrixes.second.getColumn(j), { R, T -> R * T }).sum() + return m +} /** * Сложная @@ -244,7 +422,20 @@ operator fun Matrix.times(other: Matrix): Matrix = TODO(this.toSt * 0 4 13 6 * 3 10 11 8 */ -fun fifteenGameMoves(matrix: Matrix, moves: List): Matrix = TODO() +fun fifteenGameMoves(matrix: Matrix, moves: List): Matrix { + val m = matrix + var zeroCell: Cell = m.indexOf(0) + moves.forEach { + val moveCell = m.indexOf(it) + if (moveCell != NOT_EXISTS && moveCell.near(zeroCell)) { + m.swap(zeroCell, moveCell) + zeroCell = moveCell + } else { + throw IllegalStateException("Such turn is impossible or number isn't exists") + } + } + return m +} /** * Очень сложная @@ -285,4 +476,153 @@ fun fifteenGameMoves(matrix: Matrix, moves: List): Matrix = TODO( * * Перед решением этой задачи НЕОБХОДИМО решить предыдущую */ +/* +val solution1 = createFilledMatrix(4,4, listOf(listOf(1, 2, 3, 4), + listOf(5, 6, 7, 8), + listOf(9, 10, 11, 12), + listOf(13, 14, 15, 0))) +val solution2 = createFilledMatrix(4,4, listOf(listOf(1, 2, 3, 4), + listOf(5, 6, 7, 8), + listOf(9, 10, 11, 12), + listOf(13, 15, 14, 0))) + +class State(val matrix: Matrix) { + + companion object { + var START = createMatrix(4,4,0) + set(value) { + field = value + solutionChoose() + } + var SOLUTION = createMatrix(4,4,0) + val ZERO_MATRIX = createMatrix(4,4,0) + + private fun solutionChoose() { + var N = 0 + val zeroRow = START.indexOf(0).row + 1 + val list = mutableListOf() + for (i in 0..3) + list += START.getRow(i) + for (i in 0..15) { + if (list[i] == 0) continue + for (j in i + 1..15) { + if (list[i] > list[j] && list[j] != 0) + N++ + } + } + N += zeroRow + SOLUTION = if (N % 2 == 0) solution1 else solution2 + } + } + + fun getCellsMoves(): List = this.matrix.findMoves(this.matrix.indexOf(0)) + + fun solved(): Boolean = this.matrix == State.SOLUTION + + fun zero(): Cell = this.matrix.indexOf(0) + + fun estimate(): Int { + var manhattan = 0 + for (row in 0..3) { + for (column in 0..3) { + val value = State.SOLUTION.indexOf(matrix[row, column]) + manhattan += abs(row - value.row) + abs(column - value.column) + } + } + return manhattan + linearConflict() + } + + fun linearConflict(): Int { + var conflicts = 0 + for (row in 0..3) { + for (column in 1..3) { + for (cell in 0..column - 1) { + val K = matrix[row, column] + val J = matrix[row, cell] + val TileKRow = K / 4 == row || (K / 4 == row + 1 && K % 4 == 0) //Goal-позиция тайла K в этом ряду? + val TileJRow = J / 4 == row || (J / 4 == row + 1 && J % 4 == 0) + if (TileJRow && TileKRow && J > K) + conflicts += 2 + } + } + } + return conflicts + } + +} + +val moves = mutableListOf() +val visited = mutableListOf>() +val finalMoves = mutableListOf() +var finished = 0 +var bestStep = Pair(Int.MAX_VALUE, Cell(-1, -1)) +fun limitedSearch(state: State, previous: Matrix, limit: Int, depth: Int, path: Int, moved: Cell): Boolean { + var found = false + for (move in state.getCellsMoves()) { + val zero = state.zero() + state.matrix.swap(zero, move) + if (state.matrix != previous && !visited.contains(state.matrix)) { + val firstMove = if (path == 0) move else moved + if (state.solved()) { + found = true + bestStep = Pair(path, firstMove) + } else { + val est = state.estimate() + val cost = est + path + 1 + if (path >= depth || cost > limit) { + if (est < bestStep.first) { + bestStep = Pair(est, firstMove) + } + } else { + val solution = limitedSearch(state, state.matrix.copyN(), limit, depth, path + 1, firstMove) + found = solution + } + } + } + state.matrix.swap(zero, move) + if (found) { + finalMoves.add(state.matrix[move]) + return true + } + } + finished++ + return false +} +*/ fun fifteenGameSolution(matrix: Matrix): List = TODO() +/*{ + + State.START = matrix + + var count = 0 + + val state = State(matrix) + var limit = state.estimate() + var solved = false + + if (state.matrix == State.SOLUTION) + return listOf() + + var previous = State.ZERO_MATRIX + while (!solved) { + bestStep = Pair(Int.MAX_VALUE, Cell(-1, -1)) + val solution = limitedSearch(state, previous, limit, 12, 0, Cell(-1, -1)) + if (solution) { + solved = true + return moves + finalMoves.reversed() + } else { + previous = state.matrix.copyN() + visited.add(previous) + moves.add(state.matrix[bestStep.second]) + state.matrix.swap(state.zero(), bestStep.second) + } + if (count % 2 == 0) { + println("$count searches are complete, pathes = $finished, current depth = $limit") + println("${moves.size}[${state.estimate()}] : $moves") + } + limit += 3 + count++ + } + return listOf() +} +*/ diff --git a/src/lesson8/task1/Files.kt b/src/lesson8/task1/Files.kt index 4a0e96305..88b3f173c 100644 --- a/src/lesson8/task1/Files.kt +++ b/src/lesson8/task1/Files.kt @@ -54,7 +54,12 @@ fun alignFile(inputName: String, lineLength: Int, outputName: String) { * */ fun countSubstrings(inputName: String, substrings: List): Map { - TODO() + val text = File(inputName).readText().toLowerCase() + val map = mutableMapOf() + for (str in substrings) { + map.put(str, text.split(str.toLowerCase()).size - 1) + } + return map } @@ -72,7 +77,12 @@ fun countSubstrings(inputName: String, substrings: List): Map chars[R.groupValues[1]] ?: R.groupValues[1]} )) + writer.close() + } /** @@ -93,7 +103,16 @@ fun sibilants(inputName: String, outputName: String) { * */ fun centerFile(inputName: String, outputName: String) { - TODO() + val lines = File(inputName).readLines().map { it.trim() } + val maxStr = lines.map { it.length }.max() ?: 0 + val writer = File(outputName).writer() + val str = StringBuilder() + for (line in lines) { + (0..((maxStr - line.length) / 2 - 1)).forEach { str.append(" ") } + str.appendln(line) + } + writer.write(str.toString()) + writer.close() } /** @@ -119,7 +138,32 @@ fun centerFile(inputName: String, outputName: String) { * */ fun alignFileByWidth(inputName: String, outputName: String) { - TODO() + val lines = File(inputName).readLines().map { it.trim() } + val maxStr = lines.map { it.length }.max() ?: 0 + val writer = File(outputName).writer() + val str = StringBuilder() + for (line in lines) { + if (line.isNotEmpty()) { + val spaces = maxStr - line.length + val words = line.split(" ") + if (words.size > 1) { + var extraSpaces = spaces % (words.size - 1) + val spacesPerWord = spaces / (words.size - 1) + for (i in 0..words.size - 2) { + str.append(words[i]) + (0..spacesPerWord).forEach { str.append(" ") } + if (extraSpaces > 0) { + str.append(" ") + extraSpaces-- + } + } + } + str.append(words.last()) + } + str.appendln() + } + writer.write(str.toString()) + writer.close() } /** @@ -136,9 +180,16 @@ fun alignFileByWidth(inputName: String, outputName: String) { * */ fun top20Words(inputName: String): Map { - TODO() + val words = mutableMapOf() + for (word in Regex("[a-zа-яё]+").findAll(File(inputName).readText().toLowerCase())) { + val value = word.value + words.put(value, (words[value] ?: 0) + 1) + } + return words.toList().sortedByDescending { it.second }.take(20).toMap() } + + /** * Средняя *