# 2019 台大椰林資訊營 AI Challenge Oil Tycoon 遊戲介紹
[TOC]
## 遊戲內容
* 本遊戲共有四位玩家,玩家們在石油神的眷顧下互相競爭,在遊戲時間結束時,由基地內擁有最多石油的玩家獲勝。
* 因為來自石油神的奇蹟,地圖上將隨機生成不同價值的石油(越靠螢幕中央,價值越高),且石油的顏色代表著他的價值的範圍,玩家可以自己觀察。玩家可移動到石油的位置上來獲得油,但身上的石油越多,行動速度會越慢,但若回到基地,可將身上石油全數放入基地,行動速度則回復為初始值。
* 移動速度會隨著油量的增加而線性遞減,降到一定程度之後會是定值。
* 玩家若和其他玩家碰撞,石油神會進行強制共產,把所有碰撞玩家身上的油量均分
* 遊戲場地中央為自經區,石油神認為貨出得去就能發大財,所以會在自經區內販賣道具,每個道具有不一樣的價值和效果,玩家到自經區時可用身上的石油跟石油神買道具,但若道具滯銷,石油神會自行銷毀。
* 寵物系統:每經過一段時間,寵物會出發尋找玩家,並將玩家身上一部分的油(最多1000)帶回基地,讓玩家可以放心採集。
## 手動控制

`wasd/tfgh/ijkl/上下左右`: 控制玩家的方向。
`q e/r y/u o/RSHIFT RCTRL`: 買道具=使用道具(由於在擁有或使用道具中時不能再購買,因此是同個操作)(兩個按鍵通用,只是看你習慣按左邊右邊)。
## 石油等級與價值
| Level | Value |
| ----- | ----- |
| 1 | 50~400 |
| 2 | 400~600 |
| 3 | 600~800 |
| 4 | 800~1200 |
## 道具 (item)
| item/skill | price |
| -------- | -------- |
| IGoHome | 500 |
| OtherGoHome | 500 |
| TheWorld | 1450 |
| MagnetAttract | 689 |
| Invincible | 500 |
| RadiusNotMove | 500 |
| RadiationOil | 1000 |
| ShuffleBases | 1 |
* `噴射背包 (IGoHome)`
* 讓自己瞬間回到基地。

* `通通都進來吧 (OtherGoHome)`
* 讓除了自己的所有人瞬間回到基地。

* `跟著月亮走 (MagnetAttract)`
* 在三秒內吸引玩家周圍的石油。

* `地溝油 (RadiationOil)`
* 在基地附近使用,讓範圍內基地的石油數減少(*0.9)。

* `無敵 (Invincible)`
* 在一定時間內不會被共產。

* `寒粉 (RadiusNotMove)`
* 冰凍玩家,使一定範圍之內除了自己的玩家都無法移動。

* `遷都 (ShuffleBases)`
* 隨機更換基地。

* `世界 (TheWorld)`
* 發動 "The world" 的效果中,只有發動的玩家本人可以自行移動,彷彿這是屬於他的世界一樣
* 只有發動世界的玩家有絕對的自由,例如移動、撿石油、使用其他道具、共產別人

* {%youtube -FT23AwNPOM%}
* {%youtube soyMVOxsy1Q%}
括號內的是物品在遊戲中的名稱,helper 之中跟道具有關的名稱就是指此。
<!-- $Dist(m_q) = Dist(W, N) = D(I, J) /( |W| + |N|)$ -->
## 裝備
有5種可以透過小隊表現得到的裝備卡,每張都能提供某種能力的增幅,有下列五種:
* `走到飛跑步鞋`
* 裝備者移動速度乘以1.1倍
* `666幸運戒指`
* 得到的石油乘以1.1倍
* `馮迪索牌防盜鎖`
* 得到500單位的隨身保險,當被觸發平均而將失去石油時,保險額內的石油不會被平均
* `別靠背厭世包`
* 寵物的攜帶上限乘以1.5倍
* `曲中人散熱器`
* 寵物的冷卻時間乘以0.8倍
在AI中`__init__`函式中加入`self.equipments = (a, b, c, d, e)`的5-tuple,代表每種裝備卡你有幾張。
## `decide()`的回傳值
* `AI_DIR_STOP` => 停
* `AI_DIR_U` => 上
* `AI_DIR_RU` => 右上
* `AI_DIR_R` => 右
* `AI_DIR_RD` => 右下
* `AI_DIR_D` => 下
* `AI_DIR_LD` => 左下
* `AI_DIR_L` => 左
* `AI_DIR_LU` => 左上
* `AI_TRIGGER_ITEM` => 買/用道具
## 地圖相關設定
左上角是原點,對於所有位置,第一個index是x軸,第二個index是y軸,往右是x正向,往下是y正向
示意圖:

