- full ruleset
This commit is contained in:
weiss
2020-04-10 10:11:45 +02:00
parent 3e8a95a6b1
commit 149e4173d0
4 changed files with 91 additions and 47 deletions

View File

@@ -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" ]
} }

View File

@@ -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

View File

@@ -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,

View File

@@ -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