- 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.
-}
{ name = "code_royal"
, dependencies = [ "arrays", "console", "effect", "integers", "math", "random" ]
, dependencies =
[ "arrays", "console", "effect", "integers", "js-date", "math", "random" ]
, packages = ./packages.dhall
, sources = [ "src/**/*.purs", "test/**/*.purs" ]
}

View File

@@ -3,10 +3,11 @@ module Main where
import Prelude
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 Effect (Effect)
import Effect.Console (log, error)
import Effect.Console (error, log)
import Effect.Random (randomInt)
import GameInput (Minion, Site, SiteInfo, ProtoSite, parseInitInput, parseInput)
import Lib (dist)
@@ -16,18 +17,26 @@ main :: Effect Unit
main = do
initInput <- parseInitInput
error $ show initInput
loop initInput.numSites initInput.sites
loop initInput.numSites initInput.sites Nothing
loop :: Int -> Array SiteInfo -> Effect Unit
loop numSites siteInfo = do
loop :: Int -> Array SiteInfo -> Maybe Boolean -> Effect Unit
loop numSites siteInfo leftSide = do
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
then Nothing
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
-- queenPos :: Array Minion -> { x :: Int, y :: Int }
-- queenPos minions = queen minions
-- combine sites with siteInfo
combinedSites :: Array ProtoSite -> Array Site
combinedSites sites = do
@@ -35,6 +44,8 @@ loop numSites siteInfo = do
infoS <- siteInfo
guard $ protoS.id == infoS.id
pure { id: protoS.id
, gold: protoS.gold
, maxMineSize: protoS.maxMineSize
, structureType: protoS.structureType
, owner: protoS.owner
, param1: protoS.param1
@@ -44,25 +55,46 @@ loop numSites siteInfo = do
, radius: infoS.radius
}
loop' :: Int -> Int -> Maybe Int -> Array Site -> Array Minion -> Effect Unit
loop' numSites gold touchedSite sites units = do
-- error $ "Free sites: " <> (show $ map (\s -> s.id) freeSites)
-- error $ "Near sites: " <> (show $ map (\s -> s.id) nearSites)
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
loop' :: Int -> Int -> Maybe Int -> Array Site -> Array Minion -> Boolean -> Effect Unit
loop' numSites gold touchedSite sites units leftSide = do
n <- now
let t0 = getTime n
log buildAll
t <- trainAll gold sites
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
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 = case nearestEnemy of
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 $
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
nearestEnemy :: Maybe Minion
nearestEnemy = head $ filter (\u -> u.unitType /= -1 && isEnemy u) units
@@ -85,13 +111,18 @@ trainAll :: Int -> Array Site -> Effect String
trainAll gold sites = do
randBarrack <- randomBarrack
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
where
siteToIds acc site = acc <> " " <> show site.id
knightBarrack = case head $ knightBarracks sites of
Just barrack -> [barrack]
Nothing -> []
archerBarrack = case head $ archerBarracks sites of
Just barrack -> [barrack]
Nothing -> []
randomBarrack = do
let ownBarracks = filter isOwn $ barracks sites
rand <- randomInt 0 $ length ownBarracks
@@ -99,14 +130,26 @@ trainAll gold sites = do
Just barrack -> pure [barrack]
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 = filter (\s -> s.owner == -1)
friendlySites :: Array Site -> Array Site
friendlySites = filter (\s -> s.owner == 0)
nearSites :: Minion -> Array Site -> Array Site
nearSites unit sites = sortBy (compareSiteInfoDist unit) (freeSites sites)
friendlyMines :: Array Site -> Array Site
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 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 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 s = { id: s.id, x: s.x, y: s.y, radius: s.radius }
compareSiteInfoDist :: Minion -> Site -> Site -> Ordering
compareSiteInfoDist u s1 s2 = compare (dist s1 u) (dist s2 u)
compareSiteDist :: forall x. { x :: Int, y :: Int | x } -> Site -> Site -> Ordering
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 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 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++) {
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 mineGold = parseInt(inputs[1]); // The total number of gold remaining to be mined from this site (-1 if unknown)
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 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,
gold: mineGold,
maxMineSize,
structureType,
owner,
param1,

View File

@@ -23,7 +23,9 @@ type SiteInfo =
type ProtoSite =
{ 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
, param1 :: Int -- -1 No structure, else turns till training
, param2 :: Int -- -1 No structure, barracks: 0 knight 1 archer
@@ -34,6 +36,8 @@ type Site =
, x :: Int
, y :: Int
, radius :: Int
, gold :: Int
, maxMineSize :: Int
, structureType :: Int
, owner :: Int
, param1 :: Int