Advertisement
KirillMysnik

SP quickstart (russian)

Sep 5th, 2016
164
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 16.48 KB | None | 0 0
  1. # =============================================================================
  2. # Задание 1. Создание массива. Добавление элементов. Удаление элементов.
  3. #            Срезы массива. Цикл по массиву.
  4. # =============================================================================
  5.  
  6. # В Python массивов нет, они называются списками. Но в общем, то же самое.
  7. # Создаём.
  8. my_list = [42, 5, "Hello, World"]
  9.  
  10. # Добавляем в него ещё один элемент (в конец)
  11. my_list.append("Привет")   # [42, 5, "Hello, World", "Привет"]
  12.  
  13. # Добавляем его самого в себя
  14. my_list.append(my_list)    # [42, 5, "Hello, World", "Привет", [...]]
  15.  
  16. # Получаем срез из элементов от первого до третьего (не включая третий!!!)
  17. my_list2 = my_list[1:3]    # [5, "Hello, World"]
  18.  
  19. # Удаляем первый попавшийся элемент "Hello, World"
  20. my_list.remove("Hello, World")
  21.  
  22. # Следующая строка вызовет исключение, потому что элемента 777
  23. # нет в нашем массиве
  24. my_list.remove(777)
  25.  
  26. # Цикл по массиву.
  27. # Цикл for в Пайтоне отличается от циклов for в других языках, и является тем,
  28. # что в других языках называется циклом foreach. Классического for в Пайтоне
  29. # нет.
  30. my_list = [2, 5, 10, -5, 100]
  31. for x in my_list:
  32.     print(x**2)  # **2 - возведение в квадрат
  33. # Результат:
  34. # 4
  35. # 25
  36. # 100
  37. # 25
  38. # 10000
  39.  
  40.  
  41. # =============================================================================
  42. # Задание 2. Задание функций. Вызов функций. Декораторы.
  43. # =============================================================================
  44.  
  45. # Задаём функцию от двух переменных
  46. def my_function(x, y):
  47.     print(x + y)
  48.  
  49. # Вызываем её
  50. my_function(5, 10)  # Выведет на экран 15
  51.  
  52. # Задаём функцию, возвращающую значение, с параметром по умолчанию
  53. def my_function(x, y=42):
  54.     return x - y
  55.  
  56. # Вызываем её
  57. print(my_function(15, 10))  # Выведет на экран 5
  58. print(my_function(43))  # Выведет на экран 1
  59.  
  60. # В Питоне всё есть объект класса. Даже любой класс является объектом класса.
  61. # Типы данные отсутствуют, начиная с Python 3 они называются классами данных.
  62. # Функция - тоже объект. Её можно поместить в массив, её можно передать
  63. # в качестве аргумента, её можно вернуть из другой функции.
  64.  
  65. # Создадим функцию от двух функций f и g, которая будет возвращать функцию,
  66. # возвращающую произведение возвращаемых значений функций f и g.
  67. # На примере будет понятнее.
  68. def create_function(f, g):
  69.     def new_function(x):
  70.         return f(x) * g(x)
  71.    
  72.     return new_function
  73.  
  74. # Зададим функции f и g
  75. def f(x):
  76.     return x**2
  77.  
  78. def g(x):
  79.     return x / 2
  80.  
  81. # Вызываем всё это
  82. print(create_function(f, g)(5))  # create_function(f, g) вернёт функцию. Мы эту
  83.                                  # функцию сразу вызываем с аргументом 5.
  84.  
  85. # Выведет на экран 62.5, т.е. (5**2)*(5/2) = 25*2.5 = 62.5
  86.  
  87. # Переходим к декораторам. Зададим следующую функцию
  88. def create_func(old_func):
  89.     def new_func(x):
  90.         return old_func(x) + 5
  91.  
  92.     return new_func
  93.  
  94. # Чем-то похоже на предыдущий пример? Теперь функция my_func (строчка I)
  95. def my_func(x):
  96.     return x**3
  97.  
  98. # Теперь рассмотрим такую запись (II):
  99. my_func = create_func(my_func)
  100. # Т.е. мы заменили функцию, хранящуюся в переменной my_func, на новую функцию,
  101. # которую вернула функция create_func
  102.  
  103. # Вызовем my_func
  104. my_func(10)  # Вернёт 1005, т.е. 10**3 + 5
  105.  
  106. # Теперь представим, что мы не выполняли строчки (I) и (II), а вместо этого
  107. # использовали функцию create_func в качестве декоратора при объявлении
  108. # функции my_func:
  109. @create_func
  110. def my_func(x):
  111.     return x**3
  112. # Получится то же самое. Функция my_func сразу после объявления будет передана
  113. # в декоратор create_func, а то, что вернёт декоратор, запишется в переменную
  114. # my_func вместо оригинальной функции.
  115.  
  116. # Ещё примерчик с декоратором
  117. my_list = []
  118.  
  119. def my_decorator(f):
  120.     my_list.append(f)
  121.     return f
  122.  
  123. @my_decorator
  124. def my_func(x, y):
  125.     return x * y
  126.  
  127. # В результате выполнения вышестоящих строк в массиве my_list окажется функция.
  128. # my_list[0] и переменная my_func есть, по сути, две ссылки на один и тот же
  129. # объект, которым является функция.
  130. my_list[0](2, 3)    # Вернёт 6.
  131.  
  132.  
  133. # =============================================================================
  134. # Задание 3. Выдать сообщение игроку после его смерти
  135. # =============================================================================
  136. from events import Event
  137. from messages import SayText2
  138. from players.entity import Player
  139.  
  140.  
  141. # Создаём объект класса SayText2. Сообщение одинаковое будет во всех случаях,
  142. # поэтому я создаю его заранее, чтобы по 100500 раз не создавать его внутри
  143. # события.
  144. MESSAGE = SayText2("You are dead.")
  145.  
  146.  
  147. # Знакомтесь. Декоратор Event(<название события>). Замечу, что декоратор тут не
  148. # Event, а то, что вернёт Event(<название события>).
  149. # Декоратор Event(<название события>) цепляет входную функцию к менеджеру
  150. # событий и возвращает... ту же самую функцию. Вся его роль только в
  151. # регистрации функции. Данный декоратор позаботится о том, чтобы функция
  152. # была "отцеплена" от менеджера событий при выгрузке плагина из памяти.
  153. # Декораторы используются в SP повсеместно.
  154. @Event('player_death')
  155. def on_player_death(game_event):  # имя функции может быть любым, я предпочитаю
  156.                                   # формат on_<название события>
  157.    
  158.     # В словаре game_event (название произвольное) хранятся переменные события
  159.     # Обращение как к любому словарю: словарь['ключ']
  160.     # Player - универсальный класс для игрока, наследуется от класса Entity
  161.     # В общем случае он, как и класс Entity, строится так:
  162.     # >> player = Player(index)
  163.     # где index - индекс энтити игрока.
  164.     # Но у самого класса Player есть волшебный метод from_userid, который
  165.     # принимает userid и возвращает уже построенный объект класса Player.
  166.     player = Player.from_userid(game_event['userid'])
  167.     # К слову, всё, что делает метод from_userid:
  168.     # >> def from_userid(userid):
  169.     # >>     return Player(index_from_userid(userid))
  170.     # Функция-помощник под названием index_from_userid импортируется из модуля
  171.     # players.helpers:
  172.     # >> from players.helpers import index_from_userid
  173.     # Но зачем лишний раз импортировать, если можно воспользоваться методом
  174.     # Player.from_userid?
  175.    
  176.     # Теперь отправляем сообщение. Отправляется оно по индексу игрока.
  177.     # Индекс любого объекта класса Entity получается так:
  178.     # >> object.index
  179.     # В нашем случае объект класса Entity (если конкретнее, класса Player)
  180.     # вернёт свой индекс так:
  181.     # >> player.index
  182.     MESSAGE.send(player.index)
  183.  
  184.  
  185. # =============================================================================
  186. # Задание 4. Форматирование строк
  187. # =============================================================================
  188. "{0} says {1}".format("iPlayer", "Hello")   # подстановка аргументов по их
  189.                                             # номеру
  190. # Результат: "iPlayer says Hello"
  191.  
  192.  
  193. "{} says {}".format("iPlayer", "Hello")     # номера можно опустить, если
  194.                                             # аргументы подставляются по
  195.                                             # порядку
  196. # Результат: "iPlayer says Hello"
  197.  
  198.  
  199. "{player} says {word}".format(player="iPlayer", word="Hello")
  200. # Результат: "iPlayer says Hello"
  201.  
  202.  
  203. keywords = ["iPlayer", "Hello"]
  204. "{} says {}".format(*keywords)  # разворачивание списка в аргументы функции
  205. # Результат: "iPlayer says Hello"
  206.  
  207.  
  208. keywords = {'player': "iPlayer", 'word': "Hello"}
  209. "{player} says {word}".format(**keywords)  # разворачивание словаря в
  210.                                            # именованные аргументы функции
  211.  
  212.  
  213. # =============================================================================
  214. # Задание 5. Печатать топ-3 игроков, набравших больше всего убийств,
  215. #            в конце раунда
  216. # =============================================================================
  217. from events import Event
  218. from filters.players import PlayerIter
  219. from listeners import OnClientActive, OnClientDisconnect
  220. from messages import SayText2
  221. from players.entity import Player
  222. from players.helpers import index_from_userid
  223.  
  224.  
  225. # Заводим ассоциативный массив (он же словарь) players. Ключами будут выступать
  226. # индексы игроков, а значениями - количество убийств в раунде
  227. players = {}
  228.  
  229.  
  230. # Функция load в главном файле плагина в текущей версии Source.Python
  231. # вызывается при загрузке плагина.
  232. # Нам эта функция понадобится, чтобы занести в наш словарь игроков, которые уже
  233. # играют на сервере в момент загрузки плагина (ситуация "горячий старт")
  234. def load():
  235.     # Итерируем (проходим) по всем игрокам на сервере.
  236.     # Генератор PlayerIter() будет возвращать новый объект класса Player на
  237.     # каждой итерации.
  238.     for player in PlayerIter():
  239.         players[player.index] = 0
  240.  
  241.  
  242. @OnClientActive
  243. def listener_on_client_active(index):
  244.     players[index] = 0
  245.  
  246.  
  247. @OnClientDisconnect
  248. def listener_on_client_disconnect(index):
  249.     # Когда игрок отключается во время подключения, может возникнуть ситуация,
  250.     # при которой OnClientDisconnect сработает без срабатывания OnClientActive.
  251.     # Поэтому может оказаться, что индекс отключаемого игрока отсутствует в
  252.     # нашем словаре. Чтобы избежать исключений, с помощью оператор in я
  253.     # делаю проверку, есть ли индекс среди ключей нашего словаря.
  254.     if index in players:
  255.         # Теперь, когда мы убедились, что индекс присутствует, надо его удалить
  256.         del players[index]
  257.  
  258.  
  259. @Event('round_start')
  260. def on_round_start(game_event):
  261.     # В начале нового раунда следует сбросить счётчики убийств.
  262.     # players.keys() - генератор ключей нашего словаря.
  263.     for index in players.keys():
  264.         players[index] = 0
  265.  
  266.  
  267. @Event('player_death')
  268. def on_player_death(game_event):
  269.     # Если userid нападавшего равен нулю, то нападавший - не игрок. Выходим из
  270.     # обработчика события.
  271.     if game_event['attacker'] == 0:
  272.         return
  273.  
  274.     # Заодно не будем считать самоубийства
  275.     if game_event['attacker'] == game_event['userid']:
  276.         return
  277.  
  278.     # Превращаем userid нападавшего в индекс
  279.     index = index_from_userid(game_event['attacker'])
  280.  
  281.     # Добавляем единичку к счётчику убийств нападавшего
  282.     players[index] += 1
  283.  
  284.  
  285. @Event('round_end')
  286. def on_round_end(game_event):
  287.     # Сортируем индексы по количеству убийств хозяина с помощью встроенной
  288.     # в Пайтон функции sorted
  289.     sorted_player_indexes = sorted(
  290.         # Сортировать будем индексы, т.е. ключи нашего словаря
  291.         players.keys(),
  292.  
  293.         # В качестве задающей сортировку функции будем использовать
  294.         # лямбда-функцию (анонимную однострочную функцию), которая будет
  295.         # принимать на вход ключ словаря и возвращать соответствующее значение
  296.         # (т.е. сортировка пойдёт по значениям словаря - убийствам)
  297.         key=lambda index: players[index],
  298.  
  299.         # Необязательный параметр reverse позволяет произвести сортировку в
  300.         # обратном порядке. По умолчанию (без него) сортировка идёт по
  301.         # возрастанию, а нам нужно по убыванию.
  302.         reverse=True,
  303.     )
  304.  
  305.     # В результате в списке sorted_player_indexes хранятся индексы,
  306.     # отсортированные по количеству соответствующих убийств в порядке убывания
  307.  
  308.     # Берём первые три индекса (пропустив первую координату среза, я тем самым
  309.     # заставляю срез начинаться с самого начала списка - можно было
  310.     # использовать [0:3])
  311.     sorted_player_indexes = sorted_player_indexes[:3]
  312.  
  313.     # Сюда будем складывать имена игроков
  314.     player_names = []
  315.  
  316.     for index in sorted_player_indexes:
  317.         player_names.append(Player(index).name)
  318.  
  319.     # Составляем текст сообщения
  320.     text = "TOP-3 players: 1) {}, 2) {}, 3) {}".format(*player_names)
  321.  
  322.     # Создаём и отправляем SayText2 (вызов метода send без параметров приводит
  323.     # к отправке сообщения всем игрокам на сервере)
  324.     SayText2(text).send()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement