- timer
- full ruleset
This commit is contained in:
@@ -3,7 +3,8 @@ Welcome to a Spago project!
|
|||||||
You can edit this file as you like.
|
You can edit this file as you like.
|
||||||
-}
|
-}
|
||||||
{ name = "code_royal"
|
{ name = "code_royal"
|
||||||
, dependencies = [ "arrays", "console", "effect", "integers", "math", "random" ]
|
, dependencies =
|
||||||
|
[ "arrays", "console", "effect", "integers", "js-date", "math", "random" ]
|
||||||
, packages = ./packages.dhall
|
, packages = ./packages.dhall
|
||||||
, sources = [ "src/**/*.purs", "test/**/*.purs" ]
|
, sources = [ "src/**/*.purs", "test/**/*.purs" ]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,11 @@ module Main where
|
|||||||
import Prelude
|
import Prelude
|
||||||
|
|
||||||
import Control.MonadZero (guard)
|
import Control.MonadZero (guard)
|
||||||
import Data.Array (any, filter, foldl, head, length, reverse, sortBy, (!!))
|
import Data.Array (any, filter, foldl, head, length, sortBy, (!!))
|
||||||
|
import Data.JSDate (now, getTime)
|
||||||
import Data.Maybe (Maybe(..), fromJust)
|
import Data.Maybe (Maybe(..), fromJust)
|
||||||
import Effect (Effect)
|
import Effect (Effect)
|
||||||
import Effect.Console (log, error)
|
import Effect.Console (error, log)
|
||||||
import Effect.Random (randomInt)
|
import Effect.Random (randomInt)
|
||||||
import GameInput (Minion, Site, SiteInfo, ProtoSite, parseInitInput, parseInput)
|
import GameInput (Minion, Site, SiteInfo, ProtoSite, parseInitInput, parseInput)
|
||||||
import Lib (dist)
|
import Lib (dist)
|
||||||
@@ -16,18 +17,26 @@ main :: Effect Unit
|
|||||||
main = do
|
main = do
|
||||||
initInput <- parseInitInput
|
initInput <- parseInitInput
|
||||||
error $ show initInput
|
error $ show initInput
|
||||||
loop initInput.numSites initInput.sites
|
loop initInput.numSites initInput.sites Nothing
|
||||||
|
|
||||||
loop :: Int -> Array SiteInfo -> Effect Unit
|
loop :: Int -> Array SiteInfo -> Maybe Boolean -> Effect Unit
|
||||||
loop numSites siteInfo = do
|
loop numSites siteInfo leftSide = do
|
||||||
input <- parseInput numSites
|
input <- parseInput numSites
|
||||||
|
|
||||||
|
-- do we start on the left side of the map?
|
||||||
|
let leftSide' = case leftSide of
|
||||||
|
Just ls -> ls
|
||||||
|
Nothing -> (queen input.units).x < 500
|
||||||
|
|
||||||
let touchedSite = if input.touchedSite == -1
|
let touchedSite = if input.touchedSite == -1
|
||||||
then Nothing
|
then Nothing
|
||||||
else Just input.touchedSite
|
else Just input.touchedSite
|
||||||
|
|
||||||
loop' numSites input.gold touchedSite (combinedSites input.sites) input.units
|
loop' numSites input.gold touchedSite (combinedSites input.sites) input.units leftSide'
|
||||||
where
|
where
|
||||||
|
-- queenPos :: Array Minion -> { x :: Int, y :: Int }
|
||||||
|
-- queenPos minions = queen minions
|
||||||
|
|
||||||
-- combine sites with siteInfo
|
-- combine sites with siteInfo
|
||||||
combinedSites :: Array ProtoSite -> Array Site
|
combinedSites :: Array ProtoSite -> Array Site
|
||||||
combinedSites sites = do
|
combinedSites sites = do
|
||||||
@@ -35,6 +44,8 @@ loop numSites siteInfo = do
|
|||||||
infoS <- siteInfo
|
infoS <- siteInfo
|
||||||
guard $ protoS.id == infoS.id
|
guard $ protoS.id == infoS.id
|
||||||
pure { id: protoS.id
|
pure { id: protoS.id
|
||||||
|
, gold: protoS.gold
|
||||||
|
, maxMineSize: protoS.maxMineSize
|
||||||
, structureType: protoS.structureType
|
, structureType: protoS.structureType
|
||||||
, owner: protoS.owner
|
, owner: protoS.owner
|
||||||
, param1: protoS.param1
|
, param1: protoS.param1
|
||||||
@@ -44,25 +55,46 @@ loop numSites siteInfo = do
|
|||||||
, radius: infoS.radius
|
, radius: infoS.radius
|
||||||
}
|
}
|
||||||
|
|
||||||
loop' :: Int -> Int -> Maybe Int -> Array Site -> Array Minion -> Effect Unit
|
loop' :: Int -> Int -> Maybe Int -> Array Site -> Array Minion -> Boolean -> Effect Unit
|
||||||
loop' numSites gold touchedSite sites units = do
|
loop' numSites gold touchedSite sites units leftSide = do
|
||||||
-- error $ "Free sites: " <> (show $ map (\s -> s.id) freeSites)
|
n <- now
|
||||||
-- error $ "Near sites: " <> (show $ map (\s -> s.id) nearSites)
|
let t0 = getTime n
|
||||||
|
|
||||||
if (length $ friendlySites sites) > 3
|
|
||||||
then log avoid
|
|
||||||
else case head $ nearSites queen sites of
|
|
||||||
Just sInfo -> do
|
|
||||||
let typ = if hasKnightsBarrack sites then 1 else 0
|
|
||||||
log $ build sInfo typ
|
|
||||||
Nothing -> do
|
|
||||||
log avoid
|
|
||||||
|
|
||||||
|
log buildAll
|
||||||
t <- trainAll gold sites
|
t <- trainAll gold sites
|
||||||
log $ t
|
log $ t
|
||||||
|
|
||||||
loop numSites (toSiteInfo <$> sites)
|
n' <- now
|
||||||
|
let t1 = getTime n
|
||||||
|
-- error $ show t0 <> "Execution time: " <> (show $ t1 - t0)
|
||||||
|
loop numSites (toSiteInfo <$> sites) (Just leftSide)
|
||||||
where
|
where
|
||||||
|
buildAll :: String
|
||||||
|
buildAll =
|
||||||
|
if (length $ friendlySites sites) == 0
|
||||||
|
then buildTowers
|
||||||
|
else if (length $ friendlyMines sites) < 3
|
||||||
|
then buildMines
|
||||||
|
else if (length $ friendlySites sites) > 5 && (length $ friendlySites sites) < 11
|
||||||
|
then buildTowers
|
||||||
|
else if (length $ friendlySites sites) <= 5
|
||||||
|
then case head $ nearSites (queen units) sites of
|
||||||
|
Just site -> do
|
||||||
|
let typ = if hasKnightsBarrack sites then 1 else 0
|
||||||
|
build site typ
|
||||||
|
Nothing -> avoid
|
||||||
|
else avoid
|
||||||
|
|
||||||
|
buildTowers :: String
|
||||||
|
buildTowers = case head $ nearSites (corner leftSide) sites of
|
||||||
|
Just site -> "BUILD " <> show site.id <> " TOWER"
|
||||||
|
Nothing -> avoid
|
||||||
|
|
||||||
|
buildMines :: String
|
||||||
|
buildMines = case head $ nearNonEmptyMines (queen units) sites of
|
||||||
|
Just site -> "BUILD " <> show site.id <> " MINE"
|
||||||
|
Nothing -> avoid
|
||||||
|
|
||||||
avoid :: String
|
avoid :: String
|
||||||
avoid = case nearestEnemy of
|
avoid = case nearestEnemy of
|
||||||
Just enemy -> "MOVE " <> show (site enemy).x <> " " <> show (site enemy).y
|
Just enemy -> "MOVE " <> show (site enemy).x <> " " <> show (site enemy).y
|
||||||
@@ -70,12 +102,6 @@ loop' numSites gold touchedSite sites units = do
|
|||||||
where site enemy = unsafePartial $ fromJust $ head $
|
where site enemy = unsafePartial $ fromJust $ head $
|
||||||
sortBy (\s1 s2 -> compare (dist enemy s2) (dist enemy s1)) (friendlySites sites)
|
sortBy (\s1 s2 -> compare (dist enemy s2) (dist enemy s1)) (friendlySites sites)
|
||||||
|
|
||||||
queen :: Minion
|
|
||||||
queen = unsafePartial $ fromJust $ head $ filter (\u -> u.unitType == -1 && u.owner == 0) units
|
|
||||||
|
|
||||||
enemyQueen :: Minion
|
|
||||||
enemyQueen = unsafePartial $ fromJust $ head $ filter (\u -> u.unitType == -1 && u.owner == 1) units
|
|
||||||
|
|
||||||
-- nearest non-queen enemy
|
-- nearest non-queen enemy
|
||||||
nearestEnemy :: Maybe Minion
|
nearestEnemy :: Maybe Minion
|
||||||
nearestEnemy = head $ filter (\u -> u.unitType /= -1 && isEnemy u) units
|
nearestEnemy = head $ filter (\u -> u.unitType /= -1 && isEnemy u) units
|
||||||
@@ -85,13 +111,18 @@ trainAll :: Int -> Array Site -> Effect String
|
|||||||
trainAll gold sites = do
|
trainAll gold sites = do
|
||||||
randBarrack <- randomBarrack
|
randBarrack <- randomBarrack
|
||||||
choose <- randomInt 1 100
|
choose <- randomInt 1 100
|
||||||
let barrack = if gold > 100 && choose < 23 then knightBarrack else randBarrack
|
let barrack = if gold > 140
|
||||||
|
then if choose < 42 then knightBarrack else archerBarrack
|
||||||
|
else []
|
||||||
pure $ foldl siteToIds "TRAIN" barrack
|
pure $ foldl siteToIds "TRAIN" barrack
|
||||||
where
|
where
|
||||||
siteToIds acc site = acc <> " " <> show site.id
|
siteToIds acc site = acc <> " " <> show site.id
|
||||||
knightBarrack = case head $ knightBarracks sites of
|
knightBarrack = case head $ knightBarracks sites of
|
||||||
Just barrack -> [barrack]
|
Just barrack -> [barrack]
|
||||||
Nothing -> []
|
Nothing -> []
|
||||||
|
archerBarrack = case head $ archerBarracks sites of
|
||||||
|
Just barrack -> [barrack]
|
||||||
|
Nothing -> []
|
||||||
randomBarrack = do
|
randomBarrack = do
|
||||||
let ownBarracks = filter isOwn $ barracks sites
|
let ownBarracks = filter isOwn $ barracks sites
|
||||||
rand <- randomInt 0 $ length ownBarracks
|
rand <- randomInt 0 $ length ownBarracks
|
||||||
@@ -99,14 +130,26 @@ trainAll gold sites = do
|
|||||||
Just barrack -> pure [barrack]
|
Just barrack -> pure [barrack]
|
||||||
Nothing -> pure []
|
Nothing -> pure []
|
||||||
|
|
||||||
|
queen :: Array Minion -> Minion
|
||||||
|
queen units = unsafePartial $ fromJust $ head $ filter (\u -> u.unitType == -1 && u.owner == 0) units
|
||||||
|
|
||||||
|
enemyQueen :: Array Minion -> Minion
|
||||||
|
enemyQueen units = unsafePartial $ fromJust $ head $ filter (\u -> u.unitType == -1 && u.owner == 1) units
|
||||||
|
|
||||||
freeSites :: Array Site -> Array Site
|
freeSites :: Array Site -> Array Site
|
||||||
freeSites = filter (\s -> s.owner == -1)
|
freeSites = filter (\s -> s.owner == -1)
|
||||||
|
|
||||||
friendlySites :: Array Site -> Array Site
|
friendlySites :: Array Site -> Array Site
|
||||||
friendlySites = filter (\s -> s.owner == 0)
|
friendlySites = filter (\s -> s.owner == 0)
|
||||||
|
|
||||||
nearSites :: Minion -> Array Site -> Array Site
|
friendlyMines :: Array Site -> Array Site
|
||||||
nearSites unit sites = sortBy (compareSiteInfoDist unit) (freeSites sites)
|
friendlyMines sites = filter (\s -> s.structureType == 0) $ friendlySites sites
|
||||||
|
|
||||||
|
nearSites :: forall x. { x :: Int, y :: Int | x } -> Array Site -> Array Site
|
||||||
|
nearSites unit sites = sortBy (compareSiteDist unit) (freeSites sites)
|
||||||
|
|
||||||
|
nearNonEmptyMines :: forall x. { x :: Int, y :: Int | x } -> Array Site -> Array Site
|
||||||
|
nearNonEmptyMines unit sites = filter (\s -> s.gold > 0) $ nearSites unit sites
|
||||||
|
|
||||||
hasKnightsBarrack :: Array Site -> Boolean
|
hasKnightsBarrack :: Array Site -> Boolean
|
||||||
hasKnightsBarrack sites = any (\s -> s.param2 == 0) (friendlySites sites)
|
hasKnightsBarrack sites = any (\s -> s.param2 == 0) (friendlySites sites)
|
||||||
@@ -114,11 +157,17 @@ hasKnightsBarrack sites = any (\s -> s.param2 == 0) (friendlySites sites)
|
|||||||
knightBarracks :: Array Site -> Array Site
|
knightBarracks :: Array Site -> Array Site
|
||||||
knightBarracks sites = filter (\s -> s.param2 == 0) (friendlySites sites)
|
knightBarracks sites = filter (\s -> s.param2 == 0) (friendlySites sites)
|
||||||
|
|
||||||
|
archerBarracks :: Array Site -> Array Site
|
||||||
|
archerBarracks sites = filter (\s -> s.param2 == 1) (friendlySites sites)
|
||||||
|
|
||||||
toSiteInfo :: Site -> SiteInfo
|
toSiteInfo :: Site -> SiteInfo
|
||||||
toSiteInfo s = { id: s.id, x: s.x, y: s.y, radius: s.radius }
|
toSiteInfo s = { id: s.id, x: s.x, y: s.y, radius: s.radius }
|
||||||
|
|
||||||
compareSiteInfoDist :: Minion -> Site -> Site -> Ordering
|
compareSiteDist :: forall x. { x :: Int, y :: Int | x } -> Site -> Site -> Ordering
|
||||||
compareSiteInfoDist u s1 s2 = compare (dist s1 u) (dist s2 u)
|
compareSiteDist u s1 s2 = compare (dist s1 u) (dist s2 u)
|
||||||
|
|
||||||
|
corner :: Boolean -> { x :: Int, y :: Int }
|
||||||
|
corner leftSide = if leftSide then { x: 0, y: 0 } else { x: 1920, y: 1000 }
|
||||||
|
|
||||||
build :: forall e. { id :: Int | e } -> Int -> String
|
build :: forall e. { id :: Int | e } -> Int -> String
|
||||||
build s typ = "BUILD " <> show s.id <> " BARRACKS-" <> t
|
build s typ = "BUILD " <> show s.id <> " BARRACKS-" <> t
|
||||||
@@ -138,15 +187,3 @@ barracks sites = filter (\b -> b.structureType == 2) sites
|
|||||||
|
|
||||||
moveToPos :: forall e. { x :: Int, y :: Int | e } -> String
|
moveToPos :: forall e. { x :: Int, y :: Int | e } -> String
|
||||||
moveToPos p = "MOVE " <> show p.x <> " " <> show p.y
|
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
|
|
||||||
@@ -32,14 +32,16 @@ exports.parseInput = function(numSites) {
|
|||||||
for (let i = 0; i < numSites; i++) {
|
for (let i = 0; i < numSites; i++) {
|
||||||
var inputs = readline().split(' ');
|
var inputs = readline().split(' ');
|
||||||
var siteId = parseInt(inputs[0]);
|
var siteId = parseInt(inputs[0]);
|
||||||
var ignore1 = parseInt(inputs[1]); // used in future leagues
|
var mineGold = parseInt(inputs[1]); // The total number of gold remaining to be mined from this site (-1 if unknown)
|
||||||
var ignore2 = parseInt(inputs[2]); // used in future leagues
|
var maxMineSize = parseInt(inputs[2]); // The maximum rate that a mine can extract gold from this site (-1 if unknown)
|
||||||
var structureType = parseInt(inputs[3]); // -1 = No structure, 2 = Barracks
|
var structureType = parseInt(inputs[3]); // -1 = No structure, 2 = Barracks
|
||||||
var owner = parseInt(inputs[4]); // -1 = No structure, 0 = Friendly, 1 = Enemy
|
var owner = parseInt(inputs[4]); // -1 = No structure, 0 = Friendly, 1 = Enemy
|
||||||
var param1 = parseInt(inputs[5]);
|
var param1 = parseInt(inputs[5]);
|
||||||
var param2 = parseInt(inputs[6]);
|
var param2 = parseInt(inputs[6]);
|
||||||
sites.push({
|
sites.push({
|
||||||
id: siteId,
|
id: siteId,
|
||||||
|
gold: mineGold,
|
||||||
|
maxMineSize,
|
||||||
structureType,
|
structureType,
|
||||||
owner,
|
owner,
|
||||||
param1,
|
param1,
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ type SiteInfo =
|
|||||||
|
|
||||||
type ProtoSite =
|
type ProtoSite =
|
||||||
{ id :: Int
|
{ id :: Int
|
||||||
, structureType :: Int -- -1 No structure, 2 Barracks
|
, gold :: Int -- The total number of gold remaining to be mined from this site (-1 if unknown)
|
||||||
|
, maxMineSize :: Int -- The maximum rate that a mine can extract gold from this site (-1 if unknown)
|
||||||
|
, structureType :: Int -- -1 No structure, 0 Goldmine, 1 Tower, 2 Barracks
|
||||||
, owner :: Int -- -1 No structure, 0 friendly, 1 enemy
|
, owner :: Int -- -1 No structure, 0 friendly, 1 enemy
|
||||||
, param1 :: Int -- -1 No structure, else turns till training
|
, param1 :: Int -- -1 No structure, else turns till training
|
||||||
, param2 :: Int -- -1 No structure, barracks: 0 knight 1 archer
|
, param2 :: Int -- -1 No structure, barracks: 0 knight 1 archer
|
||||||
@@ -34,6 +36,8 @@ type Site =
|
|||||||
, x :: Int
|
, x :: Int
|
||||||
, y :: Int
|
, y :: Int
|
||||||
, radius :: Int
|
, radius :: Int
|
||||||
|
, gold :: Int
|
||||||
|
, maxMineSize :: Int
|
||||||
, structureType :: Int
|
, structureType :: Int
|
||||||
, owner :: Int
|
, owner :: Int
|
||||||
, param1 :: Int
|
, param1 :: Int
|
||||||
|
|||||||
Reference in New Issue
Block a user