Code Royal - initial commit
This commit is contained in:
35
code_royal/src/Lib.purs
Normal file
35
code_royal/src/Lib.purs
Normal file
@@ -0,0 +1,35 @@
|
||||
module Lib where
|
||||
|
||||
import Prelude
|
||||
|
||||
import Data.Int (fromNumber, pow, toNumber)
|
||||
import Data.Maybe (fromMaybe)
|
||||
import Math as M
|
||||
import Range (Area(..), Pos(..), Range(..))
|
||||
|
||||
maxPos :: Pos -> Int
|
||||
maxPos (Pos x y) = max x y
|
||||
|
||||
minPos :: Pos -> Int
|
||||
minPos (Pos x y) = min x y
|
||||
|
||||
getMiddlePos :: Area -> Pos
|
||||
getMiddlePos (Area (Range x1 x2) (Range y1 y2)) = Pos x y
|
||||
where
|
||||
x = abs (x1 + x2) / 2
|
||||
y = abs (y1 + y2) / 2
|
||||
|
||||
abs :: Int -> Int
|
||||
abs x = fromMaybe 0 $ fromNumber $ M.abs $ toNumber x
|
||||
|
||||
sqrt :: Int -> Int
|
||||
sqrt x = fromMaybe 0 $ fromNumber $ M.sqrt $ toNumber x
|
||||
|
||||
dist :: forall a b. { x :: Int, y :: Int | a } -> { x :: Int, y :: Int | b } -> Int
|
||||
dist p1 p2 = sqrt $ a2 + b2
|
||||
where
|
||||
a2 = abs (p2.x - p1.x) `pow` 2
|
||||
b2 = abs (p2.y - p1.y) `pow` 2
|
||||
|
||||
toPos :: forall e. { x :: Int, y :: Int | e } -> Pos
|
||||
toPos p = Pos p.x p.y
|
||||
67
code_royal/src/Main.purs
Normal file
67
code_royal/src/Main.purs
Normal file
@@ -0,0 +1,67 @@
|
||||
module Main where
|
||||
|
||||
import Prelude
|
||||
|
||||
import Data.Array (any, drop, filter, head, length, sortBy)
|
||||
import Data.Maybe (Maybe(..), fromJust)
|
||||
import Effect (Effect)
|
||||
import Effect.Console (log, error)
|
||||
import GameInput (Site, Minion, SiteInfo, parseInitInput, parseInput)
|
||||
import Lib (dist, toPos)
|
||||
import Partial.Unsafe (unsafePartial)
|
||||
import Range (Pos(..))
|
||||
|
||||
main :: Effect Unit
|
||||
main = do
|
||||
initInput <- parseInitInput
|
||||
error $ show initInput
|
||||
loop initInput.numSites initInput.sites
|
||||
|
||||
loop :: Int -> Array SiteInfo -> Effect Unit
|
||||
loop numSites siteInfo = do
|
||||
input <- parseInput numSites
|
||||
|
||||
let touchedSite = if input.touchedSite == -1
|
||||
then Nothing
|
||||
else Just input.touchedSite
|
||||
|
||||
loop' numSites input.gold touchedSite siteInfo input.sites input.units
|
||||
|
||||
loop' :: Int -> Int -> Maybe Int -> Array SiteInfo -> Array Site -> Array Minion -> Effect Unit
|
||||
loop' numSites gold touchedSite siteInfo sites units = do
|
||||
error $ "Sites: " <> show sites
|
||||
error $ "SiteI: " <> show siteInfo
|
||||
|
||||
let queen = unsafePartial $ fromJust $ head $ filter (\u -> u.unitType == -1 && u.owner == 0) units
|
||||
let siteInfo' = sortBy (compareSiteInfoDist queen) siteInfo
|
||||
|
||||
case head siteInfo' of
|
||||
Just sInfo -> do
|
||||
log $ build sInfo
|
||||
log $ "TRAIN " <> show sInfo.id
|
||||
Nothing -> do
|
||||
log $ "WAIT"
|
||||
log $ "TRAIN"
|
||||
|
||||
loop numSites siteInfo
|
||||
|
||||
compareSiteInfoDist :: Minion -> SiteInfo -> SiteInfo -> Ordering
|
||||
compareSiteInfoDist u s1 s2 = compare (dist s1 u) (dist s2 u)
|
||||
|
||||
build :: forall e. { id :: Int | e } -> String
|
||||
build s = "BUILD " <> show s.id <> " BARRACKS-ARCHER"
|
||||
|
||||
moveToPos :: forall e. { x :: Int, y :: Int | e } -> String
|
||||
moveToPos p = "MOVE " <> show p.x <> " " <> show p.y
|
||||
|
||||
-- Phase 1
|
||||
-- Queen takes as much buildings as possible
|
||||
-- Build Archers only
|
||||
-- Phase 2
|
||||
-- Queen destroys enemy buildings
|
||||
-- Build Archers only
|
||||
-- Phase 3
|
||||
-- Queen avoids Knights
|
||||
-- All Buildings but one train Archers
|
||||
|
||||
-- nearestBuilding :: Pos
|
||||
26
code_royal/src/Ruler.purs
Normal file
26
code_royal/src/Ruler.purs
Normal file
@@ -0,0 +1,26 @@
|
||||
module Range
|
||||
( Area(..)
|
||||
, Pos(..)
|
||||
, Range(..)
|
||||
, range
|
||||
) where
|
||||
|
||||
import Prelude
|
||||
|
||||
-- data Building = Building Int Int
|
||||
data Pos = Pos Int Int
|
||||
data Area = Area Range Range
|
||||
|
||||
instance showPos :: Show Pos where
|
||||
show (Pos x y) = show x <> " " <> show y
|
||||
|
||||
instance showRange :: Show Range where
|
||||
show (Range x y) = show x <> "-" <> show y
|
||||
|
||||
instance showArea :: Show Area where
|
||||
show (Area r1 r2) = show r1 <> " / " <> show r2
|
||||
|
||||
data Range = Range Int Int
|
||||
|
||||
range :: Int -> Int -> Range
|
||||
range x y = Range (min x y) (max x y)
|
||||
73
code_royal/src/ffi/GameInput.js
Normal file
73
code_royal/src/ffi/GameInput.js
Normal file
@@ -0,0 +1,73 @@
|
||||
"use strict";
|
||||
|
||||
exports.readline = readline
|
||||
|
||||
exports.parseInitInput = function() {
|
||||
var sites = []
|
||||
var numSites = parseInt(readline());
|
||||
for (let i = 0; i < numSites; i++) {
|
||||
var inputs = readline().split(' ');
|
||||
var siteId = parseInt(inputs[0]);
|
||||
var x = parseInt(inputs[1]);
|
||||
var y = parseInt(inputs[2]);
|
||||
var radius = parseInt(inputs[3]);
|
||||
sites.push({
|
||||
id: siteId,
|
||||
x, y,
|
||||
radius,
|
||||
})
|
||||
}
|
||||
return {
|
||||
numSites,
|
||||
sites,
|
||||
}
|
||||
};
|
||||
|
||||
exports.parseInput = function(numSites) {
|
||||
return function() {
|
||||
var inputs = readline().split(' ');
|
||||
var gold = parseInt(inputs[0]);
|
||||
var touchedSite = parseInt(inputs[1]); // -1 if none
|
||||
var sites = []
|
||||
for (let i = 0; i < numSites; i++) {
|
||||
var inputs = readline().split(' ');
|
||||
var siteId = parseInt(inputs[0]);
|
||||
var ignore1 = parseInt(inputs[1]); // used in future leagues
|
||||
var ignore2 = parseInt(inputs[2]); // used in future leagues
|
||||
var structureType = parseInt(inputs[3]); // -1 = No structure, 2 = Barracks
|
||||
var owner = parseInt(inputs[4]); // -1 = No structure, 0 = Friendly, 1 = Enemy
|
||||
var param1 = parseInt(inputs[5]);
|
||||
var param2 = parseInt(inputs[6]);
|
||||
sites.push({
|
||||
id: siteId,
|
||||
structureType,
|
||||
owner,
|
||||
param1,
|
||||
param2,
|
||||
})
|
||||
}
|
||||
var numUnits = parseInt(readline());
|
||||
var units = []
|
||||
for (let i = 0; i < numUnits; i++) {
|
||||
var inputs = readline().split(' ');
|
||||
var x = parseInt(inputs[0]);
|
||||
var y = parseInt(inputs[1]);
|
||||
var owner = parseInt(inputs[2]);
|
||||
var unitType = parseInt(inputs[3]); // -1 = QUEEN, 0 = KNIGHT, 1 = ARCHER
|
||||
var health = parseInt(inputs[4]);
|
||||
units.push({
|
||||
x, y,
|
||||
owner,
|
||||
unitType,
|
||||
health
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
gold,
|
||||
touchedSite,
|
||||
sites,
|
||||
units,
|
||||
}
|
||||
}
|
||||
};
|
||||
44
code_royal/src/ffi/GameInput.purs
Normal file
44
code_royal/src/ffi/GameInput.purs
Normal file
@@ -0,0 +1,44 @@
|
||||
module GameInput where
|
||||
|
||||
import Effect (Effect)
|
||||
|
||||
type GameInitInput =
|
||||
{ numSites :: Int
|
||||
, sites :: Array SiteInfo
|
||||
}
|
||||
|
||||
type GameInput =
|
||||
{ gold :: Int
|
||||
, touchedSite :: Int -- -1 if none
|
||||
, sites :: Array Site
|
||||
, units :: Array Minion
|
||||
}
|
||||
|
||||
type SiteInfo =
|
||||
{ id :: Int
|
||||
, x :: Int
|
||||
, y :: Int
|
||||
, radius :: Int
|
||||
}
|
||||
|
||||
type Site =
|
||||
{ id :: Int
|
||||
, structureType :: Int -- -1 No structure, 2 Barracks
|
||||
, owner :: Int -- -1 No structure, 0 friendly, 1 enemy
|
||||
, param1 :: Int -- -1 No structure, else turns till training
|
||||
, param2 :: Int -- -1 No structure, barracks: 0 knight 1 archer
|
||||
}
|
||||
|
||||
type Minion =
|
||||
{ x :: Int
|
||||
, y :: Int
|
||||
, owner :: Int -- 0 = Friendly; 1 = Enemy
|
||||
, unitType :: Int -- -1 = QUEEN, 0 = KNIGHT, 1 = ARCHER
|
||||
, health :: Int
|
||||
}
|
||||
|
||||
foreign import parseInitInput :: Effect GameInitInput
|
||||
|
||||
foreign import parseInput :: Int -> Effect GameInput
|
||||
|
||||
foreign import readline :: Effect String
|
||||
Reference in New Issue
Block a user