## Helper
以下所有需要 `player_id` 作為參數的函數,如果不傳這個參數的話,就會預設自動代入自己的 id。id 的編號從 `0` 開始。
### 常數
* `player_id: int`
* 獲得自己的 id。
* `oil_radius: int`
* 油的半徑。
* `player_radius: int`
* 玩家半徑。
* `player_normal_speed: float`
* 玩家沒有負載時的速度。
* `base_length: int`
* 基地邊長。
* `game_size: tuple(int, int)`
* 遊戲場地大小。
* `market_position: tuple(int, int)`
* 市場位置。
* `market_radius: int`
* 市場半徑
* `radius_not_move_radius: int`
* "寒粉"的有效半徑。
* `radius_of_radiation_oil: int`
* 獲得"地溝油"的有效半徑。
* `radius_of_magnetic_attract: int`
* 獲得"跟著月亮走"的有效半徑。
### 玩家相關
* 通用規則: 所有需要有`player_id`參數的函數,可以不傳入此參數,來代表`player_id`為自己的id。
* `get_players_position(): [tuple(int, int), ...]`
* 獲得所有玩家的位置。
* 回傳值是長度為 4 的 list,第 i 個元素代表第 i 個玩家的位置。
* `get_player_position(player_id): tuple(int, int)`
* 獲得 `player_id` 的位置。
* `get_players_direction(): [tuple(int, int), ...]`
* 獲得所有玩家的方向。
* 回傳值跟 `get_players_position` 同理。每個方向的長度都是 1。
* `get_player_direction(player_id): tuple(int, int)`
* 獲得 `player_id` 的方向。
* `get_players_value(): [float, ...]`
* 獲得所有玩家身上的油量。
* 回傳值跟 `get_players_position` 同理。
* `get_player_value(player_id): float`
* 獲得 `player_id` 身上的油量。
* `get_players_speed(): [float, ...]`
* 獲得所有玩家的當前速度(經過負載加成後的速度)。
* 回傳值跟 `get_players_position` 同理。
* `get_player_speed(player_id): float`
* 獲得 `player_id` 的當前速度。
* `get_players_is_invincible(): [bool, ...]`
* 獲得所有玩家目前是否無敵。
* 回傳值跟 `get_players_position` 同理。
* `get_player_is_invincible(player_id): bool`
* 獲得 `player_id` 目前是否無敵。
* `get_players_insurance_value(): [int, ...]`
* 獲得所有玩家碰撞時的保底價值(不會被均分的價值量)。
* 回傳值跟 `get_players_position` 同理。
* `get_player_insurance_value(player_id): int`
* 獲得 `player_id` 的碰撞保底價值。
### 其他資訊
* `get_oils(): [tuple(float, float), ...]`
* 獲得場上所有油的位置。
* `get_oils_level(): [int, ...]`
* 獲得場上所有油的等級。
* `get_oils_distance_to_center(): [float, ...]`
* 獲得場上所有油到地圖中心的距離。
* 以上這三個函數的油是共享 index 的。即相同 index 代表的是同一個油。
* `get_oils_by_distance_from_center(): [tuple(float, float), ...]`
* 獲得場上所有油的位置,以到地圖中心的距離排序。
* `get_bases_center(): [tuple(int, int), ...]`
* 獲得所有玩家基地的位置。
* 回傳值跟 `get_players_position` 同理。
* `get_base_center(player_id): tuple(int, int)`
* 獲得 `player_id` 基地的位置。
* `get_base_value(player_id): int`
* 獲得 player_id 基地的油量。
* `get_bases_value(): [int, ...]`
* 獲得所有玩家的基地油量。
* 回傳值跟 `get_players_position` 同理。
* `get_market(): tuple(str, int, int)`
* 獲得市場販賣中的物品資訊。
* 元素分別是物品名稱、價錢,以及下一個物品出現的倒數計時。
* 如果市場中現在有物品,那倒數計時會是 0。
* 如果市場中現在沒有物品,那倒數計時會是距離物品出現的剩餘 tick 數,且前兩個元素會是 `None`。
* `get_player_item_name(player_id): str`
* 獲得 `player_id` 持有的物品名稱。
* 如果沒有物品的話,那麼回傳值是 `None`。
* `get_player_item_is_active(player_id): bool`
* 獲得 `player_id` 所持有的道具是否正在發動。
* `get_player_item_duration(player_id): int`
* 獲得 `player_id` 所持有的道具剩餘有效 tick 數量。如果道具尚未被發動,那麼回傳值是 `0`。
* `get_timer(): int`
* 獲得距離遊戲結束剩餘的 tick 數量。
### 其他
* `get_nearest_player(player_id): int`
* 獲得離 `player_id` 最近的玩家 id。
* `get_nearest_oil(player_id): tuple(float, float)`
* 獲得離 `player_id` 最近的油的位置。
* `get_most_valuable_player(): int`
* 獲得<del>最油</del>身上價值最高的玩家 id。
* `get_distance(p = tuple(float, float) or Vector2, q = tuple(float, float) or Vector2): float`
* 獲得 `p` 跟 `q` 的距離。
* 其實就是平方相加開根號。
* `get_distance_to_center(p = tuple(float, float) or Vector2): float`
* 獲得 `p` 到地圖中心的距離。
* `get_direction(vector = tuple(x, y)): int`
* 很重要的功能,取得方向代號。
* 當你決定了目的地,傳入(目的地 - 自己位置),可以得到一個代表對應的方向的整數。
## 可用顏色

當然,也可以找自己喜歡的顏色。