From e1a3c84de64beb5a2d0ca862bd3206a0e703ec9c Mon Sep 17 00:00:00 2001 From: Stycenko Ilia Date: Fri, 22 Sep 2017 22:00:50 +0300 Subject: [PATCH 1/5] docs --- README.md | 6 ++++ api.pdf | Bin 54784 -> 0 bytes clients/cpp11_client/README.md | 60 +++++++++++++++++++++++++++++++ clients/java1.8_client/README.md | 56 +++++++++++++++++++++++++++++ clients/nodejs_client/README.md | 57 +++++++++++++++++++++++++++++ clients/php7_client/README.md | 60 +++++++++++++++++++++++++++++++ clients/python2_client/README.md | 57 +++++++++++++++++++++++++++++ clients/python3_client/README.md | 57 +++++++++++++++++++++++++++++ 8 files changed, 353 insertions(+) delete mode 100644 api.pdf create mode 100644 clients/cpp11_client/README.md create mode 100644 clients/java1.8_client/README.md create mode 100644 clients/nodejs_client/README.md create mode 100644 clients/php7_client/README.md create mode 100644 clients/python2_client/README.md create mode 100644 clients/python3_client/README.md diff --git a/README.md b/README.md index 57d836c..a155383 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,12 @@ ## CodeLift, первый тестовый чемпионат +В здании есть восемь лифтов (по четыре с каждой стороны), 9 этажей, две точки появления пассажиров на каждом этаже и две лестницы. Здание симметрично относительно центра. Слева находятся лифты, которыми управляет первый игрок, справа -- лифты второго игрока. Точки появления пассажиров также принадлежат либо первому игроку (слева), либо второму (справа). Управлять можно только своими лифтами, лифт поддерживает две команды: забрать определенного пассажира ("своего" или "чужого") или уехать на определенный этаж (с пассажирами или без). Напрямую пассажирами управлять нельзя. Задача -- заработать как можно больше очков за перевоз пассажиров. + ### [Описание мира](/world.md) ### [LocalRunner](/localrunner/README.md) + +### [Клиенты](/clients/) + +### [Базовые стратегии](/baseline/) diff --git a/api.pdf b/api.pdf deleted file mode 100644 index 88e81b675555505f8e0adc4f8779d4c74df05b45..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54784 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 myElevators; +std::vector& myPassengers; +std::vector& enemyElevators; +std::vector& enemyPassengers; +// Для отладки в консоль используйте вызов this->log(T smth) +// Допустимы типы: bool, int, short, long, float, double, char, QString, +Passenger, Elevator +// Каждый тик вызывается strategy->onTick(List, List, +List, List) +// API для работы с пассажирами +class Passenger { +public: + // Текущий этаж + int floor; + // Этаж, с которого едет пассажир + int from_floor; + // Этаж, на который едет пассажир + int dest_floor; + // Координаты пассажира + int x, y; + // Сколько времени осталось до ухода на лестницу + int time_to_away; + // Состояние пассажира + int state; + // Узнать к какому игроку привязан пассажир + // Возвращаемое значение "FIRST_PLAYER", "SECOND_PLAYER" + QString type; +public: + // проверить, есть ли у пассажира лифт + bool has_elevator() {} + // назначить пассажиру лифт + void set_elevator(const Elevator& elevator) {} +}; +// API для работы с лифтами +class Elevator { +public: + // Текущий этаж + int floor; + // Этаж, к которому лифт едет в данный момент + int next_floor; + // Сколько времени лифт простоял на этаже + int time_on_floor; + // Координата лифта по Y + double y; + // Скорость движения в текущий момент + double speed; + // Какому игроку принадлежит + // Возвращаемое значение "FIRST_PLAYER", "SECOND_PLAYER" + QString type; + // Состояние лифта + int state; + // Массив пассажиров, которых перевозит данный лифт + std::vector passengers; +public: + // Отправить лифт на указанный этаж, он доедет и выпустит пассажиров + void go_to_floor(int floor) {} +}; +``` diff --git a/clients/java1.8_client/README.md b/clients/java1.8_client/README.md new file mode 100644 index 0000000..6f355cb --- /dev/null +++ b/clients/java1.8_client/README.md @@ -0,0 +1,56 @@ +```java +// В стратегию приходит четыре массива +ArrayList myElevators; +ArrayList myPassengers; +ArrayList enemyElevators; +ArrayList enemyPassengers; +// Для отладки в консоль используйте вызов +this.log(Object object) +// Каждый тик вызывается Strategy.onTick(List, List, +List, List) +// API для работы с пассажирами +class Passenger { + // Назначить пассажиру лифт + public void setElevator(Elevator elevator) {} + // Проверяет, назначен ли лифт пассажиру + public Boolean hasElevator() {} + // Текущий этаж + public Integer getFloor() {} + // Этаж, с которого едет пассажир + public Integer getFromFloor() {} + // Этаж, на который едет пассажир + public Integer getDestFloor() {} + // Состояние пассажира + public Integer getState() {} + // Сколько времени осталось до ухода на лестницу + public Integer getTimeToAway() {} + // Координаты пассажира + public Double getY() {} + public Double getX() {} + // Узнать к какому игроку привязан пассажир + // Возвращаемое значение "FIRST_PLAYER", "SECOND_PLAYER" + public String getType() {} +} +// API для работы с лифтами +class Elevator { + // Отправить лифт на указанный этаж, он доедет и выпустит пассажиров + public void goToFloor(Integer floor) {} + // Массив пассажиров, которых перевозит данный лифт + public List getPassengers() {} + // Текущий этаж + public Integer getFloor() {} + // Этаж, к которому лифт едет в данный момент + public Integer getNextFloor() {} + // Сколько времени лифт простоял на этаже + public Integer getTimeOnFloor() {} + // Координата лифта по Y + public Double getY() {} + // Скорость движения в текущий момент + public Double getSpeed() {} + // Какому игроку принадлежит + // Возвращаемое значение "FIRST_PLAYER", "SECOND_PLAYER" + public String getType() {} + // Состояние Лифта + public Integer getState() {} +} +``` diff --git a/clients/nodejs_client/README.md b/clients/nodejs_client/README.md new file mode 100644 index 0000000..3f1f1ba --- /dev/null +++ b/clients/nodejs_client/README.md @@ -0,0 +1,57 @@ +```javascript +// В стратегию приходит четыре массива +Array из Elevator myElevators +Array из Passenger myPassengers +Array из Elevator enemyElevators +Array из Passenger enemyPassengers +// Для отладки в консоль используйте вызов +this.debug(String) +// Каждый тик вызывается Strategy.onTick(myPassengers, myElevators, +enemyPassengers, enemyElevators) +// API для работы с пассажирами +class Passenger { + // Назначить пассажиру лифт + setElevator(elevator) {} + // Проверяет, назначен ли лифт пассажиру :Boolean + hasElevator() {} + // Текущий этаж :Number + get floor() {} + // Этаж, с которого едет пассажир :Number + get fromFloor() {} + // Этаж, на который едет пассажир :Number + get destFloor() {} + // Сколько времени осталось до ухода на лестницу :Number + get timeToAway() {} + // Координаты пассажира :Number + get x() {} + get y() {} + // Узнать к какому игроку привязан пассажир :String + // Возвращаемое значение "FIRST_PLAYER", "SECOND_PLAYER" + get type() {} + // Состояние пассажира + get state() {} +} +// API для работы с лифтами +class Elevator { + // Отправить лифт на указанный этаж, он доедет и выпустит +пассажиров :Number + go_to_floor(floor) {} + // Массив пассажиров, которых перевозит данный лифт :Array + get passengers() {} + // Текущий этаж :Number + get floor() {} + // Этаж, к которому лифт едет в данный момент :Number + get nextFloor() {} + // Сколько времени лифт простоял на этаже :Number + get timeOnFloor() {} + // Координата лифта по Y :Number +get y() {} + // Скорость движения в текущий момент :Number + get speed() {} + // Какому игроку принадлежит :String + // Возвращаемое значение "FIRST_PLAYER", "SECOND_PLAYER" + get type() {} + // Состояние лифта + get state() {} +} +``` diff --git a/clients/php7_client/README.md b/clients/php7_client/README.md new file mode 100644 index 0000000..4f636a8 --- /dev/null +++ b/clients/php7_client/README.md @@ -0,0 +1,60 @@ +```php +// В стратегию приходит четыре массива +$my_passengers: array из Passenger +$my_elevators: array из Elevator +$enemy_passengers: array из Passenger +$enemy_elevators: array из Elevator +// Для отладки в консоль используйте вызов +$this->log($text) +// Каждый тик вызывается Strategy->on_tick($my_passengers, $my_elevators, +$enemy_passengers, $enemy_elevators) +// API для работы с пассажирами +class Passenger { + function __construct() { + // Текущий этаж :integer + $this->floor = $floor; + // Этаж, с которого едет пассажир :integer + $this->from_floor = $from_floor; + // Этаж, на который едет пассажир :integer + $this->dest_floor = $dest_floor; + // Сколько времени осталось до ухода на лестницу :integer + $this->time_to_away = $time_to_away; + // Координаты пассажира :float + $this->x = $x; + $this->y = $y; + // Узнать к какому игроку привязан пассажир :string {"FIRST_PLAYER", +"SECOND_PLAYER"} + $this->type = $type; + // Состояние пассажира + $this->state = $state; + } + // Назначить пассажиру лифт + public function set_elevator($elevator) {} + // Проверяет, назначен ли лифт пассажиру + public function has_elevator() : bool {} +} +// API для работы с лифтами +class Elevator { + function __construct() { + // Текущий этаж :integer + $this->floor = $floor; + // Этаж, к которому лифт едет в данный момент :integer + $this->next_floor = $next_floor; + // Сколько времени лифт простоял на этаже :integer + $this->time_on_floor = $time_on_floor; + // Координата лифта по Y :float + $this->y = $y; + // Скорость движения в текущий момент :float + $this->speed = $speed; + // Какому игроку принадлежит :string {"FIRST_PLAYER", "SECOND_PLAYER"} + $this->type = $type; + // Массив пассажиров, которых перевозит данный лифт + $this->$passengers = $passengers; + // Состояние лифта + $this->state = $state; +} + // Отправить лифт на указанный этаж, он доедет и выпустит +пассажиров :integer + public function go_to_floor(floor) {} +} +``` diff --git a/clients/python2_client/README.md b/clients/python2_client/README.md new file mode 100644 index 0000000..9dffd8e --- /dev/null +++ b/clients/python2_client/README.md @@ -0,0 +1,57 @@ +```python +# В стратегию приходит четыре массива +list из Elevator: my_elevators +list из Passenger: my_passengers +list из Elevator: enemy_elevators +list из Passenger: enemy_passengers +# Для отладки в консоль используйте вызов +self.debug(str) +# Каждый тик вызывается Strategy.on_tick(my_elevators, my_passengers, +enemy_elevators, enemy_passengers) +# API для работы с пассажирами +class Passenger(object): + def __init__(self, x, y, type, time_to_away, from_floor, dest_floor, +floor): +# Текущий этаж :int +self.floor = floor +# Этаж, с которого едет пассажир: int +self.from_floor = from_floor +# Этаж, на который едет пассажир :int +self.dest_floor = dest_floor +# Сколько времени осталось до ухода на лестницу :int +self.time_to_away = time_to_away +# Координаты пассажира :float +self.x, self.y = x, y +# Узнать к какому игроку привязан пассажир :string +# Возвращаемое значение "FIRST_PLAYER", "SECOND_PLAYER" +self.type = type +# Состояние пассажира +self.state = state + # Проверяет, назначен ли лифт пассажиру + def has_elevator(self): pass + # Назначить пассажиру лифт + def set_elevator(self, elevator): pass +# API для работы с лифтами +class Elevator(object): + def __init__(self, y, passengers, speed, floor, next_floor, time_on_floor, +type): +# Текущий этаж :int +self.floor = floor +# Этаж, к которому лифт едет в данный момент :int +self.next_floor = next_floor +# Сколько времени лифт простоял на этаже :int +self.time_on_floor = time_on_floor +# Координата лифта по Y :float +self.y = y +# Скорость движения в текущий момент :float +self.speed = speed +# Какому игроку принадлежит :string +# Возвращаемое значение "FIRST_PLAYER", "SECOND_PLAYER" +self.type = type +# Массив пассажиров, которых перевозит данный лифт :list из Passenger +self.passengers = passengers +# Состояние лифта +self.state = state +# Отправить лифт на указанный этаж :int, он доедет и выпустит пассажиров +def go_to_floor(self, floor): pass +``` diff --git a/clients/python3_client/README.md b/clients/python3_client/README.md new file mode 100644 index 0000000..9dffd8e --- /dev/null +++ b/clients/python3_client/README.md @@ -0,0 +1,57 @@ +```python +# В стратегию приходит четыре массива +list из Elevator: my_elevators +list из Passenger: my_passengers +list из Elevator: enemy_elevators +list из Passenger: enemy_passengers +# Для отладки в консоль используйте вызов +self.debug(str) +# Каждый тик вызывается Strategy.on_tick(my_elevators, my_passengers, +enemy_elevators, enemy_passengers) +# API для работы с пассажирами +class Passenger(object): + def __init__(self, x, y, type, time_to_away, from_floor, dest_floor, +floor): +# Текущий этаж :int +self.floor = floor +# Этаж, с которого едет пассажир: int +self.from_floor = from_floor +# Этаж, на который едет пассажир :int +self.dest_floor = dest_floor +# Сколько времени осталось до ухода на лестницу :int +self.time_to_away = time_to_away +# Координаты пассажира :float +self.x, self.y = x, y +# Узнать к какому игроку привязан пассажир :string +# Возвращаемое значение "FIRST_PLAYER", "SECOND_PLAYER" +self.type = type +# Состояние пассажира +self.state = state + # Проверяет, назначен ли лифт пассажиру + def has_elevator(self): pass + # Назначить пассажиру лифт + def set_elevator(self, elevator): pass +# API для работы с лифтами +class Elevator(object): + def __init__(self, y, passengers, speed, floor, next_floor, time_on_floor, +type): +# Текущий этаж :int +self.floor = floor +# Этаж, к которому лифт едет в данный момент :int +self.next_floor = next_floor +# Сколько времени лифт простоял на этаже :int +self.time_on_floor = time_on_floor +# Координата лифта по Y :float +self.y = y +# Скорость движения в текущий момент :float +self.speed = speed +# Какому игроку принадлежит :string +# Возвращаемое значение "FIRST_PLAYER", "SECOND_PLAYER" +self.type = type +# Массив пассажиров, которых перевозит данный лифт :list из Passenger +self.passengers = passengers +# Состояние лифта +self.state = state +# Отправить лифт на указанный этаж :int, он доедет и выпустит пассажиров +def go_to_floor(self, floor): pass +``` From 0724818f0b36102ccf1877361bc9c03f7c36acb7 Mon Sep 17 00:00:00 2001 From: Stycenko Ilia Date: Fri, 22 Sep 2017 22:03:34 +0300 Subject: [PATCH 2/5] docs --- clients/c_sharp_client/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 clients/c_sharp_client/README.md diff --git a/clients/c_sharp_client/README.md b/clients/c_sharp_client/README.md new file mode 100644 index 0000000..5d08686 --- /dev/null +++ b/clients/c_sharp_client/README.md @@ -0,0 +1 @@ +To be done From a6255ef3d75973f348b2055cf24b74cbc1de7d51 Mon Sep 17 00:00:00 2001 From: Stycenko Ilia Date: Fri, 22 Sep 2017 22:17:13 +0300 Subject: [PATCH 3/5] doc c# --- clients/c_sharp_client/README.md | 58 +++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/clients/c_sharp_client/README.md b/clients/c_sharp_client/README.md index 5d08686..5419792 100644 --- a/clients/c_sharp_client/README.md +++ b/clients/c_sharp_client/README.md @@ -1 +1,57 @@ -To be done +```csharp +// В стратегию приходит четыре массива +List myElevators; +List myPassengers; +List enemyElevators; +List enemyPassengers; +// Для отладки в консоль используйте вызов +this.log(Object object) +// Каждый тик вызывается Strategy.onTick(List, List, List, List) +// API для работы с пассажирами +class Passenger { + // Назначить пассажиру лифт + public void SetElevator(Elevator elevator) {} + // Проверяет, назначен ли лифт пассажиру + public bool HasElevator() {} + // Текущий этаж + public int Floor; + // Этаж, с которого едет пассажир + public int FromFloor; + // Этаж, на который едет пассажир + public int DestFloor; + // Состояние пассажира + public int State; + // Сколько времени осталось до ухода на лестницу + public int TimeToAway; + // Координаты пассажира + public float Y; + public float X; + // Узнать к какому игроку привязан пассажир + // Возвращаемое значение "FIRST_PLAYER", "SECOND_PLAYER" + public String Type; + // Вес пассажира + public float Weight; +} +// API для работы с лифтами +class Elevator { + // Отправить лифт на указанный этаж, он доедет и выпустит пассажиров + public void goToFloor(int floor) {} + // Массив пассажиров, которых перевозит данный лифт + public List Passengers; + // Текущий этаж + public int Floor; + // Этаж, к которому лифт едет в данный момент + public int NextFloor; + // Сколько времени лифт простоял на этаже + public int TimeOnFloor; + // Координата лифта по Y + public float Y; + // Скорость движения в текущий момент + public float Speed; + // Какому игроку принадлежит + // Возвращаемое значение "FIRST_PLAYER", "SECOND_PLAYER" + public String Type; + // Состояние Лифта + public int State; +} +``` From 29099f0e2044e3c59e47f5f2f3257048676e682b Mon Sep 17 00:00:00 2001 From: Stycenko Ilia Date: Fri, 22 Sep 2017 22:22:02 +0300 Subject: [PATCH 4/5] go, kotlin --- clients/go_client/README.md | 1 + .../go_client/client/src/client/Strategy.go | 42 +++++++ .../client/src/client/core/API/API.go | 90 ++++++++++++++ .../src/client/core/API/BaseStrategy.go | 36 ++++++ .../client/src/client/core/API/Debug.go | 33 +++++ .../client/src/client/core/API/Elevator.go | 101 +++++++++++++++ .../client/src/client/core/API/Message.go | 11 ++ .../client/src/client/core/API/Passenger.go | 117 ++++++++++++++++++ clients/go_client/client/src/client/main.go | 100 +++++++++++++++ clients/kotlin_client/README.md | 1 + .../client/src/main/kotlin/Run.kt | 8 ++ .../client/src/main/kotlin/core/API/API.kt | 57 +++++++++ .../client/src/main/kotlin/core/API/Debug.kt | 39 ++++++ .../src/main/kotlin/core/API/Elevator.kt | 35 ++++++ .../main/kotlin/core/API/MessagesInterface.kt | 7 ++ .../src/main/kotlin/core/API/Passenger.kt | 33 +++++ .../src/main/kotlin/core/BaseStrategy.kt | 15 +++ .../client/src/main/kotlin/core/Client.kt | 59 +++++++++ .../client/src/main/kotlin/core/Strategy.kt | 24 ++++ 19 files changed, 809 insertions(+) create mode 100644 clients/go_client/README.md create mode 100644 clients/go_client/client/src/client/Strategy.go create mode 100644 clients/go_client/client/src/client/core/API/API.go create mode 100644 clients/go_client/client/src/client/core/API/BaseStrategy.go create mode 100644 clients/go_client/client/src/client/core/API/Debug.go create mode 100644 clients/go_client/client/src/client/core/API/Elevator.go create mode 100644 clients/go_client/client/src/client/core/API/Message.go create mode 100644 clients/go_client/client/src/client/core/API/Passenger.go create mode 100644 clients/go_client/client/src/client/main.go create mode 100644 clients/kotlin_client/README.md create mode 100644 clients/kotlin_client/client/src/main/kotlin/Run.kt create mode 100644 clients/kotlin_client/client/src/main/kotlin/core/API/API.kt create mode 100644 clients/kotlin_client/client/src/main/kotlin/core/API/Debug.kt create mode 100644 clients/kotlin_client/client/src/main/kotlin/core/API/Elevator.kt create mode 100644 clients/kotlin_client/client/src/main/kotlin/core/API/MessagesInterface.kt create mode 100644 clients/kotlin_client/client/src/main/kotlin/core/API/Passenger.kt create mode 100644 clients/kotlin_client/client/src/main/kotlin/core/BaseStrategy.kt create mode 100644 clients/kotlin_client/client/src/main/kotlin/core/Client.kt create mode 100644 clients/kotlin_client/client/src/main/kotlin/core/Strategy.kt diff --git a/clients/go_client/README.md b/clients/go_client/README.md new file mode 100644 index 0000000..5d08686 --- /dev/null +++ b/clients/go_client/README.md @@ -0,0 +1 @@ +To be done diff --git a/clients/go_client/client/src/client/Strategy.go b/clients/go_client/client/src/client/Strategy.go new file mode 100644 index 0000000..90a27c1 --- /dev/null +++ b/clients/go_client/client/src/client/Strategy.go @@ -0,0 +1,42 @@ +package main + +import ( + "client/core/API" +) + +type Strategy struct { + API.BaseStrategy +} + +// Вызывается при инициализации клиента +func (s *Strategy) Init(){ + +} + +func (s *Strategy) OnTick(myPassengers []*API.Passenger, myElevators []*API.Elevator, + enemyPassengers []*API.Passenger, enemyElevators []*API.Elevator) error { + + for i := 0; i < len(myElevators); i++ { + elevator := myElevators[i] + + for j := 0; j < len(myPassengers); j++ { + passenger := myPassengers[j] + + if passenger.State() < 5{ + if elevator.State() != 1{ + elevator.GoToFloor(passenger.FromFloor()) + } + if elevator.Floor() == passenger.Floor(){ + passenger.SetElevator(elevator) + } + } + } + + if len(elevator.Passengers()) > 0 && elevator.State() != 1{ + elevator.GoToFloor(elevator.Passengers()[0].DestFloor()) + } + } + + return nil +} + diff --git a/clients/go_client/client/src/client/core/API/API.go b/clients/go_client/client/src/client/core/API/API.go new file mode 100644 index 0000000..f3418dd --- /dev/null +++ b/clients/go_client/client/src/client/core/API/API.go @@ -0,0 +1,90 @@ +package API + +type API struct { + mDebug *Debug + mStrategy IBaseStrategy +} + +func (a *API) parseState(state map[string]interface{}) ([]*Passenger, []*Elevator, []*Passenger, []*Elevator) { + + var myPassengers, enemyPassengers []*Passenger + var myElevators, enemyElevators []*Elevator + + my_passengers, _ := state["my_passengers"] + + for _, passenger := range my_passengers.([]interface{}) { + myPassengers = append(myPassengers, NewPassenger(passenger.(map[string]interface{}))) + } + + enemy_passengers, _ := state["enemy_passengers"] + + for _, passenger := range enemy_passengers.([]interface{}) { + enemyPassengers = append(enemyPassengers, NewPassenger(passenger.(map[string]interface{}))) + } + + my_elevators, _ := state["my_elevators"] + + for _, elevator := range my_elevators.([]interface{}) { + myElevators = append(myElevators, NewElevator(elevator.(map[string]interface{}))) + } + + enemy_elevators, _ := state["enemy_elevators"] + + for _, elevator := range enemy_elevators.([]interface{}) { + enemyElevators = append(enemyElevators, NewElevator(elevator.(map[string]interface{}))) + } + + return myPassengers, myElevators, enemyPassengers, enemyElevators +} + +func (a *API) Turn(state map[string]interface{}) []interface{}{ + var messages []interface{} + + myPassengers, myElevators, enemyPassengers, enemyElevators := a.parseState(state) + + err := a.mStrategy.OnTick(myPassengers, myElevators, enemyPassengers, enemyElevators) + + if err != nil{ + a.mDebug.Exception(err) + } + + for i := 0; i < len(myPassengers); i++ { + if m := myPassengers[i].Messages(); m != nil{ + messages = append(messages, m...) + } + } + + for i := 0; i < len(myElevators); i++ { + if m := myElevators[i].Messages(); m != nil{ + messages = append(messages, m...) + } + } + + for i := 0; i < len(enemyPassengers); i++ { + if m := enemyPassengers[i].Messages(); m != nil{ + messages = append(messages, m...) + } + } + + for i := 0; i < len(enemyElevators); i++ { + if m := enemyElevators[i].Messages(); m != nil{ + messages = append(messages, m...) + } + } + + if m := a.mDebug.Messages(); m != nil{ + messages = append(messages, m...) + } + + return messages +} + +func NewAPI(s IBaseStrategy) *API { + a := &API{} + a.mDebug = NewDebug() + a.mStrategy = s + a.mStrategy.Init() + a.mStrategy.SetDebug(a.mDebug) + + return a +} \ No newline at end of file diff --git a/clients/go_client/client/src/client/core/API/BaseStrategy.go b/clients/go_client/client/src/client/core/API/BaseStrategy.go new file mode 100644 index 0000000..69a3d30 --- /dev/null +++ b/clients/go_client/client/src/client/core/API/BaseStrategy.go @@ -0,0 +1,36 @@ +package API + +type BaseStrategy struct { + mDebug *Debug +} + +type IBaseStrategy interface { + Init() + Debug() *Debug + SetDebug(debug *Debug) + Log(object interface{}) + OnTick(myPassengers []*Passenger, myElevators []*Elevator, + enemyPassengers []*Passenger, enemyElevators []*Elevator) error +} + +func (s *BaseStrategy) Init() { + +} + +func (s *BaseStrategy) Debug() *Debug { + return s.mDebug +} + +func (s *BaseStrategy) SetDebug(debug *Debug) { + s.mDebug = debug +} + +func (s *BaseStrategy) Log(object interface{}) { + s.mDebug.Log(object) +} + +func (s *BaseStrategy) OnTick(myPassengers []*Passenger, myElevators []*Elevator, + enemyPassengers []*Passenger, enemyElevators []*Elevator) error { + + return nil +} diff --git a/clients/go_client/client/src/client/core/API/Debug.go b/clients/go_client/client/src/client/core/API/Debug.go new file mode 100644 index 0000000..cc99a34 --- /dev/null +++ b/clients/go_client/client/src/client/core/API/Debug.go @@ -0,0 +1,33 @@ +package API + +import "fmt" + +type Debug struct { + message +} + +func (d *Debug) Log(object interface{}) { + cmd := make(map[string]interface{}) + cmd["text"] = fmt.Sprint(object) + + message := make(map[string]interface{}) + message["command"] = "log" + message["args"] = cmd + + d.mMessages = append(d.mMessages, message) +} + +func (d *Debug) Exception(object interface{}) { + cmd := make(map[string]interface{}) + cmd["text"] = fmt.Sprint(object) + + message := make(map[string]interface{}) + message["command"] = "exception" + message["args"] = cmd + + d.mMessages = append(d.mMessages, message) +} + +func NewDebug() *Debug { + return &Debug{} +} diff --git a/clients/go_client/client/src/client/core/API/Elevator.go b/clients/go_client/client/src/client/core/API/Elevator.go new file mode 100644 index 0000000..a4b7a0f --- /dev/null +++ b/clients/go_client/client/src/client/core/API/Elevator.go @@ -0,0 +1,101 @@ +package API + +type Elevator struct { + message + mID int + mState int + mType string + mFloor int + mY float64 + mPassengers []*Passenger + mSpeed float64 + mTimeOnFloor int + mNextFloor int +} + +func (e *Elevator) ID() int { + return e.mID +} + +func (e *Elevator) State() int { + return e.mState +} + +func (e *Elevator) Type() string { + return e.mType +} + +func (e *Elevator) Floor() int { + return e.mFloor +} + +func (e *Elevator) Y() float64 { + return e.mY +} + +func (e *Elevator) Passengers() []*Passenger { + return e.mPassengers +} + +func (e *Elevator) Speed() float64 { + return e.mSpeed +} + +func (e *Elevator) TimeOnFloor() int { + return e.mTimeOnFloor +} + +func (e *Elevator) NextFloor() int { + return e.mNextFloor +} + +func (e *Elevator) GoToFloor(floor int) { + e.mNextFloor = floor + + cmd := make(map[string]interface{}) + cmd["elevator_id"] = e.ID() + cmd["floor"] = floor + + message := make(map[string]interface{}) + message["command"] = "go_to_floor" + message["args"] = cmd + + e.mMessages = append(e.mMessages, message) +} + +func NewElevator(JSONObj map[string]interface{}) *Elevator { + + e := &Elevator{} + + id, _ := JSONObj["id"] + e.mID = int(id.(float64)) + + state, _ := JSONObj["state"] + e.mState = int(state.(float64)) + + t, _ := JSONObj["type"] + e.mType = t.(string) + + floor, _ := JSONObj["floor"] + e.mFloor = int(floor.(float64)) + + y, _ := JSONObj["y"] + e.mY = y.(float64) + + passengers, _ := JSONObj["passengers"] + + for _, passenger := range passengers.([]interface{}) { + e.mPassengers = append(e.Passengers(), NewPassenger(passenger.(map[string]interface{}))) + } + + speed, _ := JSONObj["speed"] + e.mSpeed = speed.(float64) + + timeOnFloor, _ := JSONObj["time_on_floor"] + e.mTimeOnFloor = int(timeOnFloor.(float64)) + + nextFloor, _ := JSONObj["next_floor"] + e.mNextFloor = int(nextFloor.(float64)) + + return e +} diff --git a/clients/go_client/client/src/client/core/API/Message.go b/clients/go_client/client/src/client/core/API/Message.go new file mode 100644 index 0000000..db920e7 --- /dev/null +++ b/clients/go_client/client/src/client/core/API/Message.go @@ -0,0 +1,11 @@ +package API + +type message struct { + mMessages []interface{} +} + +func (m *message) Messages() []interface{} { + messages := m.mMessages + m.mMessages = []interface{}{} + return messages +} diff --git a/clients/go_client/client/src/client/core/API/Passenger.go b/clients/go_client/client/src/client/core/API/Passenger.go new file mode 100644 index 0000000..b9159f9 --- /dev/null +++ b/clients/go_client/client/src/client/core/API/Passenger.go @@ -0,0 +1,117 @@ +package API + +type Passenger struct { + message + mID int + mState int + mType string + mFloor int + mX float64 + mY float64 + mElevator int + mFromFloor int + mDestFloor int + mTimeToAway int + mWeight float64 +} + +func (p *Passenger) ID() int { + return p.mID +} + +func (p *Passenger) State() int { + return p.mState +} + +func (p *Passenger) Type() string { + return p.mType +} + +func (p *Passenger) Floor() int { + return p.mFloor +} + +func (p *Passenger) X() float64 { + return p.mX +} + +func (p *Passenger) Y() float64 { + return p.mY +} + +func (p *Passenger) HasElevator() bool { + return p.mElevator != -1 +} + +func (p *Passenger) FromFloor() int { + return p.mFromFloor +} + +func (p *Passenger) DestFloor() int { + return p.mDestFloor +} + +func (p *Passenger) TimeToAway() int { + return p.mTimeToAway +} + +func (p *Passenger) Weight() float64 { + return p.mWeight +} + +func (p *Passenger) SetElevator(elevator *Elevator) { + p.mElevator = elevator.ID() + + cmd := make(map[string]interface{}) + cmd["passenger_id"] = p.ID() + cmd["elevator_id"] = elevator.ID() + + message := make(map[string]interface{}) + message["command"] = "set_elevator_to_passenger" + message["args"] = cmd + + p.mMessages = append(p.mMessages, message) +} + +func NewPassenger(JSONObj map[string]interface{}) *Passenger { + p := &Passenger{} + + id, _ := JSONObj["id"] + p.mID = int(id.(float64)) + + state, _ := JSONObj["state"] + p.mState = int(state.(float64)) + + t, _ := JSONObj["type"] + p.mType = t.(string) + + floor, _ := JSONObj["floor"] + p.mFloor = int(floor.(float64)) + + x, _ := JSONObj["x"] + p.mX = x.(float64) + + y, _ := JSONObj["y"] + p.mY = y.(float64) + + elevator, ok := JSONObj["elevator"] + if !ok || elevator == nil { + p.mElevator = -1 + } else { + p.mElevator = int(elevator.(float64)) + } + + fromFloor, _ := JSONObj["from_floor"] + p.mFromFloor = int(fromFloor.(float64)) + + destFloor, _ := JSONObj["dest_floor"] + p.mDestFloor = int(destFloor.(float64)) + + timeToAway, _ := JSONObj["time_to_away"] + p.mTimeToAway = int(timeToAway.(float64)) + + weight, _ := JSONObj["weight"] + p.mWeight = weight.(float64) + + return p +} diff --git a/clients/go_client/client/src/client/main.go b/clients/go_client/client/src/client/main.go new file mode 100644 index 0000000..4600b36 --- /dev/null +++ b/clients/go_client/client/src/client/main.go @@ -0,0 +1,100 @@ +package main + +import ( + "encoding/json" + "client/core/API" + "fmt" + "net" + "bufio" + "sync" + "log" + "os" +) + +func main() { + + host := os.Getenv("WORLD_NAME") + + if host == "" { + host = "127.0.0.1" + } + + solutionId := os.Getenv("SOLUTION_ID") + + if solutionId == "" { + solutionId = "-1" + } + + loop(host, 8000, solutionId) +} + +func getMessage(reader *bufio.Reader, jsonObject *interface{}) error{ + message, err := reader.ReadBytes('\n') + + if err != nil { + return err + } + + err = json.Unmarshal(message, &jsonObject) + + if err != nil || jsonObject == nil { + log.Fatalf("JSON parse error: %s", err) + return err + } + + return nil +} + +func loop(host string, port int, solutionId string) { + var jsonPool = sync.Pool{} + + conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", host, port)) + + if err != nil { + log.Fatalf("Socket error: %s", err) + return + } + + defer conn.Close() + + reader := bufio.NewReader(conn) + + _, err = fmt.Fprintf(conn, `{"solution_id":"%s"}` + "\n", solutionId) + + if err != nil { + log.Fatal("Can not send solution_id") + return + } + + api := API.NewAPI(&Strategy{}) + + for { + + jsonObject := jsonPool.Get() + + if err := getMessage(reader , &jsonObject); err != nil{ + log.Fatalf("JSON parse error: %s", err) + break + } + + if cmd, ok := jsonObject.(map[string]interface{})["message"]; ok { + if cmd.(string) == "down" { + log.Println("Parsed down") + break + } + if err := getMessage(reader , &jsonObject); err != nil{ + log.Fatalf("JSON parse error: %s", err) + break + } + } + + jsonArray := api.Turn(jsonObject.(map[string]interface{})) + + res, _ := json.Marshal(jsonArray) + + conn.Write(res) + conn.Write([]byte("\n")) + + jsonPool.Put(jsonObject) + } +} diff --git a/clients/kotlin_client/README.md b/clients/kotlin_client/README.md new file mode 100644 index 0000000..5d08686 --- /dev/null +++ b/clients/kotlin_client/README.md @@ -0,0 +1 @@ +To be done diff --git a/clients/kotlin_client/client/src/main/kotlin/Run.kt b/clients/kotlin_client/client/src/main/kotlin/Run.kt new file mode 100644 index 0000000..432f688 --- /dev/null +++ b/clients/kotlin_client/client/src/main/kotlin/Run.kt @@ -0,0 +1,8 @@ +import core.Client + +fun main(args: Array) { + val host = System.getenv("WORLD_NAME") ?: "127.0.0.1" + val solutionId = System.getenv("SOLUTION_ID") ?: "-1" + val client = Client(host, 8000, solutionId) + client.connect() +} \ No newline at end of file diff --git a/clients/kotlin_client/client/src/main/kotlin/core/API/API.kt b/clients/kotlin_client/client/src/main/kotlin/core/API/API.kt new file mode 100644 index 0000000..43bda45 --- /dev/null +++ b/clients/kotlin_client/client/src/main/kotlin/core/API/API.kt @@ -0,0 +1,57 @@ +package core.API + +import core.BaseStrategy +import core.Strategy +import javafx.util.Pair +import org.json.simple.JSONArray +import org.json.simple.JSONObject +import java.util.ArrayList +import java.util.function.Function +import java.util.stream.Collectors +import java.util.stream.Stream + +class API { + private val debug = Debug() + private var strategy : BaseStrategy? = null + + init { + try { + strategy = Strategy() + strategy?.setDebug(debug) + } catch (e: Exception) { + debug.exception(e) + } + } + + private fun parseState(state: JSONObject): Pair, List>, Pair, List>> { + val myPassengers = (state["my_passengers"] as JSONArray).map { Passenger(it as JSONObject) } + val myElevators = (state["my_elevators"] as JSONArray).mapTo(ArrayList(3)) { Elevator(it as JSONObject) } + + val enemyPassengers = (state["enemy_passengers"] as JSONArray).map { Passenger(it as JSONObject) } + val enemyElevators = (state["enemy_elevators"] as JSONArray).mapTo(ArrayList(3)) { Elevator(it as JSONObject) } + + val myPair = Pair, List>(myPassengers, myElevators) + val enemyPair = Pair, List>(enemyPassengers, enemyElevators) + + return Pair(myPair, enemyPair) + } + + fun turn(state: JSONObject): JSONArray { + val pair = parseState(state) + + try { + this.strategy?.onTick(pair.key.key, pair.key.value, pair.value.key, pair.value.value) + } catch (e: Exception) { + debug.exception(e) + } + + val resultArray = JSONArray() + resultArray.addAll(Stream.of(pair.key.key.stream(), + pair.key.value.stream(), + pair.value.key.stream(), Stream.of(debug)) + .flatMap(Function.identity()) + .flatMap { msg -> msg.getMessages().stream() } + .collect(Collectors.toList())) + return resultArray + } +} \ No newline at end of file diff --git a/clients/kotlin_client/client/src/main/kotlin/core/API/Debug.kt b/clients/kotlin_client/client/src/main/kotlin/core/API/Debug.kt new file mode 100644 index 0000000..37706b8 --- /dev/null +++ b/clients/kotlin_client/client/src/main/kotlin/core/API/Debug.kt @@ -0,0 +1,39 @@ +package core.API + +import org.json.simple.JSONObject +import java.util.* + +class Debug : MessagesInterface { + + private var messages = ArrayList() + + fun log(obj: Any) { + val jo = JSONObject() + jo.put("command", "log") + + val args = JSONObject() + args.put("text", obj.toString()) + + jo.put("args", args) + this.messages.add(jo) + } + + fun exception(obj: Any) { + val jo = JSONObject() + jo.put("command", "exception") + + val args = JSONObject() + args.put("text", obj.toString()) + + jo.put("args", args) + this.messages.add(jo) + } + + + override fun getMessages(): List { + val result = ArrayList(this.messages) + this.messages.clear() + return result + } + +} \ No newline at end of file diff --git a/clients/kotlin_client/client/src/main/kotlin/core/API/Elevator.kt b/clients/kotlin_client/client/src/main/kotlin/core/API/Elevator.kt new file mode 100644 index 0000000..f06fe2e --- /dev/null +++ b/clients/kotlin_client/client/src/main/kotlin/core/API/Elevator.kt @@ -0,0 +1,35 @@ +package core.API + +import org.json.simple.JSONArray +import org.json.simple.JSONObject + +class Elevator(elevator: JSONObject) : MessagesInterface { + val id: Int = elevator["id"]?.toString()?.toInt() ?: 0 + val y: Double = elevator["y"]?.toString()?.toDouble() ?: 0.0 + val passengers = ArrayList() + val state: Int = elevator["state"]?.toString()?.toInt() ?: 0 + val speed: Double = elevator["speed"]?.toString()?.toDouble() ?: 0.0 + val timeOnFloor: Int = elevator["time_on_floor"]?.toString()?.toInt() ?: 0 + val floor: Int = elevator["floor"]?.toString()?.toInt() ?: 0 + val type: String = elevator["type"]?.toString() ?: "" + var nextFloor: Int = elevator["next_floor"]?.toString()?.toInt() ?: 0 + private set + val messages = ArrayList() + + init { + (elevator["passengers"] as JSONArray).mapTo(passengers) { Passenger(it as JSONObject) } + } + + override fun getMessages(): List = messages + + fun goToFloor(floor: Int?) { + this.nextFloor = floor ?: 0 + val jo = JSONObject() + jo.put("command", "go_to_floor") + val args = JSONObject() + args.put("elevator_id", this.id) + args.put("floor", floor) + jo.put("args", args) + this.messages.add(jo) + } +} \ No newline at end of file diff --git a/clients/kotlin_client/client/src/main/kotlin/core/API/MessagesInterface.kt b/clients/kotlin_client/client/src/main/kotlin/core/API/MessagesInterface.kt new file mode 100644 index 0000000..f4195ba --- /dev/null +++ b/clients/kotlin_client/client/src/main/kotlin/core/API/MessagesInterface.kt @@ -0,0 +1,7 @@ +package core.API + +import org.json.simple.JSONObject + +interface MessagesInterface { + fun getMessages(): List +} \ No newline at end of file diff --git a/clients/kotlin_client/client/src/main/kotlin/core/API/Passenger.kt b/clients/kotlin_client/client/src/main/kotlin/core/API/Passenger.kt new file mode 100644 index 0000000..b167faf --- /dev/null +++ b/clients/kotlin_client/client/src/main/kotlin/core/API/Passenger.kt @@ -0,0 +1,33 @@ +package core.API + +import org.json.simple.JSONObject + +class Passenger(passenger: JSONObject) : MessagesInterface{ + + val id: Int = passenger["id"]?.toString()?.toInt() ?: 0 + var elevator: Int = passenger["elevator"]?.toString()?.toInt() ?: 0 + private set + + val fromFloor: Int = passenger["from_floor"]?.toString()?.toInt() ?: 0 + val destFloor: Int = passenger["dest_floor"]?.toString()?.toInt() ?: 0 + val state: Int = passenger["state"]?.toString()?.toInt() ?: 0 + val timeToAway: Int = passenger["time_to_away"]?.toString()?.toInt() ?: 0 + val type: String = passenger["type"]?.toString() ?: "" + val floor: Int = passenger["floor"]?.toString()?.toLong()?.toInt() ?: 0 + private val messages = ArrayList() + var x: Double = passenger["x"]?.toString()?.toDouble() ?: 0.0 + var y: Double = passenger["y"]?.toString()?.toDouble() ?: 0.0 + + override fun getMessages(): List = messages + + fun setElevator(elevator: Elevator) { + this.elevator = elevator.id + val jo = JSONObject() + jo.put("command", "set_elevator_to_passenger") + val args = JSONObject() + args.put("passenger_id", this.id) + args.put("elevator_id", elevator.id) + jo.put("args", args) + this.messages.add(jo) + } +} \ No newline at end of file diff --git a/clients/kotlin_client/client/src/main/kotlin/core/BaseStrategy.kt b/clients/kotlin_client/client/src/main/kotlin/core/BaseStrategy.kt new file mode 100644 index 0000000..3cb5a32 --- /dev/null +++ b/clients/kotlin_client/client/src/main/kotlin/core/BaseStrategy.kt @@ -0,0 +1,15 @@ +package core + +import core.API.Debug +import core.API.Elevator +import core.API.Passenger + +open class BaseStrategy { + private var debug: Debug? = null + + fun setDebug(debug: Debug) { + this.debug = debug + } + fun log(obj: Any) = debug?.log(obj) + open fun onTick(myPassengers: List, myElevators: List, enemyPassengers: List, enemyElevators: List) {} +} \ No newline at end of file diff --git a/clients/kotlin_client/client/src/main/kotlin/core/Client.kt b/clients/kotlin_client/client/src/main/kotlin/core/Client.kt new file mode 100644 index 0000000..c7ebe7e --- /dev/null +++ b/clients/kotlin_client/client/src/main/kotlin/core/Client.kt @@ -0,0 +1,59 @@ +package core + +import core.API.API +import org.json.simple.JSONAware +import org.json.simple.JSONObject +import org.json.simple.parser.ParseException +import org.json.simple.parser.JSONParser + +import java.io.* +import java.net.InetSocketAddress +import java.nio.ByteBuffer +import java.nio.channels.SocketChannel + +class Client(private val host: String, private val port: Int, private val solutionId: String) { + private val parser = JSONParser() + private var clientSocket: SocketChannel? = null + + private fun parseString(jsonString: String): JSONObject? { + return try { + parser.parse(jsonString) as JSONObject + } catch (e: ParseException) { + null + } + } + + @Throws(IOException::class) + fun connect() { + this.clientSocket = SocketChannel.open(InetSocketAddress(this.host, port)) + val obj = JSONObject() + obj.put("solution_id", solutionId) + clientSocket?.write(ByteBuffer.wrap(this.dumpMessage(obj).toByteArray())) + + val reader = BufferedReader(InputStreamReader(clientSocket?.socket()?.getInputStream())) + val message = parseString(reader.readLine()) + if (message == null) { + System.exit(1) + return + } + if ("beginning" == message["message"]) { + strategyLoop(reader) + } + } + + @Throws(IOException::class) + private fun strategyLoop(reader: BufferedReader) { + val api = API() + while (true) { + val obj = parseString(reader.readLine()) + if (obj == null || (obj["message"] != null && obj["message"] == "down")) { + break + } + clientSocket?.write(ByteBuffer.wrap(this.dumpMessage(api.turn(obj)).toByteArray())) + } + } + + private fun dumpMessage(obj: JSONAware): String { + return obj.toJSONString() + "\n" + } +} \ No newline at end of file diff --git a/clients/kotlin_client/client/src/main/kotlin/core/Strategy.kt b/clients/kotlin_client/client/src/main/kotlin/core/Strategy.kt new file mode 100644 index 0000000..8683eb1 --- /dev/null +++ b/clients/kotlin_client/client/src/main/kotlin/core/Strategy.kt @@ -0,0 +1,24 @@ +package core + +import core.API.Elevator +import core.API.Passenger + +class Strategy : BaseStrategy() { + override fun onTick(myPassengers: List, myElevators: List, enemyPassengers: List, enemyElevators: List) { + for (e in myElevators) { + for (p in myPassengers) { + if (p.state < 5) { + if (e.state != 1) { + e.goToFloor(p.fromFloor) + } + if (e.floor == p.fromFloor) { + p.setElevator(e) + } + } + } + if (e.passengers.size > 0 && e.state != 1) { + e.goToFloor(e.passengers[0].destFloor) + } + } + } +} \ No newline at end of file From b608a740a277c7c946c6e21c89bd31635675255a Mon Sep 17 00:00:00 2001 From: Stycenko Ilia Date: Fri, 22 Sep 2017 22:26:17 +0300 Subject: [PATCH 5/5] docs --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a155383..0bf735c 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,6 @@ ### [LocalRunner](/localrunner/README.md) -### [Клиенты](/clients/) +### [API](/clients/) ### [Базовые стратегии](/baseline/)