{"id":352502,"date":"2024-05-20T22:09:52","date_gmt":"2024-05-20T22:09:52","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=352502"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2024-05-20T22:09:52","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=352502","title":{"rendered":"<span>\u041f\u0440\u043e\u0441\u0442\u0430\u044f \u043d\u0435\u0439\u0440\u043e\u043d\u043d\u0430\u044f \u0441\u0435\u0442\u044c \u0431\u0435\u0437 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0438 \u043c\u0430\u0442\u0440\u0438\u0446. \u042d\u0432\u043e\u043b\u044e\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0415\u0441\u043b\u0438 \u0435\u0449\u0435 \u043d\u0435 \u0447\u0438\u0442\u0430\u043b\u0438, \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0439\u0442\u0435 <a href=\"https:\/\/habr.com\/ru\/articles\/755096\/\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0443\u044e \u0441\u0442\u0430\u0442\u044c\u044e.<\/a><\/p>\n<p>\u0412 \u043f\u0440\u043e\u0448\u043b\u044b\u0439 \u0440\u0430\u0437 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043a\u043b\u0430\u0441\u0441 \u043d\u0435\u0439\u0440\u043e\u043d\u043d\u043e\u0439 \u0441\u0435\u0442\u0438, \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u0436\u0435 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u043d\u0430 \u0435\u0435 \u043e\u0441\u043d\u043e\u0432\u0435 \u044d\u0432\u043e\u043b\u044e\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u0435\u043c \u0437\u0430\u0434\u0430\u0447\u0443: \u041d\u0435\u0439\u0440\u043e\u0441\u0435\u0442\u044c \u0434\u043e\u043b\u0436\u043d\u0430 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u0435\u043c \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0443\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043c\u044f\u0447. <\/p>\n<h2>\u0421\u0440\u0435\u0434\u0430 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f<\/h2>\n<p>\u041c\u043e\u044f \u0441\u0430\u043c\u0430\u044f (\u043d\u0435) \u043b\u044e\u0431\u0438\u043c\u0430\u044f \u0447\u0430\u0441\u0442\u044c &#8212; \u0444\u0438\u0437\u0438\u043a\u0430. \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043a\u043b\u0430\u0441\u0441 \u0434\u0432\u0443\u0445\u043c\u0435\u0440\u043d\u043e\u0433\u043e \u0432\u0435\u043a\u0442\u043e\u0440\u0430 \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u0440\u0430\u0441\u0447\u0435\u0442\u043e\u0432: \u043d\u043e\u0440\u043c\u0430\u043b\u0438 \u043a \u0434\u0430\u043d\u043d\u043e\u0439 \u043f\u0440\u044f\u043c\u043e\u0439 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u0435 \u0434\u0432\u0443\u0445 \u043f\u0440\u044f\u043c\u044b\u0445.<\/p>\n<details class=\"spoiler\">\n<summary>\u0414\u0432\u0443\u0445\u043c\u0435\u0440\u043d\u044b\u0439 \u0432\u0435\u043a\u0442\u043e\u0440 \u0438 \u0440\u0430\u0441\u0447\u0435\u0442\u044b<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">import random import time import tkinter as tk import math from copy import deepcopy as copy from neuro import NeuralNetwork import datetime import matplotlib.pyplot as plt  class Vector:     def __init__(self, x, y):         self.x = x         self.y = y      def __add__(self, other): #\u0441\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432\u0435\u043a\u0442\u043e\u0440\u043e\u0432         new = Vector(self.x + other.x, self.y + other.y)         return new      def __sub__(self, other): #\u0432\u044b\u0447\u0438\u0442\u0430\u043d\u0438\u0435 \u0432\u0435\u043a\u0442\u043e\u0440\u043e\u0432         new = Vector(self.x - other.x, self.y - other.y)         return new            def __mul__(self, other): #\u0443\u043c\u043d\u043e\u0436\u0435\u043d\u0438\u0435 \u0432\u0435\u043a\u0442\u043e\u0440\u0430 \u043d\u0430 \u0447\u0438\u0441\u043b\u043e         new = Vector(self.x * other, self.y * other)         return new      def length(self): #\u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u0434\u043b\u0438\u043d\u044b \u0432\u0435\u043a\u0442\u043e\u0440\u0430         return (self.x**2 + self.y**2) ** 0.5   def calculate_edge_normal(point1, point2):  # \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0440\u043c\u0430\u043b\u0438 \u043a \u0440\u0435\u0431\u0440\u0443     edge_vector = Vector(point2.x - point1.x, point2.y - point1.y)  # \u0412\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u0432\u0435\u043a\u0442\u043e\u0440\u0430 \u0440\u0435\u0431\u0440\u0430     edge_length = edge_vector.length()  # \u0412\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u0434\u043b\u0438\u043d\u044b \u0440\u0435\u0431\u0440\u0430      if edge_length == 0:         raise ValueError(\"The edge has zero length.\")  # \u0418\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435, \u0435\u0441\u043b\u0438 \u0434\u043b\u0438\u043d\u0430 \u0440\u0435\u0431\u0440\u0430 \u0440\u0430\u0432\u043d\u0430 \u043d\u0443\u043b\u044e      normalized_edge_vector = Vector(edge_vector.x \/ edge_length,                                     edge_vector.y \/ edge_length)  # \u041d\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0432\u0435\u043a\u0442\u043e\u0440\u0430 \u0440\u0435\u0431\u0440\u0430     normal_vector = Vector(-normalized_edge_vector.y, normalized_edge_vector.x)  # \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0432\u0435\u043a\u0442\u043e\u0440\u0430 \u043d\u043e\u0440\u043c\u0430\u043b\u0438     return normal_vector  # \u0412\u043e\u0437\u0432\u0440\u0430\u0442 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u043e\u0439 \u043d\u043e\u0440\u043c\u0430\u043b\u0438 \u043a \u0440\u0435\u0431\u0440\u0443   def lines_intersect(line1, line2):  # \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f \u0434\u0432\u0443\u0445 \u043e\u0442\u0440\u0435\u0437\u043a\u043e\u0432     x1, y1, x2, y2 = line1[0].x, line1[0].y, line1[1].x, line1[1].y  # \u0418\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 \u0442\u043e\u0447\u0435\u043a \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u043e\u0442\u0440\u0435\u0437\u043a\u0430     x3, y3, x4, y4 = line2[0].x, line2[0].y, line2[1].x, line2[1].y  # \u0418\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 \u0442\u043e\u0447\u0435\u043a \u0432\u0442\u043e\u0440\u043e\u0433\u043e \u043e\u0442\u0440\u0435\u0437\u043a\u0430          # \u0412\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u043d\u0430\u043a\u043b\u043e\u043d\u043e\u0432 (\u0443\u0433\u043b\u043e\u0432\u044b\u0445 \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442\u043e\u0432) \u043e\u0442\u0440\u0435\u0437\u043a\u043e\u0432, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044f \u0441\u043b\u0443\u0447\u0430\u0439 \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u043e\u0442\u0440\u0435\u0437\u043a\u043e\u0432     slope1 = (y2 - y1) \/ (x2 - x1) if x2 - x1 != 0 else float('inf')     slope2 = (y4 - y3) \/ (x4 - x3) if x4 - x3 != 0 else float('inf')          # \u0415\u0441\u043b\u0438 \u043d\u0430\u043a\u043b\u043e\u043d\u044b \u043e\u0442\u0440\u0435\u0437\u043a\u043e\u0432 \u0440\u0430\u0432\u043d\u044b, \u043e\u043d\u0438 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b \u0438 \u043d\u0435 \u043f\u0435\u0440\u0435\u0441\u0435\u043a\u0430\u044e\u0442\u0441\u044f     if slope1 == slope2:         return False          # \u0412\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 \u0442\u043e\u0447\u043a\u0438 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f     if slope1 == float('inf'):  # \u0415\u0441\u043b\u0438 \u043f\u0435\u0440\u0432\u044b\u0439 \u043e\u0442\u0440\u0435\u0437\u043e\u043a \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439         x = x1         y = slope2 * (x - x3) + y3     elif slope2 == float('inf'):  # \u0415\u0441\u043b\u0438 \u0432\u0442\u043e\u0440\u043e\u0439 \u043e\u0442\u0440\u0435\u0437\u043e\u043a \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439         x = x3         y = slope1 * (x - x1) + y1     else:  # \u0415\u0441\u043b\u0438 \u043e\u0431\u0430 \u043e\u0442\u0440\u0435\u0437\u043a\u0430 \u043d\u0435\u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0435         x = (slope1 * x1 - slope2 * x3 + y3 - y1) \/ (slope1 - slope2)         y = slope1 * (x - x1) + y1          # \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430, \u043b\u0435\u0436\u0438\u0442 \u043b\u0438 \u0442\u043e\u0447\u043a\u0430 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u0433\u0440\u0430\u043d\u0438\u0446 \u043e\u0431\u043e\u0438\u0445 \u043e\u0442\u0440\u0435\u0437\u043a\u043e\u0432     if ((x1 &lt;= x &lt;= x2 or x2 &lt;= x &lt;= x1) and         (x3 &lt;= x &lt;= x4 or x4 &lt;= x &lt;= x3)) and \\             ((y1 &lt;= y &lt;= y2 or y2 &lt;= y &lt;= y1) and              (y3 &lt;= y &lt;= y4 or y4 &lt;= y &lt;= y3)):         return True  # \u0422\u043e\u0447\u043a\u0430 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f \u043b\u0435\u0436\u0438\u0442 \u043d\u0430 \u043e\u0431\u043e\u0438\u0445 \u043e\u0442\u0440\u0435\u0437\u043a\u0430\u0445          return False  # \u0422\u043e\u0447\u043a\u0430 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f \u043d\u0435 \u043b\u0435\u0436\u0438\u0442 \u043d\u0430 \u043e\u0434\u043d\u043e\u043c \u0438\u0437 \u043e\u0442\u0440\u0435\u0437\u043a\u043e\u0432   G = Vector(0, .1)<\/code><\/pre>\n<p>G &#8212; \u0433\u0440\u0430\u0432\u0438\u0442\u0430\u0446\u0438\u043e\u043d\u043d\u0430\u044f \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u0430\u044f, \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u0430\u0434\u0440 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u0438\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0435\u0435 \u043a \u0432\u0435\u043a\u0442\u043e\u0440\u0443 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043e\u0432<\/p>\n<\/div>\n<\/details>\n<p>\u0418 \u043a\u043b\u0430\u0441\u0441\u044b \u0434\u043b\u044f \u043c\u044f\u0447\u0430 \u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b:<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043b\u0430\u0441\u0441\u044b \u043c\u044f\u0447\u0430 \u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">class Ball:     def __init__(self, x, y, radius):         # \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 \u043a\u043b\u0430\u0441\u0441\u0430 Ball \u0441 \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438         self.pos = Vector(x, y)  # \u041f\u043e\u0437\u0438\u0446\u0438\u044f \u0448\u0430\u0440\u0430 \u043a\u0430\u043a \u0432\u0435\u043a\u0442\u043e\u0440         self.radius = radius  # \u0420\u0430\u0434\u0438\u0443\u0441 \u0448\u0430\u0440\u0430         self.movement = Vector(0, 1)  # \u0412\u0435\u043a\u0442\u043e\u0440 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0448\u0430\u0440\u0430         self.collide = False  # \u0424\u043b\u0430\u0433 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f \u0441 \u0433\u0440\u0430\u043d\u0438\u0446\u0435\u0439         self.weight = 1  # \u041c\u0430\u0441\u0441\u0430 \u0448\u0430\u0440\u0430      def next_frame(self, edges):         collide = False  # \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0444\u043b\u0430\u0433\u0430 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f          normals = []  # \u0421\u043f\u0438\u0441\u043e\u043a \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043d\u043e\u0440\u043c\u0430\u043b\u0435\u0439 \u043a \u0433\u0440\u0430\u043d\u044f\u043c         intersect = []  # \u0421\u043f\u0438\u0441\u043e\u043a \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0444\u043b\u0430\u0433\u043e\u0432 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f         for i, edge in enumerate(edges):             normal = calculate_edge_normal(edge[0], edge[1])  # \u0412\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u043d\u043e\u0440\u043c\u0430\u043b\u0438 \u043a \u0433\u0440\u0430\u043d\u0438             normals.append(normal)             height = (self.pos, self.pos + (normal * self.radius))  # \u0412\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u0432\u044b\u0441\u043e\u0442\u044b \u043e\u0442 \u0446\u0435\u043d\u0442\u0440\u0430 \u0448\u0430\u0440\u0430 \u043a \u0433\u0440\u0430\u043d\u0438              intersect.append(lines_intersect(edge, height))  # \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f          # \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u0439 \u0441 \u0433\u0440\u0430\u043d\u044f\u043c\u0438         # \u0415\u0441\u043b\u0438 \u0434\u0432\u0435 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f, \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0435\u0435 \u043f\u043e \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u044e         # \u041f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0438 \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0448\u0430\u0440\u0430         # \u0415\u0441\u043b\u0438 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f \u043d\u0435\u0442, \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u0435 \u0448\u0430\u0440\u0430 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u0442\u0441\u044f \u0431\u0435\u0437 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439         # \u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0448\u0430\u0440\u0430 \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0432\u0435\u043a\u0442\u043e\u0440 \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f G (\u0433\u0440\u0430\u0432\u0438\u0442\u0430\u0446\u0438\u0438)         for i in range(4):             if intersect[i] and intersect[i + 1]:                 if (intersect[i] - self.pos).length() &lt;= (intersect[i + 1] - self.pos).length():                     self.movement = (normals[i] * self.movement.length()) * -1 * self.weight                     self.pos -= normals[i]                 else:                     self.movement = (normals[i + 1] * self.movement.length()) * -1 * self.weight                     self.pos -= normals[i + 1]              elif intersect[i]:                 self.movement = (normals[i] * self.movement.length()) * -1 * self.weight                 self.pos -= normals[i]              elif intersect[i + 1]:                 self.movement = (normals[i + 1] * self.movement.length()) * -1 * self.weight                 self.pos -= normals[i + 1]          self.collide = any(intersect)  # \u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0444\u043b\u0430\u0433\u0430 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f         self.movement += G * self.weight  # \u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0433\u0440\u0430\u0432\u0438\u0442\u0430\u0446\u0438\u0438 \u043a \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438         self.pos += self.movement  # \u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u043a \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0448\u0430\u0440\u0430   class Platform:     def __init__(self, x, y, height, width, rotate):         self.pos = Vector(x, y)         self.height = height         self.width = width         self.rotate = rotate<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043b\u0430\u0441\u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">class RotatingRectangleApp:     def __init__(self, root):         # \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f         self.root = root         self.root.title(\"Rotate Rectangle\")         self.canvas = tk.Canvas(root, width=1280, height=1280)         self.canvas.pack()          # \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u043e\u0432 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0438 \u0434\u0432\u0443\u0445 \u0448\u0430\u0440\u043e\u0432         self.rectangle = Platform(1280\/\/2, 1280\/\/2, 10, 800, 0)         self.ball = Ball(1280\/\/2-100, 1280\/\/2 - 500, 25)         self.ball1 = Ball(1280\/\/2+100, 1280\/\/2 - 300, 25)                  # \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043f\u0440\u044f\u043c\u043e\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430 \u043d\u0430 \u0445\u043e\u043b\u0441\u0442\u0435         self.drawing_rectangle = self.canvas.create_rectangle(self.rectangle.pos.x, self.rectangle.pos.y, self.rectangle.width, self.rectangle.height, outline='red', fill='red', width=2)                  # \u041f\u0440\u0438\u0432\u044f\u0437\u043a\u0430 \u043a\u043b\u0430\u0432\u0438\u0448 \u043a \u043c\u0435\u0442\u043e\u0434\u0430\u043c         self.root.bind(\"&lt;Right>\", self.rotate_right)         self.root.bind(\"&lt;Left>\", self.rotate_left)         self.root.bind(\"&lt;Up>\", self.set_pause)      def rotate_right(self, event):         # \u041c\u0435\u0442\u043e\u0434 \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043f\u0440\u044f\u043c\u043e\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430 \u0432\u043f\u0440\u0430\u0432\u043e         self.rectangle.rotate = self.rectangle.rotate + 1  # \u0412\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043d\u0430 1 \u0433\u0440\u0430\u0434\u0443\u0441      def set_pause(self, event):         # \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438\/\u0432\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u0448\u0430\u0440\u043e\u0432         global pause         pause = not pause      def rotate_left(self, event):         # \u041c\u0435\u0442\u043e\u0434 \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043f\u0440\u044f\u043c\u043e\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430 \u0432\u043b\u0435\u0432\u043e         self.rectangle.rotate = self.rectangle.rotate - 1  # \u0412\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043d\u0430 1 \u0433\u0440\u0430\u0434\u0443\u0441      def draw_rectangle(self):         # \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0435\u0433\u043e\u0441\u044f \u043f\u0440\u044f\u043c\u043e\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430                  # \u0412\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 \u0443\u0433\u043b\u043e\u0432 \u043f\u0440\u044f\u043c\u043e\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430 \u043f\u043e\u0441\u043b\u0435 \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f         center_x = self.rectangle.pos.x         center_y = self.rectangle.pos.y         angle_rad = math.radians(self.rectangle.rotate)                  corner_coords = [             self.rotate_point(self.rectangle.pos.x - self.rectangle.width\/2, self.rectangle.pos.y - self.rectangle.height\/2, center_x, center_y, angle_rad),             self.rotate_point(self.rectangle.pos.x + self.rectangle.width\/2, self.rectangle.pos.y - self.rectangle.height\/2, center_x, center_y, angle_rad),             self.rotate_point(self.rectangle.pos.x + self.rectangle.width\/2, self.rectangle.pos.y + self.rectangle.height\/2, center_x, center_y, angle_rad),             self.rotate_point(self.rectangle.pos.x - self.rectangle.width\/2, self.rectangle.pos.y + self.rectangle.height\/2, center_x, center_y, angle_rad)         ]          edges = [(Vector(corner_coords[i%4][0], corner_coords[i%4][1]), Vector(corner_coords[(i+1)%4][0], corner_coords[(i+1)%4][1])) for i in range(4)]          # \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043f\u0440\u044f\u043c\u043e\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430 \u043d\u0430 \u0445\u043e\u043b\u0441\u0442\u0435         self.drawing_rectangle = self.canvas.create_polygon(corner_coords, outline='red', fill='red', width=2)         return edges      def draw_ball(self):         # \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0448\u0430\u0440\u043e\u0432         coords = [             (self.ball.pos.x - self.ball.radius, self.ball.pos.y - self.ball.radius),             (self.ball.pos.x + self.ball.radius, self.ball.pos.y + self.ball.radius),         ]          self.canvas.create_oval(coords, outline='black', fill='', width=2)          coords = [             (self.ball1.pos.x - self.ball1.radius, self.ball1.pos.y - self.ball1.radius),             (self.ball1.pos.x + self.ball1.radius, self.ball1.pos.y + self.ball1.radius),         ]          self.canvas.create_oval(coords, outline='black', fill='', width=2)      def rotate_point(self, x, y, cx, cy, angle_rad):         # \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0442\u043e\u0447\u043a\u0438 \u0432\u043e\u043a\u0440\u0443\u0433 \u0446\u0435\u043d\u0442\u0440\u0430         new_x = cx + (x - cx) * math.cos(angle_rad) - (y - cy) * math.sin(angle_rad)         new_y = cy + (x - cx) * math.sin(angle_rad) + (y - cy) * math.cos(angle_rad)         return new_x, new_y      def clear_canvas(self):         # \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043e\u0447\u0438\u0441\u0442\u043a\u0438 \u0445\u043e\u043b\u0441\u0442\u0430         self.canvas.delete(\"all\") <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<h2>\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f<\/h2>\n<p>\u0423 \u043d\u0435\u0439\u0440\u043e\u0441\u0435\u0442\u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430:<\/p>\n<p>7 \u0432\u0445\u043e\u0434\u043d\u044b\u0445 \u043d\u0435\u0439\u0440\u043e\u043d\u043e\u0432, \u043f\u043e 20 \u043d\u0435\u0439\u0440\u043e\u043d\u043e\u0432 \u0432 \u0434\u0432\u0443\u0445 \u0441\u043a\u0440\u044b\u0442\u044b\u0445 \u0441\u043b\u043e\u044f\u0445, 3 \u0432\u044b\u0445\u043e\u0434\u043d\u044b\u0445 \u0438 1 \u043d\u0435\u0439\u0440\u043e\u043d \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u043b\u043e\u044f, \u043a\u0440\u043e\u043c\u0435 \u0432\u044b\u0445\u043e\u0434\u043d\u043e\u0433\u043e. \u041d\u0435\u0439\u0440\u043e\u0441\u0435\u0442\u0438 \u043d\u0430 \u0432\u0445\u043e\u0434 \u0434\u0430\u0435\u0442\u0441\u044f: \u041f\u043e\u0432\u043e\u0440\u043e\u0442 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b, \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b, \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043c\u044f\u0447\u0430 \u0438 \u0435\u0433\u043e \u0432\u0435\u043a\u0442\u043e\u0440 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f. \u041d\u0435\u0439\u0440\u043e\u0441\u0435\u0442\u044c \u0434\u043e\u043b\u0436\u043d\u0430 \u0432\u044b\u0432\u0435\u0441\u0442\u0438 \u0443\u0433\u043e\u043b, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0432\u0435\u0440\u043d\u0435\u0442\u0441\u044f \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0438 \u0432\u0435\u043a\u0442\u043e\u0440 \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u043d\u0430 \u0441\u0434\u0432\u0438\u043d\u0435\u0442\u0441\u044f.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/eae\/bb2\/261\/eaebb2261e1e9391b088ed5421cf62e6.png\" alt=\"\u041d\u0435\u043e\u0431\u0443\u0447\u0435\u043d\u043d\u0430\u044f \u043d\u0435\u0439\u0440\u043e\u0441\u0435\u0442\u044c\" title=\"\u041d\u0435\u043e\u0431\u0443\u0447\u0435\u043d\u043d\u0430\u044f \u043d\u0435\u0439\u0440\u043e\u0441\u0435\u0442\u044c\" width=\"640\" height=\"480\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/eae\/bb2\/261\/eaebb2261e1e9391b088ed5421cf62e6.png\"\/><\/p>\n<div><figcaption>\u041d\u0435\u043e\u0431\u0443\u0447\u0435\u043d\u043d\u0430\u044f \u043d\u0435\u0439\u0440\u043e\u0441\u0435\u0442\u044c<\/figcaption><\/div>\n<\/figure>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043f\u043e\u043f\u0443\u043b\u044f\u0446\u0438\u044e \u0438\u0437 20\u0442\u0438 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u0445 \u043d\u0435\u0439\u0440\u043e\u043d\u043d\u044b\u0445 \u0441\u0435\u0442\u0435\u0439 \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0438\u0445 \u0432 \u0441\u0438\u043c\u0443\u043b\u044f\u0446\u0438\u044e.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/6fa\/670\/7f2\/6fa6707f2cd0a810cd0847d74a0ec05a.png\" width=\"1463\" height=\"809\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/6fa\/670\/7f2\/6fa6707f2cd0a810cd0847d74a0ec05a.png\"\/><\/figure>\n<p>\u0412\u044b\u0431\u0438\u0440\u0430\u0435\u043c 4\u0435\u0445 \u0441\u0430\u043c\u044b\u0445 \u0443\u0441\u043f\u0435\u0448\u043d\u044b\u0445 \u0438 \u043a\u0430\u0436\u0434\u043e\u043c\u0443 \u0441\u043e\u0437\u0434\u0430\u0435\u043c 4 \u043f\u043e\u0442\u043e\u043c\u043a\u0430 \u0441 \u043c\u0443\u0442\u0430\u0446\u0438\u044f\u043c\u0438. \u0412\u0441\u0435\u0433\u043e \u043e\u043f\u044f\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f 20 \u043e\u0441\u043e\u0431\u0435\u0439(4 \u043e\u0441\u043e\u0431\u0438, 16 \u043c\u0443\u0442\u0430\u043d\u0442\u043e\u0432), \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u044b \u043e\u043f\u044f\u0442\u044c \u0437\u0430\u043a\u0438\u0434\u044b\u0432\u0430\u0435\u043c \u0432 \u0441\u0438\u043c\u0443\u043b\u044f\u0446\u0438\u044e.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/643\/e52\/545\/643e52545062a378caf7f432b7729b14.png\" width=\"2063\" height=\"1546\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/643\/e52\/545\/643e52545062a378caf7f432b7729b14.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\"># \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u043e\u043f\u0443\u043b\u044f\u0446\u0438\u0438 \u043d\u0435\u0439\u0440\u043e\u043d\u043d\u044b\u0445 \u0441\u0435\u0442\u0435\u0439 generation = [NeuralNetwork([7, 20, 20, 3]) for i in range(20)]  gen_count = 0 graph = []  # \u0421\u043f\u0438\u0441\u043e\u043a \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0439  # \u0411\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u0446\u0438\u043a\u043b \u044d\u0432\u043e\u043b\u044e\u0446\u0438\u0438 \u0438 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f while True:     gen_count += 1     generation_times = []  # \u0421\u043f\u0438\u0441\u043e\u043a \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u0441\u0435\u0442\u0438 \u0432 \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0438      for i, nn in enumerate(generation):         root = tk.Tk()         app = RotatingRectangleApp(root)          # \u0417\u0430\u043f\u0443\u0441\u043a \u0441\u0438\u043c\u0443\u043b\u044f\u0446\u0438\u0438 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u0448\u0430\u0440\u0430 \u0438 \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043f\u0440\u044f\u043c\u043e\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430         start_time = datetime.datetime.now()         frames_count = -1         while 0 &lt;= app.ball.pos.x &lt;= 1280 and 0 &lt;= app.ball.pos.y &lt;= 1280:             frames_count += 1             edges = app.draw_rectangle()             app.ball.next_frame(edges)             input = [app.rectangle.rotate\/360, app.rectangle.pos.x\/1280, app.rectangle.pos.y\/1280, app.ball.pos.x\/1280, app.ball.pos.y\/1280, app.ball.movement.x, app.ball.movement.y]             formatted_input = [math.tanh(el) for el in input]              # \u041f\u0440\u044f\u043c\u043e\u0439 \u043f\u0440\u043e\u0445\u043e\u0434 \u0447\u0435\u0440\u0435\u0437 \u043d\u0435\u0439\u0440\u043e\u043d\u043d\u0443\u044e \u0441\u0435\u0442\u044c             out = nn.out(formatted_input)[-1]              # \u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043f\u0440\u044f\u043c\u043e\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430 \u0438 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u0448\u0430\u0440\u0430 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0432\u044b\u0445\u043e\u0434\u0430 \u0441\u0435\u0442\u0438             app.rectangle.rotate = (app.rectangle.rotate + out[0]) % 360             app.rectangle.pos += Vector(out[1], out[2])              app.draw_ball()             root.update()             if pause:                 time.sleep(0.01)             app.clear_canvas()                  root.destroy()         all_time = frames_count         generation_times.append(all_time)          # \u042d\u0432\u043e\u043b\u044e\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u043e\u0442\u0431\u043e\u0440: \u0432\u044b\u0431\u043e\u0440 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u044b\u0445 \u0441\u0435\u0442\u0435\u0439     sorted_times = sorted(generation_times)[-4:]     lucky = [generation_times.index(el) for el in sorted_times]      if max(generation_times) >= 15000:         for el in lucky:             generation[el].save(f'dumps\/{gen_count}-{el}-{generation_times[el]}.nn')      # \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u044f \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043b\u0443\u0447\u0448\u0438\u0445 \u0441\u0435\u0442\u0435\u0439 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u044f     new_generation = [copy(generation[lucky[0]]) for el in range(5)] + [copy(generation[lucky[1]]) for el in range(5)] + [copy(generation[lucky[2]]) for el in range(5)] + [copy(generation[lucky[3]]) for el in range(5)]     k_mut = 0.1     for i in range(len(new_generation)):         if i % 5 != 0:             new_generation[i].mutate(k_mut)      generation = new_generation     graph.append(max(generation_times))          # \u0412\u044b\u0432\u043e\u0434 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0438     print(gen_count, generation_times, lucky, max(generation_times))     print(generation[0].difference(generation[1]))      # \u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0433\u0440\u0430\u0444\u0438\u043a\u0430 \u0441 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430\u043c\u0438     plt.close()     plt.plot(graph[-100:])     plt.show(block=False)     plt.pause(0.0000001) <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<h2>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u043c\u0443\u0442\u0430\u0446\u0438\u0438<\/h2>\n<p>\u0414\u043b\u044f \u043a\u043b\u0430\u0441\u0441\u0430 \u043d\u0435\u0439\u0440\u043e\u043d\u043d\u043e\u0439 \u0441\u0435\u0442\u0438 \u0438\u0437 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0435\u0449\u0435 \u0434\u0432\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438: <\/p>\n<p>\u041c\u0443\u0442\u0430\u0446\u0438\u044f &#8212; \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0432\u0435\u0441\u043e\u0432. \u041f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0431\u043e\u0440 \u0432\u0435\u0441\u043e\u0432 \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u043c \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u0435.<\/p>\n<pre><code class=\"python\">    def mutate(self, mutate_k):         for layer in range(len(self.weights)):             for inp in range(len(self.weights[layer])):                 for outp in range(len(self.weights[layer][inp])):                     self.weights[layer][inp][outp] += random.uniform(-mutate_k, mutate_k)<\/code><\/pre>\n<p>\u0420\u0430\u0437\u043d\u0438\u0446\u0430 \u0432 \u0432\u0435\u0441\u0430\u0445. \u042d\u0442\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043d\u0443\u0436\u043d\u0430 \u0434\u043b\u044f \u043e\u0442\u043b\u0430\u0434\u043a\u0438 \u0438 \u043f\u0440\u043e\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u0440\u0430\u0437\u043d\u0438\u0446\u044b \u043c\u0435\u0436\u0434\u0443 \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u044f\u043c\u0438.<\/p>\n<pre><code class=\"python\">    def difference(self, other):         if self.neuron_size != other.neuron_size:             return None         difference_count = 0         for layer in range(len(self.weights)):             for inp in range(len(self.weights[layer])):                 for outp in range(len(self.weights[layer][inp])):                     difference_count += abs(self.weights[layer][inp][outp] - other.weights[layer][inp][outp])          return difference_count <\/code><\/pre>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u043d\u0435\u0439\u0440\u043e\u0441\u0435\u0442\u0438 (neuro.py)<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">import math import random import time import datetime import json from copy import copy  activation = math.tanh deactivation = math.tanh   class NeuralNetwork:     def __init__(self, neurons_size: list, weights: list = None):         self.neuron_size = neurons_size         for i in range(len(neurons_size) - 1):             self.neuron_size[i] += 1          if weights is None:             self.weights = []             for i in range(len(neurons_size) - 1):                 self.weights.append(                     [[random.uniform(-1, 1) for x in range(neurons_size[i + 1])] for y in range(neurons_size[i])])         else:             self.weights = weights      def out(self, inp):         out = [inp + [1]]         for i in range(1, len(self.weights) + 1):             a = []             for j in range(self.neuron_size[i]):                 s = sum([out[i - 1][k] * self.weights[i - 1][k][j] for k in range(self.neuron_size[i - 1])])                 a.append(activation(s))             if i != len(self.weights):                 a += [1]             out.append(a)         return out      def correct(self, inp, answer, learning_rate=0.1):         out = self.out(inp)         errors = [[answer[i] - out[-1][i] for i in range(len(out[-1]))]]          for i in range(len(self.weights) - 1, 0, -1):             a = []             for j in range(self.neuron_size[i]):                 s = sum([errors[0][k] * self.weights[i][j][k] for k in range(self.neuron_size[i + 1])])                 a.append((1 - out[i][j] ** 2) * s)             errors.insert(0, a)          for i in range(len(self.weights)):             for j in range(self.neuron_size[i]):                 for k in range(self.neuron_size[i + 1]):                     self.weights[i][j][k] += learning_rate * errors[i][k] * out[i][j]          error_count = sum([sum(abs(en) for en in el) for el in errors])         return out, error_count      def mutate(self, mutate_k):         for layer in range(len(self.weights)):             for inp in range(len(self.weights[layer])):                 for outp in range(len(self.weights[layer][inp])):                     self.weights[layer][inp][outp] += random.uniform(-mutate_k, mutate_k)      def difference(self, other):         if self.neuron_size != other.neuron_size:             return None         difference_count = 0         for layer in range(len(self.weights)):             for inp in range(len(self.weights[layer])):                 for outp in range(len(self.weights[layer][inp])):                     difference_count += abs(self.weights[layer][inp][outp] - other.weights[layer][inp][outp])          return difference_count      def save(self, name):         with open(name, 'w') as f:             neuron_size = copy(self.neuron_size)             for i in range(len(neuron_size) - 1):                 neuron_size[i] -= 1             f.write(json.dumps({'shape': neuron_size, 'weights': self.weights}))      def open(name):         with open(name, 'r') as f:             data = json.loads(f.read())             return NeuralNetwork(data['shape'], data['weights'])      def show(self, name):         import matplotlib.pyplot as plt         import networkx as nx         from networkx.drawing.nx_agraph import graphviz_layout          G = nx.DiGraph()          for layer in range(len(self.neuron_size)):             for neuron in range(self.neuron_size[layer]):                 G.add_node((layer, neuron))          for layer in range(len(self.neuron_size) - 1):             for from_neuron in range(self.neuron_size[layer]):                 for to_neuron in range(self.neuron_size[layer + 1]):                     weight = self.weights[layer][from_neuron][to_neuron]                     G.add_edge((layer, from_neuron), (layer + 1, to_neuron), weight=weight)          pos = graphviz_layout(G, prog='dot', args=\"-Grankdir=LR\")          edge_widths = [2 + abs(G.edges[edge]['weight']) for edge in G.edges]         edge_alpha = [abs(activation(G.edges[edge]['weight'])) \/ 2 for edge in G.edges]         edge_colors = ['green' if G.edges[edge]['weight'] >= 0 else 'red' for edge in G.edges]          nx.draw_networkx_nodes(G, pos, node_size=300, node_color='skyblue', alpha=0.8)          nx.draw_networkx_edges(G, pos, width=edge_widths, alpha=edge_alpha, edge_color=edge_colors, arrows=True)          layer_labels = {}         for layer in range(len(self.neuron_size)):             for neuron in range(self.neuron_size[layer]):                 layer_labels[(layer, neuron)] = f\"{neuron}\"         nx.draw_networkx_labels(G, pos, labels=layer_labels, font_size=12, font_color='r')          plt.axis('off')         plt.title(f\"Neural Network Weights\")         plt.savefig(f'{name}.png') <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u0441\u0440\u0435\u0434\u044b \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f (balance.py)<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">import random import time import tkinter as tk import math from copy import deepcopy as copy from neuro import NeuralNetwork import datetime import matplotlib.pyplot as plt   class Vector:     def __init__(self, x, y):         self.x = x         self.y = y      def __add__(self, other):         new = Vector(self.x + other.x, self.y + other.y)         return new      def __mul__(self, other):         new = Vector(self.x * other, self.y * other)         return new      def __sub__(self, other):         new = Vector(self.x - other.x, self.y - other.y)         return new      def length(self):         return (self.x**2 + self.y**2) ** 0.5   def calculate_edge_normal(point1, point2):  # \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0440\u043c\u0430\u043b\u0438 \u043a \u0440\u0435\u0431\u0440\u0443     edge_vector = Vector(point2.x - point1.x, point2.y - point1.y)  # \u0412\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u0432\u0435\u043a\u0442\u043e\u0440\u0430 \u0440\u0435\u0431\u0440\u0430     edge_length = edge_vector.length()  # \u0412\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u0434\u043b\u0438\u043d\u044b \u0440\u0435\u0431\u0440\u0430      if edge_length == 0:         raise ValueError(\"The edge has zero length.\")  # \u0418\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435, \u0435\u0441\u043b\u0438 \u0434\u043b\u0438\u043d\u0430 \u0440\u0435\u0431\u0440\u0430 \u0440\u0430\u0432\u043d\u0430 \u043d\u0443\u043b\u044e      normalized_edge_vector = Vector(edge_vector.x \/ edge_length,                                     edge_vector.y \/ edge_length)  # \u041d\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0432\u0435\u043a\u0442\u043e\u0440\u0430 \u0440\u0435\u0431\u0440\u0430     normal_vector = Vector(-normalized_edge_vector.y, normalized_edge_vector.x)  # \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0432\u0435\u043a\u0442\u043e\u0440\u0430 \u043d\u043e\u0440\u043c\u0430\u043b\u0438     return normal_vector  # \u0412\u043e\u0437\u0432\u0440\u0430\u0442 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u043e\u0439 \u043d\u043e\u0440\u043c\u0430\u043b\u0438 \u043a \u0440\u0435\u0431\u0440\u0443   def lines_intersect(line1, line2):     x1, y1, x2, y2 = line1[0].x, line1[0].y, line1[1].x, line1[1].y     x3, y3, x4, y4 = line2[0].x, line2[0].y, line2[1].x, line2[1].y      slope1 = (y2 - y1) \/ (x2 - x1) if x2 - x1 != 0 else float('inf')     slope2 = (y4 - y3) \/ (x4 - x3) if x4 - x3 != 0 else float('inf')      if slope1 == slope2:         return False      if slope1 == float('inf'):         x = x1         y = slope2 * (x - x3) + y3     elif slope2 == float('inf'):         x = x3         y = slope1 * (x - x1) + y1     else:         x = (slope1 * x1 - slope2 * x3 + y3 - y1) \/ (slope1 - slope2)         y = slope1 * (x - x1) + y1      if ((x1 &lt;= x &lt;= x2 or x2 &lt;= x &lt;= x1) and         (x3 &lt;= x &lt;= x4 or x4 &lt;= x &lt;= x3)) and \\             ((y1 &lt;= y &lt;= y2 or y2 &lt;= y &lt;= y1) and              (y3 &lt;= y &lt;= y4 or y4 &lt;= y &lt;= y3)):         return True      return False   G = Vector(0, .1)   class Ball:     def __init__(self, x, y, radius):         self.pos = Vector(x, y)         self.radius = radius         self.movement = Vector(0, 1)         self.collide = False         self.weight = 1      def next_frame(self, edges):         collide = False          normals = []         intersect = []         for i, edge in enumerate(edges):             normal = calculate_edge_normal(edge[0], edge[1])             normals.append(normal)             height = (self.pos, self.pos + (normal * self.radius))              intersect.append(lines_intersect(edge, height))          if intersect[0] and intersect[1]:             if (intersect[0] - self.pos).length() &lt;= (intersect[1] - self.pos).length():                 self.movement = (normals[0] * self.movement.length()) * -1 * self.weight                 self.pos -= normals[0]             else:                 self.movement = (normals[1] * self.movement.length()) * -1 * self.weight                 self.pos -= normals[1]          elif intersect[0]:             self.movement = (normals[0] * self.movement.length()) * -1 * self.weight             self.pos -= normals[0]          elif intersect[1]:             self.movement = (normals[1] * self.movement.length()) * -1 * self.weight             self.pos -= normals[1]          if intersect[2] and intersect[3]:             if (intersect[2] - self.pos).length() &lt;= (intersect[3] - self.pos).length():                 self.movement = (normals[2] * self.movement.length()) * -1 * self.weight                 self.pos -= normals[2]             else:                 self.movement = (normals[3] * self.movement.length()) * -1 * self.weight                 self.pos -= normals[3]          elif intersect[2]:             self.movement = (normals[2] * self.movement.length()) * -1 * self.weight             self.pos -= normals[2]          elif intersect[3]:             self.movement = (normals[3] * self.movement.length()) * -1 * self.weight             self.pos -= normals[3]          self.collide = any(intersect)         self.movement += G*self.weight         self.pos += self.movement   pause = False   class Platform:     def __init__(self, x, y, height, width, rotate):         self.pos = Vector(x, y)         self.height = height         self.width = width         self.rotate = rotate   class RotatingRectangleApp:     def __init__(self, root):         self.root = root         self.root.title(\"Rotate Rectangle\")          self.canvas = tk.Canvas(root, width=1280, height=1280)         self.canvas.pack()          self.rectangle = Platform(1280\/\/2, 1280\/\/2, 10, 800, 0)         self.ball = Ball(1280\/\/2-100, 1280\/\/2 - 500, 25)         self.drawing_rectangle = self.canvas.create_rectangle(self.rectangle.pos.x, self.rectangle.pos.y, self.rectangle.width, self.rectangle.height, outline='red', fill='red', width=2)         self.root.bind(\"&lt;Right>\", self.rotate_right)  # Bind right arrow key         self.root.bind(\"&lt;Left>\", self.rotate_left)         self.root.bind(\"&lt;Up>\", self.set_pause)      def rotate_right(self, event):         self.rectangle.rotate = self.rectangle.rotate + 1  # Rotate by 15 degrees each time      def set_pause(self, event):         global pause         pause = not pause      def rotate_left(self, event):         self.rectangle.rotate = self.rectangle.rotate - 1  # Rotate by 15 degrees each time      def draw_rectangle(self):         center_x = self.rectangle.pos.x         center_y = self.rectangle.pos.y          angle_rad = math.radians(self.rectangle.rotate)          corner_coords = [             self.rotate_point(self.rectangle.pos.x - self.rectangle.width\/2, self.rectangle.pos.y - self.rectangle.height\/2, center_x, center_y, angle_rad),             self.rotate_point(self.rectangle.pos.x + self.rectangle.width\/2, self.rectangle.pos.y - self.rectangle.height\/2, center_x, center_y, angle_rad),             self.rotate_point(self.rectangle.pos.x + self.rectangle.width\/2, self.rectangle.pos.y + self.rectangle.height\/2, center_x, center_y, angle_rad),             self.rotate_point(self.rectangle.pos.x - self.rectangle.width\/2, self.rectangle.pos.y + self.rectangle.height\/2, center_x, center_y, angle_rad)         ]          edges = [(Vector(corner_coords[i%4][0], corner_coords[i%4][1]), Vector(corner_coords[(i+1)%4][0], corner_coords[(i+1)%4][1])) for i in range(4)]          self.drawing_rectangle = self.canvas.create_polygon(corner_coords, outline='red', fill='red', width=2)         return edges      def draw_ball(self):         coords = [             (self.ball.pos.x - self.ball.radius, self.ball.pos.y - self.ball.radius),             (self.ball.pos.x + self.ball.radius, self.ball.pos.y + self.ball.radius),         ]          self.canvas.create_oval(coords, outline='black', fill='', width=2)      def rotate_point(self, x, y, cx, cy, angle_rad):         new_x = cx + (x - cx) * math.cos(angle_rad) - (y - cy) * math.sin(angle_rad)         new_y = cy + (x - cx) * math.sin(angle_rad) + (y - cy) * math.cos(angle_rad)         return new_x, new_y      def clear_canvas(self):         self.canvas.delete(\"all\")   if __name__ == \"__main__\":     graph = []     generation = [NeuralNetwork([7, 20, 20, 3]) for i in range(20)]     gen_count = 0     while True:         gen_count += 1         generation_times = []         for i, nn in enumerate(generation):             root = tk.Tk()              app = RotatingRectangleApp(root)             start_time = datetime.datetime.now()             frames_count = -1             while 0 &lt;= app.ball.pos.x &lt;= 1280 and 0 &lt;= app.ball.pos.y &lt;= 1280:                 frames_count += 1                 #app.rectangle.rotate = math.cos(app.rectangle.rotate)*360                 edges = app.draw_rectangle()                 app.ball.next_frame(edges)                 input = [app.rectangle.rotate\/360, app.rectangle.pos.x\/1280, app.rectangle.pos.y\/1280, app.ball.pos.x\/1280, app.ball.pos.y\/1280, app.ball.movement.x, app.ball.movement.y]                 formatted_input = [math.tanh(el) for el in input]                 out = nn.out(formatted_input)[-1]                 app.rectangle.rotate = (app.rectangle.rotate + out[0]) % 360                 app.rectangle.pos += Vector(out[1], out[2])                 #if gen_count % 100 == 0 or frames_count >= 20000:                 app.draw_ball()                 root.update()                 if pause:                     time.sleep(0.01)                 app.clear_canvas()             root.destroy()             all_time = frames_count             generation_times.append(all_time)          root.mainloop()         sorted_times = sorted(generation_times)[-4:]         lucky = [generation_times.index(el) for el in sorted_times]          if max(generation_times) >= 15000:             for el in lucky:                 generation[el].save(f'dumps\/{gen_count}-{el}-{generation_times[el]}.nn')          new_generation = [copy(generation[lucky[0]]) for el in range(5)] + [copy(generation[lucky[1]]) for el in range(5)] + [copy(generation[lucky[2]]) for el in range(5)] + [copy(generation[lucky[3]]) for el in range(5)]         k_mut = 0.1         for i in range(len(new_generation)):             if i % 5 != 0:                 new_generation[i].mutate(k_mut)          generation = new_generation         graph.append(max(generation_times))         print(gen_count, generation_times, lucky, max(generation_times))         print(generation[0].difference(generation[1]))         plt.close()         plt.plot(graph[-100:])         plt.show(block=False)         plt.pause(0.0000001) <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<h2>\u041e\u0431\u0443\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f &#8212; \u043f\u0435\u0440\u0432\u044b\u0435 \u043e\u0441\u043e\u0431\u0438 \u043d\u0435 \u043f\u043e\u043d\u0438\u043c\u0430\u044e\u0442, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c, \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e \u0432\u0440\u0430\u0449\u0430\u044f \u0438 \u0434\u0432\u0438\u0433\u0430\u044f \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0443, \u0445\u043e\u0442\u044f \u0438\u043d\u043e\u0433\u0434\u0430 \u0443 \u043d\u0438\u0445 \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u044e\u0442\u0441\u044f \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f. <span class=\"habrahidden\">\u0412\u0438\u0434\u0435\u043b\u0438, \u043a\u0430\u043a\u00a0\u043a\u0440\u0443\u0442\u0430\u043d\u0443\u043b?\u041e_\u043e<\/span><\/p>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/64dd57523eb8e176bfb6dc4c\" data-style=\"\" id=\"64dd57523eb8e176bfb6dc4c\" width=\"\"><\/div>\n<p>\u0423\u0436\u0435 \u043d\u0430 9\u043e\u043c \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0438 \u0431\u044b\u043b \u043f\u0440\u0435\u043e\u0434\u043e\u043b\u0435\u043d \u0440\u0443\u0431\u0435\u0436 \u0432 20 \u0442\u044b\u0441\u044f\u0447 \u043a\u0430\u0434\u0440\u043e\u0432.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f9b\/b0e\/995\/f9bb0e995e08bbe1344727cae8e4f8ef.png\" width=\"1070\" height=\"778\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f9b\/b0e\/995\/f9bb0e995e08bbe1344727cae8e4f8ef.png\"\/><\/figure>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/64ddf8c1ff7a727696c94664\" data-style=\"\" id=\"64ddf8c1ff7a727696c94664\" width=\"\"><\/div>\n<p>\u0425\u043e\u0442\u044c \u043d\u0435\u0439\u0440\u043e\u0441\u0435\u0442\u044c \u0438 \u043f\u0440\u043e\u0438\u0433\u0440\u0430\u043b\u0430 \u0441\u043f\u0443\u0441\u0442\u044f 20 \u0442\u044b\u0441\u044f\u0447 \u043a\u0430\u0434\u0440\u043e\u0432, \u043d\u043e \u0441\u043f\u0443\u0441\u0442\u044f \u0435\u0449\u0435 \u043f\u0430\u0440\u0443 \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0439 \u043b\u0435\u0433\u043a\u043e \u0434\u0435\u0440\u0436\u0430\u043b\u0430\u0441\u044c \u0431\u044b \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u043e. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0443\u0441\u043b\u043e\u0436\u043d\u0438\u043c \u0437\u0430\u0434\u0430\u0447\u0443 &#8212; \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432\u0442\u043e\u0440\u043e\u0439 \u043c\u044f\u0447.<\/p>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/64de196b72e08276d78fd5f9\" data-style=\"\" id=\"64de196b72e08276d78fd5f9\" width=\"\"><\/div>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/bcb\/b56\/1cb\/bcbb561cbcbc3a884eac41306cac51c3.png\" alt=\"\u041d\u0430 15\u043e\u043c \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0438 \u043e\u0441\u043e\u0431\u044c \u043f\u0440\u043e\u0434\u0435\u0440\u0436\u0430\u043b\u0430\u0441\u044c 300000 \u043a\u0430\u0434\u0440\u043e\u0432, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u044f \u0435\u0435 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b.\" title=\"\u041d\u0430 15\u043e\u043c \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0438 \u043e\u0441\u043e\u0431\u044c \u043f\u0440\u043e\u0434\u0435\u0440\u0436\u0430\u043b\u0430\u0441\u044c 300000 \u043a\u0430\u0434\u0440\u043e\u0432, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u044f \u0435\u0435 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b.\" width=\"1051\" height=\"789\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/bcb\/b56\/1cb\/bcbb561cbcbc3a884eac41306cac51c3.png\"\/><\/p>\n<div><figcaption>\u041d\u0430 15\u043e\u043c \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0438 \u043e\u0441\u043e\u0431\u044c \u043f\u0440\u043e\u0434\u0435\u0440\u0436\u0430\u043b\u0430\u0441\u044c 300000 \u043a\u0430\u0434\u0440\u043e\u0432, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u044f \u0435\u0435 <strong>\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b.<\/strong><\/figcaption><\/div>\n<\/figure>\n<p>\u041d\u0435\u0439\u0440\u043e\u043d\u043a\u0430 \u043b\u0435\u0433\u043a\u043e \u0441\u043f\u0440\u0430\u0432\u0438\u043b\u0430\u0441\u044c \u0438 \u0441 \u044d\u0442\u0438\u043c. \u042f \u0435\u0449\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u043b \u0440\u0430\u0437\u043d\u044b\u0435 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u044b, \u043d\u043e \u043e\u043d\u0430 \u043b\u0435\u0433\u043a\u043e \u0441 \u043d\u0438\u043c\u0438 \u0441\u043f\u0440\u0430\u0432\u0438\u043b\u0430\u0441\u044c.<\/p>\n<p>\u0413\u0438\u0442\u0445\u0430\u0431-\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439: <a href=\"https:\/\/github.com\/leo-need-more-coffee\/neuro-balance\" rel=\"noopener noreferrer nofollow\">\u0441\u0441\u044b\u043b\u043a\u0430<\/a><\/p>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>\u041d\u0435\u0439\u0440\u043e\u043d\u043a\u0438 \u044d\u0442\u043e \u043a\u0440\u0443\u0442\u043e! \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0439\u0442\u0435 \u0432 \u0437\u0430\u043a\u043b\u0430\u0434\u043a\u0438 \u0438 \u043f\u043e\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u0430\u043f\u0432\u043e\u0443\u0442, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u044d\u0442\u043e \u043e\u0447\u0435\u043d\u044c \u043c\u043e\u0442\u0438\u0432\u0438\u0440\u0443\u0435\u0442. \u0422\u0430\u043a\u0436\u0435, \u0435\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c \u043a\u0430\u043a\u0438\u0435-\u0442\u043e \u0438\u0434\u0435\u0438 \u0434\u043b\u044f \u043d\u0435\u0439\u0440\u043e\u0441\u0435\u0442\u0435\u0439, \u043f\u0438\u0448\u0438\u0442\u0435 \u0438\u0445 \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438.<\/p>\n<h3>\u041a\u043b\u0438\u0444\u0444\u0445\u044d\u043d\u0433\u0435\u0440<\/h3>\n<p>\u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c \u044d\u0442\u0438 \u0434\u0432\u0430 \u043f\u043e\u0434\u0445\u043e\u0434\u0430. \u0416\u0434\u0438\u0442\u0435!<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/755360\/\"> https:\/\/habr.com\/ru\/articles\/755360\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0415\u0441\u043b\u0438 \u0435\u0449\u0435 \u043d\u0435 \u0447\u0438\u0442\u0430\u043b\u0438, \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0439\u0442\u0435 <a href=\"https:\/\/habr.com\/ru\/articles\/755096\/\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0443\u044e \u0441\u0442\u0430\u0442\u044c\u044e.<\/a><\/p>\n<p>\u0412 \u043f\u0440\u043e\u0448\u043b\u044b\u0439 \u0440\u0430\u0437 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043a\u043b\u0430\u0441\u0441 \u043d\u0435\u0439\u0440\u043e\u043d\u043d\u043e\u0439 \u0441\u0435\u0442\u0438, \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u0436\u0435 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u043d\u0430 \u0435\u0435 \u043e\u0441\u043d\u043e\u0432\u0435 \u044d\u0432\u043e\u043b\u044e\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u0435\u043c \u0437\u0430\u0434\u0430\u0447\u0443: \u041d\u0435\u0439\u0440\u043e\u0441\u0435\u0442\u044c \u0434\u043e\u043b\u0436\u043d\u0430 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u0435\u043c \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0443\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043c\u044f\u0447. <\/p>\n<h2>\u0421\u0440\u0435\u0434\u0430 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f<\/h2>\n<p>\u041c\u043e\u044f \u0441\u0430\u043c\u0430\u044f (\u043d\u0435) \u043b\u044e\u0431\u0438\u043c\u0430\u044f \u0447\u0430\u0441\u0442\u044c &#8212; \u0444\u0438\u0437\u0438\u043a\u0430. \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043a\u043b\u0430\u0441\u0441 \u0434\u0432\u0443\u0445\u043c\u0435\u0440\u043d\u043e\u0433\u043e \u0432\u0435\u043a\u0442\u043e\u0440\u0430 \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u0440\u0430\u0441\u0447\u0435\u0442\u043e\u0432: \u043d\u043e\u0440\u043c\u0430\u043b\u0438 \u043a \u0434\u0430\u043d\u043d\u043e\u0439 \u043f\u0440\u044f\u043c\u043e\u0439 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u0435 \u0434\u0432\u0443\u0445 \u043f\u0440\u044f\u043c\u044b\u0445.<\/p>\n<details class=\"spoiler\">\n<summary>\u0414\u0432\u0443\u0445\u043c\u0435\u0440\u043d\u044b\u0439 \u0432\u0435\u043a\u0442\u043e\u0440 \u0438 \u0440\u0430\u0441\u0447\u0435\u0442\u044b<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">import random import time import tkinter as tk import math from copy import deepcopy as copy from neuro import NeuralNetwork import datetime import matplotlib.pyplot as plt  class Vector:     def __init__(self, x, y):         self.x = x         self.y = y      def __add__(self, other): #\u0441\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432\u0435\u043a\u0442\u043e\u0440\u043e\u0432         new = Vector(self.x + other.x, self.y + other.y)         return new      def __sub__(self, other): #\u0432\u044b\u0447\u0438\u0442\u0430\u043d\u0438\u0435 \u0432\u0435\u043a\u0442\u043e\u0440\u043e\u0432         new = Vector(self.x - other.x, self.y - other.y)         return new            def __mul__(self, other): #\u0443\u043c\u043d\u043e\u0436\u0435\u043d\u0438\u0435 \u0432\u0435\u043a\u0442\u043e\u0440\u0430 \u043d\u0430 \u0447\u0438\u0441\u043b\u043e         new = Vector(self.x * other, self.y * other)         return new      def length(self): #\u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u0434\u043b\u0438\u043d\u044b \u0432\u0435\u043a\u0442\u043e\u0440\u0430         return (self.x**2 + self.y**2) ** 0.5   def calculate_edge_normal(point1, point2):  # \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0440\u043c\u0430\u043b\u0438 \u043a \u0440\u0435\u0431\u0440\u0443     edge_vector = Vector(point2.x - point1.x, point2.y - point1.y)  # \u0412\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u0432\u0435\u043a\u0442\u043e\u0440\u0430 \u0440\u0435\u0431\u0440\u0430     edge_length = edge_vector.length()  # \u0412\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u0434\u043b\u0438\u043d\u044b \u0440\u0435\u0431\u0440\u0430      if edge_length == 0:         raise ValueError(\"The edge has zero length.\")  # \u0418\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435, \u0435\u0441\u043b\u0438 \u0434\u043b\u0438\u043d\u0430 \u0440\u0435\u0431\u0440\u0430 \u0440\u0430\u0432\u043d\u0430 \u043d\u0443\u043b\u044e      normalized_edge_vector = Vector(edge_vector.x \/ edge_length,                                     edge_vector.y \/ edge_length)  # \u041d\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0432\u0435\u043a\u0442\u043e\u0440\u0430 \u0440\u0435\u0431\u0440\u0430     normal_vector = Vector(-normalized_edge_vector.y, normalized_edge_vector.x)  # \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0432\u0435\u043a\u0442\u043e\u0440\u0430 \u043d\u043e\u0440\u043c\u0430\u043b\u0438     return normal_vector  # \u0412\u043e\u0437\u0432\u0440\u0430\u0442 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u043e\u0439 \u043d\u043e\u0440\u043c\u0430\u043b\u0438 \u043a \u0440\u0435\u0431\u0440\u0443   def lines_intersect(line1, line2):  # \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f \u0434\u0432\u0443\u0445 \u043e\u0442\u0440\u0435\u0437\u043a\u043e\u0432     x1, y1, x2, y2 = line1[0].x, line1[0].y, line1[1].x, line1[1].y  # \u0418\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 \u0442\u043e\u0447\u0435\u043a \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u043e\u0442\u0440\u0435\u0437\u043a\u0430     x3, y3, x4, y4 = line2[0].x, line2[0].y, line2[1].x, line2[1].y  # \u0418\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 \u0442\u043e\u0447\u0435\u043a \u0432\u0442\u043e\u0440\u043e\u0433\u043e \u043e\u0442\u0440\u0435\u0437\u043a\u0430          # \u0412\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u043d\u0430\u043a\u043b\u043e\u043d\u043e\u0432 (\u0443\u0433\u043b\u043e\u0432\u044b\u0445 \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442\u043e\u0432) \u043e\u0442\u0440\u0435\u0437\u043a\u043e\u0432, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044f \u0441\u043b\u0443\u0447\u0430\u0439 \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u043e\u0442\u0440\u0435\u0437\u043a\u043e\u0432     slope1 = (y2 - y1) \/ (x2 - x1) if x2 - x1 != 0 else float('inf')     slope2 = (y4 - y3) \/ (x4 - x3) if x4 - x3 != 0 else float('inf')          # \u0415\u0441\u043b\u0438 \u043d\u0430\u043a\u043b\u043e\u043d\u044b \u043e\u0442\u0440\u0435\u0437\u043a\u043e\u0432 \u0440\u0430\u0432\u043d\u044b, \u043e\u043d\u0438 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b \u0438 \u043d\u0435 \u043f\u0435\u0440\u0435\u0441\u0435\u043a\u0430\u044e\u0442\u0441\u044f     if slope1 == slope2:         return False          # \u0412\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 \u0442\u043e\u0447\u043a\u0438 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f     if slope1 == float('inf'):  # \u0415\u0441\u043b\u0438 \u043f\u0435\u0440\u0432\u044b\u0439 \u043e\u0442\u0440\u0435\u0437\u043e\u043a \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439         x = x1         y = slope2 * (x - x3) + y3     elif slope2 == float('inf'):  # \u0415\u0441\u043b\u0438 \u0432\u0442\u043e\u0440\u043e\u0439 \u043e\u0442\u0440\u0435\u0437\u043e\u043a \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439         x = x3         y = slope1 * (x - x1) + y1     else:  # \u0415\u0441\u043b\u0438 \u043e\u0431\u0430 \u043e\u0442\u0440\u0435\u0437\u043a\u0430 \u043d\u0435\u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0435         x = (slope1 * x1 - slope2 * x3 + y3 - y1) \/ (slope1 - slope2)         y = slope1 * (x - x1) + y1          # \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430, \u043b\u0435\u0436\u0438\u0442 \u043b\u0438 \u0442\u043e\u0447\u043a\u0430 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u0433\u0440\u0430\u043d\u0438\u0446 \u043e\u0431\u043e\u0438\u0445 \u043e\u0442\u0440\u0435\u0437\u043a\u043e\u0432     if ((x1 &lt;= x &lt;= x2 or x2 &lt;= x &lt;= x1) and         (x3 &lt;= x &lt;= x4 or x4 &lt;= x &lt;= x3)) and \\             ((y1 &lt;= y &lt;= y2 or y2 &lt;= y &lt;= y1) and              (y3 &lt;= y &lt;= y4 or y4 &lt;= y &lt;= y3)):         return True  # \u0422\u043e\u0447\u043a\u0430 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f \u043b\u0435\u0436\u0438\u0442 \u043d\u0430 \u043e\u0431\u043e\u0438\u0445 \u043e\u0442\u0440\u0435\u0437\u043a\u0430\u0445          return False  # \u0422\u043e\u0447\u043a\u0430 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f \u043d\u0435 \u043b\u0435\u0436\u0438\u0442 \u043d\u0430 \u043e\u0434\u043d\u043e\u043c \u0438\u0437 \u043e\u0442\u0440\u0435\u0437\u043a\u043e\u0432   G = Vector(0, .1)<\/code><\/pre>\n<p>G &#8212; \u0433\u0440\u0430\u0432\u0438\u0442\u0430\u0446\u0438\u043e\u043d\u043d\u0430\u044f \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u0430\u044f, \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u0430\u0434\u0440 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u0438\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0435\u0435 \u043a \u0432\u0435\u043a\u0442\u043e\u0440\u0443 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043e\u0432<\/p>\n<\/div>\n<\/details>\n<p>\u0418 \u043a\u043b\u0430\u0441\u0441\u044b \u0434\u043b\u044f \u043c\u044f\u0447\u0430 \u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b:<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043b\u0430\u0441\u0441\u044b \u043c\u044f\u0447\u0430 \u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">class Ball:     def __init__(self, x, y, radius):         # \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 \u043a\u043b\u0430\u0441\u0441\u0430 Ball \u0441 \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438         self.pos = Vector(x, y)  # \u041f\u043e\u0437\u0438\u0446\u0438\u044f \u0448\u0430\u0440\u0430 \u043a\u0430\u043a \u0432\u0435\u043a\u0442\u043e\u0440         self.radius = radius  # \u0420\u0430\u0434\u0438\u0443\u0441 \u0448\u0430\u0440\u0430         self.movement = Vector(0, 1)  # \u0412\u0435\u043a\u0442\u043e\u0440 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0448\u0430\u0440\u0430         self.collide = False  # \u0424\u043b\u0430\u0433 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f \u0441 \u0433\u0440\u0430\u043d\u0438\u0446\u0435\u0439         self.weight = 1  # \u041c\u0430\u0441\u0441\u0430 \u0448\u0430\u0440\u0430      def next_frame(self, edges):         collide = False  # \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0444\u043b\u0430\u0433\u0430 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f          normals = []  # \u0421\u043f\u0438\u0441\u043e\u043a \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043d\u043e\u0440\u043c\u0430\u043b\u0435\u0439 \u043a \u0433\u0440\u0430\u043d\u044f\u043c         intersect = []  # \u0421\u043f\u0438\u0441\u043e\u043a \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0444\u043b\u0430\u0433\u043e\u0432 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f         for i, edge in enumerate(edges):             normal = calculate_edge_normal(edge[0], edge[1])  # \u0412\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u043d\u043e\u0440\u043c\u0430\u043b\u0438 \u043a \u0433\u0440\u0430\u043d\u0438             normals.append(normal)             height = (self.pos, self.pos + (normal * self.radius))  # \u0412\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u0432\u044b\u0441\u043e\u0442\u044b \u043e\u0442 \u0446\u0435\u043d\u0442\u0440\u0430 \u0448\u0430\u0440\u0430 \u043a \u0433\u0440\u0430\u043d\u0438              intersect.append(lines_intersect(edge, height))  # \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f          # \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u0439 \u0441 \u0433\u0440\u0430\u043d\u044f\u043c\u0438         # \u0415\u0441\u043b\u0438 \u0434\u0432\u0435 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f, \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0435\u0435 \u043f\u043e \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u044e         # \u041f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0438 \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0448\u0430\u0440\u0430         # \u0415\u0441\u043b\u0438 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f \u043d\u0435\u0442, \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u0435 \u0448\u0430\u0440\u0430 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u0442\u0441\u044f \u0431\u0435\u0437 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439         # \u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0448\u0430\u0440\u0430 \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0432\u0435\u043a\u0442\u043e\u0440 \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f G (\u0433\u0440\u0430\u0432\u0438\u0442\u0430\u0446\u0438\u0438)         for i in range(4):             if intersect[i] and intersect[i + 1]:                 if (intersect[i] - self.pos).length() &lt;= (intersect[i + 1] - self.pos).length():                     self.movement = (normals[i] * self.movement.length()) * -1 * self.weight                     self.pos -= normals[i]                 else:                     self.movement = (normals[i + 1] * self.movement.length()) * -1 * self.weight                     self.pos -= normals[i + 1]              elif intersect[i]:                 self.movement = (normals[i] * self.movement.length()) * -1 * self.weight                 self.pos -= normals[i]              elif intersect[i + 1]:                 self.movement = (normals[i + 1] * self.movement.length()) * -1 * self.weight                 self.pos -= normals[i + 1]          self.collide = any(intersect)  # \u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0444\u043b\u0430\u0433\u0430 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f         self.movement += G * self.weight  # \u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0433\u0440\u0430\u0432\u0438\u0442\u0430\u0446\u0438\u0438 \u043a \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438         self.pos += self.movement  # \u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u043a \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0448\u0430\u0440\u0430   class Platform:     def __init__(self, x, y, height, width, rotate):         self.pos = Vector(x, y)         self.height = height         self.width = width         self.rotate = rotate<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043b\u0430\u0441\u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">class RotatingRectangleApp:     def __init__(self, root):         # \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f         self.root = root         self.root.title(\"Rotate Rectangle\")         self.canvas = tk.Canvas(root, width=1280, height=1280)         self.canvas.pack()          # \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u043e\u0432 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0438 \u0434\u0432\u0443\u0445 \u0448\u0430\u0440\u043e\u0432         self.rectangle = Platform(1280\/\/2, 1280\/\/2, 10, 800, 0)         self.ball = Ball(1280\/\/2-100, 1280\/\/2 - 500, 25)         self.ball1 = Ball(1280\/\/2+100, 1280\/\/2 - 300, 25)                  # \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043f\u0440\u044f\u043c\u043e\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430 \u043d\u0430 \u0445\u043e\u043b\u0441\u0442\u0435         self.drawing_rectangle = self.canvas.create_rectangle(self.rectangle.pos.x, self.rectangle.pos.y, self.rectangle.width, self.rectangle.height, outline='red', fill='red', width=2)                  # \u041f\u0440\u0438\u0432\u044f\u0437\u043a\u0430 \u043a\u043b\u0430\u0432\u0438\u0448 \u043a \u043c\u0435\u0442\u043e\u0434\u0430\u043c         self.root.bind(\"&lt;Right>\", self.rotate_right)         self.root.bind(\"&lt;Left>\", self.rotate_left)         self.root.bind(\"&lt;Up>\", self.set_pause)      def rotate_right(self, event):         # \u041c\u0435\u0442\u043e\u0434 \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043f\u0440\u044f\u043c\u043e\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430 \u0432\u043f\u0440\u0430\u0432\u043e         self.rectangle.rotate = self.rectangle.rotate + 1  # \u0412\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043d\u0430 1 \u0433\u0440\u0430\u0434\u0443\u0441      def set_pause(self, event):         # \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438\/\u0432\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u0448\u0430\u0440\u043e\u0432         global pause         pause = not pause      def rotate_left(self, event):         # \u041c\u0435\u0442\u043e\u0434 \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043f\u0440\u044f\u043c\u043e\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430 \u0432\u043b\u0435\u0432\u043e         self.rectangle.rotate = self.rectangle.rotate - 1  # \u0412\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043d\u0430 1 \u0433\u0440\u0430\u0434\u0443\u0441      def draw_rectangle(self):         # \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0435\u0433\u043e\u0441\u044f \u043f\u0440\u044f\u043c\u043e\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430                  # \u0412\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 \u0443\u0433\u043b\u043e\u0432 \u043f\u0440\u044f\u043c\u043e\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430 \u043f\u043e\u0441\u043b\u0435 \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f         center_x = self.rectangle.pos.x         center_y = self.rectangle.pos.y         angle_rad = math.radians(self.rectangle.rotate)                  corner_coords = [             self.rotate_point(self.rectangle.pos.x - self.rectangle.width\/2, self.rectangle.pos.y - self.rectangle.height\/2, center_x, center_y, angle_rad),             self.rotate_point(self.rectangle.pos.x + self.rectangle.width\/2, self.rectangle.pos.y - self.rectangle.height\/2, center_x, center_y, angle_rad),             self.rotate_point(self.rectangle.pos.x + self.rectangle.width\/2, self.rectangle.pos.y + self.rectangle.height\/2, center_x, center_y, angle_rad),             self.rotate_point(self.rectangle.pos.x - self.rectangle.width\/2, self.rectangle.pos.y + self.rectangle.height\/2, center_x, center_y, angle_rad)         ]          edges = [(Vector(corner_coords[i%4][0], corner_coords[i%4][1]), Vector(corner_coords[(i+1)%4][0], corner_coords[(i+1)%4][1])) for i in range(4)]          # \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043f\u0440\u044f\u043c\u043e\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430 \u043d\u0430 \u0445\u043e\u043b\u0441\u0442\u0435         self.drawing_rectangle = self.canvas.create_polygon(corner_coords, outline='red', fill='red', width=2)         return edges      def draw_ball(self):         # \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0448\u0430\u0440\u043e\u0432         coords = [             (self.ball.pos.x - self.ball.radius, self.ball.pos.y - self.ball.radius),             (self.ball.pos.x + self.ball.radius, self.ball.pos.y + self.ball.radius),         ]          self.canvas.create_oval(coords, outline='black', fill='', width=2)          coords = [             (self.ball1.pos.x - self.ball1.radius, self.ball1.pos.y - self.ball1.radius),             (self.ball1.pos.x + self.ball1.radius, self.ball1.pos.y + self.ball1.radius),         ]          self.canvas.create_oval(coords, outline='black', fill='', width=2)      def rotate_point(self, x, y, cx, cy, angle_rad):         # \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0442\u043e\u0447\u043a\u0438 \u0432\u043e\u043a\u0440\u0443\u0433 \u0446\u0435\u043d\u0442\u0440\u0430         new_x = cx + (x - cx) * math.cos(angle_rad) - (y - cy) * math.sin(angle_rad)         new_y = cy + (x - cx) * math.sin(angle_rad) + (y - cy) * math.cos(angle_rad)         return new_x, new_y      def clear_canvas(self):         # \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043e\u0447\u0438\u0441\u0442\u043a\u0438 \u0445\u043e\u043b\u0441\u0442\u0430         self.canvas.delete(\"all\") <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<h2>\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f<\/h2>\n<p>\u0423 \u043d\u0435\u0439\u0440\u043e\u0441\u0435\u0442\u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430:<\/p>\n<p>7 \u0432\u0445\u043e\u0434\u043d\u044b\u0445 \u043d\u0435\u0439\u0440\u043e\u043d\u043e\u0432, \u043f\u043e 20 \u043d\u0435\u0439\u0440\u043e\u043d\u043e\u0432 \u0432 \u0434\u0432\u0443\u0445 \u0441\u043a\u0440\u044b\u0442\u044b\u0445 <\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-352502","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/352502","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=352502"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/352502\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=352502"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=352502"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=352502"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}