Автор работы: Пользователь скрыл имя, 26 Февраля 2013 в 06:52, курсовая работа
Данная курсовая работа посвящена разработке алгоритма интеллектуального управления танком для участия в конкурсе «Российский кубок по программированию искусственного интеллекта CodeTanks 2012 (Russian AI Cup)». В работе рассмотрены принципы наиболее эффективного поведения танка, позволяющие ему эффективно передвигаться по полю, минимизировать повреждения от танков оппонентов и набирать как можно большее количество очков за счет уничтожения танков оппонентов. Алгоритм реализован на языке программирования Python 2.7.3 в среде разработки JetBrains PyCharm 2.6.3.
Введение 3
1 О мире CodeTanks 2012 4
1.1Общие положения и правила 4
1.2 Описание игрового мира 5
1.3 Описание танков 7
1.4 Описание снарядов и механики попаданий 9
1.5 Описание бонусов 10
1.6 Начисление баллов 11
2 Стратегия управления танком 12
2.1 Выбор танка 12
2.2 Принципы поведения танка 14
2.2.1 Движение танка 15
2.2.1.1 Уворот 19
2.2.1.2 Рикошет 20
2.2.2 Стрельба 22
Заключение 24
Список использованной литературы 25
Приложение А 26
if alpha < 0:
if abs(alpha) > pi/9:
move.left_track_power = -1
move.right_track_power = me.engine_rear_power_factor
if abs(alpha) < pi/18:
move.left_track_power = me.engine_rear_power_factor
move.right_track_power = -1
else:
if abs(alpha) > pi/9:
move.left_track_power = me.engine_rear_power_factor
move.right_track_power = -1
if abs(alpha) < pi/18:
move.left_track_power = -1
move.right_track_power = me.engine_rear_power_factor
# if frontSideAttacked:
# print 'front'
#can we dodge moving directly forward/backward
def canBeDodged(self, power, me, shell, time):
# ax = a * cos(me.angle)
# ay = a * sin(me.angle)
calculation = Calculation()
newMe = Unit(6666, me.width, me.height, me.x, me.y, me.speedX, me.speedY, me.angle, me.angular_speed)
newMe.x, newMe.y = calculation.get_new_pos(me, time, power)
# newMe.x = newMe.x + newMe.speedX*time + ax*time*time/2
# newMe.y = newMe.y + newMe.speedY*time + ay*time*time/2
MinD, pt = self.hits(shell, newMe)
if MinD == 6666 and pt.x == -1 and pt.y == -1:
return True
else:
return False
#can we dodge at all. Returns capability to dodge; left track power; right track power
def tryDodge(self, me, shell, time, move):
forward_works = False
backward_works = False
if self.canBeDodged(1, me, shell, time):
forward_works = True
if self.canBeDodged(-me.engine_
backward_works = True
if not forward_works and not backward_works:
return False, move.left_track_power, move.right_track_power
if forward_works and not backward_works:
return True, 1, 1
if not forward_works and backward_works:
return True, -1, -1
if forward_works and backward_works:
if me.speedX == 0:
angleV = pi/2
else:
angleV = atan(me.speedY / me.speedX)
if abs(angleV - me.angle) <= pi / (1 + me.engine_rear_power_factor):
return True, 1, 1
else:
return True, -1, -1
def moveToDodge(self, me, shell, move):
Dist, pt = self.hits(shell, me)
distance = shell.get_distance_to(pt.x, pt.y)
if shell.type == FireType.PREMIUM:
time = bisect(Factor.SHELL_PREMIUM_
else:
time = bisect(Factor.SHELL_REGULAR_
Модуль Head.py
# -*- coding: utf-8 -*-
from bisect import bisect
__author__ = 'yokre_000'
import copy
from Calculation import Calculation
from model.FireType import FireType
from Factor import Factor
class Head():
def __init__(self):
self.locks = {}
def move(self, me, world, move):
targets = self.get_targets(world)
obstacles = self.get_obstacles(world, me)
if me.remaining_reloading_time == 0:
if self.can_fire_any_aimed(me, targets, obstacles):
move.fire_type = FireType.PREMIUM_PREFERRED
selected_target = self.select_target(me, targets, obstacles)
if selected_target:
move.turret_turn = Calculation.turret_angle_to_
def can_fire_any_aimed(self, me, targets, obstacles):
bad_obstacles = [] # содержит дистанции до плохих целей
for obstacle in obstacles:
if Calculation.can_hit_unmoving_
bad_obstacles.append(me.get_
for target in targets:
if Calculation.aimed_to_moving_
distance = me.get_distance_to_unit(
can_hit = True
for d in bad_obstacles:
if d < distance:
can_hit = False
break
return can_hit
return False
def get_targets(self, world):
"""
Возвращает список возможных целей
"""
good_targets = []
for tank in world.tanks:
if not tank.teammate and tank.hull_durability > 0 and tank.crew_health > 0:
good_targets.append(tank)
return good_targets
def get_obstacles(self, world, me):
"""
Возвращает список препятствий
"""
obstacles = []
if len(world.tanks) > 0:
for tank in world.tanks:
if tank.hull_durability <= 0 or tank.crew_health <= 0 or (tank.teammate and tank.id != me.id):
obstacles.append(tank)
[obstacles.append(b) for b in world.bonuses]
[obstacles.append(o) for o in world.obstacles]
return obstacles
def select_target(self, me, targets, obstacles):
rotate_time_for_targets = []
new_targets = copy.deepcopy(targets)
for key in self.locks:
if self.locks[key] > 0:
self.locks[key] -= 1
bad_target = None
for target in targets:
if target.id == key:
bad_target = target
break
if bad_target:
targets.remove(bad_target)
if not targets:
targets = new_targets
# просчет времени поворота
for target in targets:
time = self.get_time_to_rotate(me, target)
if time < me.remaining_reloading_time:
time = -1
rotate_time_for_targets.
# удалим цели, в которые не cможем попасть
# for target in rotate_time_for_targets:
#
if not Calculation.can_hit_tank_in_
#
rotate_time_for_targets.
if not rotate_time_for_targets:
return targets[0]
# сортировка по времени
rotate_time_for_targets.sort(
min_distance = 2000 # не может быть выше
selected_target = None
for target in rotate_time_for_targets:
# выбрать только те цели, до которых успеем повернуться
if target[1] != -1: break
# из них выбрать приоритетные
distance = me.get_distance_to_unit(
if distance < min_distance:
min_distance = distance
selected_target = target[0]
# если таких целей нет, то выбираем ту, до которой меньше крутиться
if not selected_target:
selected_target = rotate_time_for_targets[0][0]
return selected_target
def get_time_to_rotate(self, me, target):
"""
Возвращает
время, необходимое для
Не
учитывает угловую скорость
Не учитывает новое положение цели
"""
angle =
me.get_turret_angle_to_unit(
time = abs(angle) / me.turret_turn_speed
return int(time)
Модуль RemoteProcessClient.py
import socket
import struct
from model.Bonus import Bonus
from model.BonusType import BonusType
from model.Obstacle import Obstacle
from model.Player import Player
from model.PlayerContext import PlayerContext
from model.Shell import Shell
from model.ShellType import ShellType
from model.Tank import Tank
from model.TankType import TankType
from model.World import World
class RemoteProcessClient:
LITTLE_ENDIAN_BYTE_ORDER = True
SIGNED_BYTE_FORMAT_STRING = '<b' if LITTLE_ENDIAN_BYTE_ORDER else '>b'
INTEGER_FORMAT_STRING = '<i' if LITTLE_ENDIAN_BYTE_ORDER else '>i'
LONG_FORMAT_STRING = '<q' if LITTLE_ENDIAN_BYTE_ORDER else '>q'
DOUBLE_FORMAT_STRING = '<d' if LITTLE_ENDIAN_BYTE_ORDER else '>d'
SIGNED_BYTE_SIZE_BYTES = 1
INTEGER_SIZE_BYTES = 4
LONG_SIZE_BYTES = 8
DOUBLE_SIZE_BYTES = 8
def __init__(self, host, port):
self.socket = socket.socket()
self.socket.connect((host, port))
def write_token(self, token):
self.write_enum(
self.write_string(token)
def read_team_size(self):
message_type
= self.read_enum(
self.ensure_message_type(
return self.read_int()
def write_selected_tanks(self, tank_types):
self.write_enum(
if tank_types is None:
self.write_int(-1)
else:
self.write_int(tank_types.__
for type in tank_types:
self.write_enum(type)
def read_player_context(self):
message_type
= self.read_enum(
if message_type
== RemoteProcessClient.
return None
self.ensure_message_type(
return
PlayerContext(self.read_tanks(
def write_moves(self, moves):
self.write_enum(
if moves is None:
self.write_int(-1)
else:
self.write_int(moves.__len__()
for move in moves:
if move is None:
self.write_boolean(False)
else:
self.write_boolean(True)
self.write_double(move.left_
self.write_double(move.right_
self.write_double(move.turret_
self.write_enum(move.fire_
def close(self):
self.socket.close()
def read_world(self):
if not self.read_boolean():
return None
return World(
self.read_int(), self.read_double(), self.read_double(), self.read_players(),
self.read_obstacles(), self.read_tanks(), self.read_shells(), self.read_bonuses()
)
def read_players(self):
player_count = self.read_int()
if player_count < 0:
return None
players = []
for player_index in xrange(player_count):
if self.read_boolean():
player = Player(self.read_string(), self.read_int(), self.read_boolean())
players.append(player)
else:
players.append(None)
return players
def read_obstacles(self):
obstacle_count = self.read_int()
if obstacle_count < 0:
return None
obstacles = []
for obstacle_index in xrange(obstacle_count):
if self.read_boolean():
obstacle = Obstacle(
self.read_long(), self.read_double(), self.read_double(),
self.read_double(), self.read_double()
)
obstacles.append(obstacle)
else:
obstacles.append(None)
return obstacles
def read_tanks(self):
tank_count = self.read_int()
if tank_count < 0:
return None
tanks = []
for tank_index in xrange(tank_count):
if self.read_boolean():
tank = Tank(
self.read_long(), self.read_string(), self.read_int(),
self.read_double(), self.read_double(), self.read_double(), self.read_double(),
self.read_double(), self.read_double(), self.read_double(),
self.read_int(), self.read_int(), self.read_int(), self.read_int(),
self.read_int(), self.read_boolean(), self.read_enum(TankType)
)
tanks.append(tank)
else:
tanks.append(None)
return tanks
def read_shells(self):
shell_count = self.read_int()
if shell_count < 0:
return None
shells = []
for shell_index in xrange(shell_count):
if self.read_boolean():
shell = Shell(
self.read_long(), self.read_string(), self.read_double(), self.read_double(),
self.read_double(), self.read_double(), self.read_double(), self.read_double(),
self.read_double(), self.read_double(), self.read_enum(ShellType)
)
shells.append(shell)
else:
shells.append(None)
return shells
def read_bonuses(self):
bonus_count = self.read_int()
if bonus_count < 0:
return None
bonuses = []
for bonus_index in xrange(bonus_count):
if self.read_boolean():
bonus = Bonus(
self.read_long(), self.read_double(), self.read_double(),
self.read_double(), self.read_double(), self.read_enum(BonusType)
)
bonuses.append(bonus)
else:
bonuses.append(None)
return bonuses
def ensure_message_type(self, actual_type, expected_type):
if actual_type != expected_type:
raise ValueError("Received wrong message [actual=%s, expected=%s]" % (actual_type, expected_type))
def read_enum(self, enum_class):
bytes =
self.read_bytes(
value =
struct.unpack(
for enum_key,
enum_value in enum_class.__dict__.iteritems(
if not str(enum_key).startswith("__") and value == enum_value:
return enum_value
return None
def write_enum(self, value):
self.write_bytes(struct.pack(
def read_string(self):
length = self.read_int()
if length == -1:
return None
bytes = self.read_bytes(length)
return bytes.decode("utf-8")
def write_string(self, value):
if value is None:
self.write_int(-1)
return
bytes = value.encode("utf-8")
self.write_int(len(bytes))
self.write_bytes(bytes)
def read_boolean(self):
bytes =
self.read_bytes(
return
struct.unpack(
def write_boolean(self, value):
self.write_bytes(struct.pack(
def read_int(self):
bytes =
self.read_bytes(
return
struct.unpack(
def write_int(self, value):
self.write_bytes(struct.pack(
def read_long(self):
bytes =
self.read_bytes(
return
struct.unpack(
def write_long(self, value):
self.write_bytes(struct.pack(
def read_double(self):
bytes =
self.read_bytes(
return
struct.unpack(
def write_double(self, value):
self.write_bytes(struct.pack(
def read_bytes(self, byte_count):
bytes = ''
while len(bytes) < byte_count:
chunk = self.socket.recv(byte_count - len(bytes))
if not len(chunk):
raise IOError("Can't read %s bytes from input stream." % str(byte_count))
bytes += chunk
return bytes
def write_bytes(self, bytes):
self.socket.sendall(bytes)
class MessageType:
UNKNOWN = 0
GAME_OVER = 1
AUTHENTICATION_TOKEN = 2
TEAM_SIZE = 3
TANK_TYPES = 4