build giants
This commit is contained in:
@@ -1,11 +1,13 @@
|
|||||||
module Main where
|
module Main where
|
||||||
|
|
||||||
|
-- mines only on side
|
||||||
|
-- build giants
|
||||||
|
|
||||||
import Prelude
|
import Prelude
|
||||||
|
|
||||||
import Control.Monad.State (State, gets, runState)
|
import Control.Monad.State (State, gets, modify_, runState)
|
||||||
import Control.MonadZero (guard)
|
import Control.MonadZero (guard)
|
||||||
import Data.Array (any, filter, foldl, head, length, 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 Data.Tuple (fst, snd)
|
import Data.Tuple (fst, snd)
|
||||||
import Effect (Effect)
|
import Effect (Effect)
|
||||||
@@ -17,7 +19,7 @@ import Partial.Unsafe (unsafePartial)
|
|||||||
type GameState =
|
type GameState =
|
||||||
{ gold :: Int
|
{ gold :: Int
|
||||||
, numSites :: Int
|
, numSites :: Int
|
||||||
, touchedSite :: Maybe Int
|
, touchedSite :: Int
|
||||||
, sites :: Array Site
|
, sites :: Array Site
|
||||||
, units :: Array Minion
|
, units :: Array Minion
|
||||||
, leftSide :: Boolean
|
, leftSide :: Boolean
|
||||||
@@ -29,44 +31,43 @@ main = do
|
|||||||
error $ show initInput
|
error $ show initInput
|
||||||
loop initInput.numSites initInput.sites Nothing
|
loop initInput.numSites initInput.sites Nothing
|
||||||
|
|
||||||
loop :: Int -> Array SiteInfo -> Maybe Boolean -> Effect Unit
|
loop :: Int -> Array SiteInfo -> Maybe GameState -> Effect Unit
|
||||||
loop numSites siteInfo leftSide = do
|
loop numSites siteInfo gameState = do
|
||||||
input <- parseInput numSites
|
input <- parseInput numSites
|
||||||
|
|
||||||
-- do we start on the left side of the map?
|
-- do we start on the left side of the map?
|
||||||
let leftSide' = case leftSide of
|
let leftSide' = case gameState of
|
||||||
Just ls -> ls
|
Just gs -> gs.leftSide
|
||||||
Nothing -> (queen input.units).x < 500
|
Nothing -> (queen input.units).x < 500
|
||||||
|
|
||||||
let touchedSite = if input.touchedSite == -1
|
let gameState' =
|
||||||
then Nothing
|
|
||||||
else Just input.touchedSite
|
|
||||||
|
|
||||||
let gameState =
|
|
||||||
{ gold: input.gold
|
{ gold: input.gold
|
||||||
, numSites
|
, numSites
|
||||||
, touchedSite
|
, touchedSite: input.touchedSite
|
||||||
, sites: combinedSites input.sites
|
, sites: combinedSites input.sites
|
||||||
, units: input.units
|
, units: input.units
|
||||||
, leftSide: leftSide'
|
, leftSide: leftSide'
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = runState loop' gameState
|
let res = runState loop' gameState'
|
||||||
let state = snd res
|
let state = snd res
|
||||||
let val = fst res
|
let val = fst res
|
||||||
log $ val
|
log $ val
|
||||||
loop state.numSites (toSiteInfo <$> state.sites) (Just state.leftSide)
|
loop state.numSites (toSiteInfo <$> state.sites) (Just state)
|
||||||
|
|
||||||
where
|
where
|
||||||
-- queenPos :: Array Minion -> { x :: Int, y :: Int }
|
-- combine sites with siteInfo and old state
|
||||||
-- queenPos minions = queen minions
|
|
||||||
|
|
||||||
-- combine sites with siteInfo
|
|
||||||
combinedSites :: Array ProtoSite -> Array Site
|
combinedSites :: Array ProtoSite -> Array Site
|
||||||
combinedSites sites = do
|
combinedSites sites = do
|
||||||
protoS <- sites
|
protoS <- sites
|
||||||
infoS <- siteInfo
|
infoS <- siteInfo
|
||||||
guard $ protoS.id == infoS.id
|
guard $ protoS.id == infoS.id
|
||||||
|
let prevSite = case gameState of
|
||||||
|
Just gs -> head $ filter (\s -> s.id == infoS.id) gs.sites
|
||||||
|
Nothing -> Nothing
|
||||||
|
let mineLvl = case prevSite of
|
||||||
|
Just site -> site.mineLvl
|
||||||
|
Nothing -> 0
|
||||||
pure { id: protoS.id
|
pure { id: protoS.id
|
||||||
, gold: protoS.gold
|
, gold: protoS.gold
|
||||||
, maxMineSize: protoS.maxMineSize
|
, maxMineSize: protoS.maxMineSize
|
||||||
@@ -77,7 +78,7 @@ loop numSites siteInfo leftSide = do
|
|||||||
, x: infoS.x
|
, x: infoS.x
|
||||||
, y: infoS.y
|
, y: infoS.y
|
||||||
, radius: infoS.radius
|
, radius: infoS.radius
|
||||||
, mineLvl: -1
|
, mineLvl
|
||||||
}
|
}
|
||||||
|
|
||||||
loop' :: State GameState String
|
loop' :: State GameState String
|
||||||
@@ -90,18 +91,20 @@ buildAll :: State GameState String
|
|||||||
buildAll = do
|
buildAll = do
|
||||||
sites <- gets _.sites
|
sites <- gets _.sites
|
||||||
units <- gets _.units
|
units <- gets _.units
|
||||||
if (length $ friendlySites sites) == 0
|
let buildingsCnt = length $ friendlySites sites
|
||||||
then buildTowers
|
let minesCnt = length $ friendlyMines sites
|
||||||
else if (length $ friendlyMines sites) < 3
|
if minesCnt < 3
|
||||||
then buildMines
|
then buildMines
|
||||||
else if (length $ friendlySites sites) > 5 && (length $ friendlySites sites) < 11
|
else if buildingsCnt < 6
|
||||||
then buildTowers
|
|
||||||
else if (length $ friendlySites sites) <= 5
|
|
||||||
then case head $ nearFreeSites (queen units) sites of
|
then case head $ nearFreeSites (queen units) sites of
|
||||||
Just site -> do
|
Just site -> do
|
||||||
let typ = if hasKnightsBarrack sites then 1 else 0
|
let typ = if not $ hasArcherBarrack sites then 1
|
||||||
|
else if not $ hasKnightsBarrack sites then 0
|
||||||
|
else 2
|
||||||
pure $ build site typ
|
pure $ build site typ
|
||||||
Nothing -> avoid
|
Nothing -> avoid
|
||||||
|
else if buildingsCnt < 9
|
||||||
|
then buildTowers
|
||||||
else avoid
|
else avoid
|
||||||
|
|
||||||
buildTowers :: State GameState String
|
buildTowers :: State GameState String
|
||||||
@@ -117,9 +120,18 @@ buildMines = do
|
|||||||
units <- gets _.units
|
units <- gets _.units
|
||||||
sites <- gets _.sites
|
sites <- gets _.sites
|
||||||
case head $ nearNonEmptyMines (queen units) sites of
|
case head $ nearNonEmptyMines (queen units) sites of
|
||||||
Just site ->
|
Just site -> do
|
||||||
|
touched <- gets _.touchedSite
|
||||||
|
if touched == -1 || touched /= site.id
|
||||||
|
then pure unit
|
||||||
|
else modify_ (\s -> s { sites = map (incMineLvl site.id) s.sites })
|
||||||
pure $ "BUILD " <> show site.id <> " MINE"
|
pure $ "BUILD " <> show site.id <> " MINE"
|
||||||
Nothing -> avoid
|
Nothing -> avoid
|
||||||
|
where
|
||||||
|
incMineLvl :: Int -> Site -> Site
|
||||||
|
incMineLvl sId site
|
||||||
|
| sId == site.id = site { mineLvl = site.mineLvl + 1 }
|
||||||
|
| otherwise = site
|
||||||
|
|
||||||
avoid :: State GameState String
|
avoid :: State GameState String
|
||||||
avoid = do
|
avoid = do
|
||||||
@@ -129,24 +141,30 @@ avoid = do
|
|||||||
Just enemy -> do
|
Just enemy -> do
|
||||||
let site = unsafePartial $ fromJust $ head $
|
let site = 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)
|
||||||
pure $ "MOVE " <> show site.x <> " " <> show site.y
|
pure $ moveToPos site
|
||||||
Nothing -> pure $ "MOVE 0 0"
|
Nothing -> pure $ "MOVE 0 0"
|
||||||
|
|
||||||
-- nearest non-queen enemy
|
-- nearest non-queen enemy
|
||||||
nearestEnemy :: State GameState (Maybe Minion)
|
nearestEnemy :: State GameState (Maybe Minion)
|
||||||
nearestEnemy = do
|
nearestEnemy = do
|
||||||
units <- gets _.units
|
units <- gets _.units
|
||||||
pure $ head $ filter (\u -> u.unitType /= -1 && isEnemy u) units
|
pure $ head $ filter (\u -> isEnemy u) units
|
||||||
|
|
||||||
trainAll :: State GameState String
|
trainAll :: State GameState String
|
||||||
trainAll = do
|
trainAll = do
|
||||||
gold <- gets _.gold
|
gold <- gets _.gold
|
||||||
sites <- gets _.sites
|
sites <- gets _.sites
|
||||||
|
units <- gets _.units
|
||||||
|
|
||||||
-- choose <- randomInt 1 100
|
let ownArchers = ownMinions units
|
||||||
let choose = -1 -- TODO!!!
|
let barrack =if gold > 140
|
||||||
let barrack = if gold > 140
|
then
|
||||||
then if choose < 42 then knightBarrack sites else archerBarrack sites
|
if length ownArchers < 4 && length (enemyKnights units) /= 0
|
||||||
|
then archerBarrack sites
|
||||||
|
else if length (enemyTowers sites) > 2
|
||||||
|
then giantBarrack sites
|
||||||
|
else
|
||||||
|
knightBarrack sites
|
||||||
else []
|
else []
|
||||||
pure $ foldl siteToIds "TRAIN" barrack
|
pure $ foldl siteToIds "TRAIN" barrack
|
||||||
where
|
where
|
||||||
@@ -157,6 +175,15 @@ trainAll = do
|
|||||||
archerBarrack sites = case head $ archerBarracks sites of
|
archerBarrack sites = case head $ archerBarracks sites of
|
||||||
Just barrack -> [barrack]
|
Just barrack -> [barrack]
|
||||||
Nothing -> []
|
Nothing -> []
|
||||||
|
giantBarrack sites = case head $ giantBarracks sites of
|
||||||
|
Just barrack -> [barrack]
|
||||||
|
Nothing -> []
|
||||||
|
|
||||||
|
build :: forall e. { id :: Int | e } -> Int -> String
|
||||||
|
build s typ = "BUILD " <> show s.id <> " BARRACKS-" <> t
|
||||||
|
where t | typ == 0 = "KNIGHT"
|
||||||
|
| typ == 1 = "ARCHER"
|
||||||
|
| otherwise = "GIANT"
|
||||||
|
|
||||||
queen :: Array Minion -> Minion
|
queen :: Array Minion -> Minion
|
||||||
queen units = unsafePartial $ fromJust $ head $ filter (\u -> u.unitType == -1 && u.owner == 0) units
|
queen units = unsafePartial $ fromJust $ head $ filter (\u -> u.unitType == -1 && u.owner == 0) units
|
||||||
@@ -164,6 +191,12 @@ queen units = unsafePartial $ fromJust $ head $ filter (\u -> u.unitType == -1 &
|
|||||||
enemyQueen :: Array Minion -> Minion
|
enemyQueen :: Array Minion -> Minion
|
||||||
enemyQueen units = unsafePartial $ fromJust $ head $ filter (\u -> u.unitType == -1 && u.owner == 1) units
|
enemyQueen units = unsafePartial $ fromJust $ head $ filter (\u -> u.unitType == -1 && u.owner == 1) units
|
||||||
|
|
||||||
|
ownMinions :: Array Minion -> Array Minion
|
||||||
|
ownMinions = filter isOwn
|
||||||
|
|
||||||
|
enemyKnights :: Array Minion -> Array Minion
|
||||||
|
enemyKnights = filter isEnemy <<< filter isKnight
|
||||||
|
|
||||||
freeSites :: Array Site -> Array Site
|
freeSites :: Array Site -> Array Site
|
||||||
freeSites = filter (\s -> s.owner == -1)
|
freeSites = filter (\s -> s.owner == -1)
|
||||||
|
|
||||||
@@ -173,24 +206,36 @@ friendlySites = filter (\s -> s.owner == 0)
|
|||||||
friendlyMines :: Array Site -> Array Site
|
friendlyMines :: Array Site -> Array Site
|
||||||
friendlyMines sites = filter (\s -> s.structureType == 0) $ friendlySites sites
|
friendlyMines sites = filter (\s -> s.structureType == 0) $ friendlySites sites
|
||||||
|
|
||||||
|
enemyTowers :: Array Site -> Array Site
|
||||||
|
enemyTowers = filter isEnemy <<< filter isTower
|
||||||
|
|
||||||
nearSites :: forall a. { x :: Int, y :: Int | a } -> Array Site -> Array Site
|
nearSites :: forall a. { x :: Int, y :: Int | a } -> Array Site -> Array Site
|
||||||
nearSites unit sites = sortBy (compareSiteDist unit) sites
|
nearSites minion sites = sortBy (compareSiteDist minion) sites
|
||||||
|
|
||||||
nearFreeSites :: forall a. { x :: Int, y :: Int | a } -> Array Site -> Array Site
|
nearFreeSites :: forall a. { x :: Int, y :: Int | a } -> Array Site -> Array Site
|
||||||
nearFreeSites unit sites = sortBy (compareSiteDist unit) (freeSites sites)
|
nearFreeSites minion sites = sortBy (compareSiteDist minion) (freeSites sites)
|
||||||
|
|
||||||
nearNonEmptyMines :: forall x. { x :: Int, y :: Int | x } -> Array Site -> Array Site
|
nearNonEmptyMines :: forall x. { x :: Int, y :: Int | x } -> Array Site -> Array Site
|
||||||
nearNonEmptyMines unit sites = filter (\s -> s.gold > 0 && s.mineLvl < 5 && s.owner /= 1) $ nearSites unit sites
|
nearNonEmptyMines minion sites = filter (\s -> s.gold > 20 && s.mineLvl < 5 && s.owner /= 1) $ nearSites minion 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)
|
||||||
|
|
||||||
|
hasArcherBarrack :: Array Site -> Boolean
|
||||||
|
hasArcherBarrack sites = any (\s -> s.param2 == 1) (friendlySites sites)
|
||||||
|
|
||||||
|
hasGiantsBarrack :: Array Site -> Boolean
|
||||||
|
hasGiantsBarrack sites = any (\s -> s.param2 == 2) (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 :: Array Site -> Array Site
|
||||||
archerBarracks sites = filter (\s -> s.param2 == 1) (friendlySites sites)
|
archerBarracks sites = filter (\s -> s.param2 == 1) (friendlySites sites)
|
||||||
|
|
||||||
|
giantBarracks :: Array Site -> Array Site
|
||||||
|
giantBarracks sites = filter (\s -> s.param2 == 2) (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 }
|
||||||
|
|
||||||
@@ -200,10 +245,6 @@ compareSiteDist u s1 s2 = compare (dist s1 u) (dist s2 u)
|
|||||||
corner :: Boolean -> { x :: Int, y :: Int }
|
corner :: Boolean -> { x :: Int, y :: Int }
|
||||||
corner leftSide = if leftSide then { x: 0, y: 0 } else { x: 1920, y: 1000 }
|
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
|
|
||||||
where t = if typ == 0 then "KNIGHT" else "ARCHER"
|
|
||||||
|
|
||||||
isOwn :: forall a. { owner :: Int | a } -> Boolean
|
isOwn :: forall a. { owner :: Int | a } -> Boolean
|
||||||
isOwn = owner 0
|
isOwn = owner 0
|
||||||
|
|
||||||
@@ -213,6 +254,18 @@ isEnemy = owner 1
|
|||||||
owner :: Int -> forall a. { owner :: Int | a } -> Boolean
|
owner :: Int -> forall a. { owner :: Int | a } -> Boolean
|
||||||
owner oId r = r.owner == oId
|
owner oId r = r.owner == oId
|
||||||
|
|
||||||
|
isKnight :: Minion -> Boolean
|
||||||
|
isKnight minion = minion.unitType == 0
|
||||||
|
|
||||||
|
isArcher :: Minion -> Boolean
|
||||||
|
isArcher minion = minion.unitType == 1
|
||||||
|
|
||||||
|
isGiant :: Minion -> Boolean
|
||||||
|
isGiant minion = minion.unitType == 2
|
||||||
|
|
||||||
|
isTower :: forall a. { structureType :: Int | a } -> Boolean
|
||||||
|
isTower s = s.structureType == 1
|
||||||
|
|
||||||
barracks :: Array Site -> Array Site
|
barracks :: Array Site -> Array Site
|
||||||
barracks sites = filter (\b -> b.structureType == 2) sites
|
barracks sites = filter (\b -> b.structureType == 2) sites
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ type Site =
|
|||||||
, structureType :: Int -- -1 No structure, 0 Goldmine, 1 Tower, 2 Barracks
|
, 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 2 giant
|
||||||
, mineLvl :: Int -- -1 whatever, otherwise curr. mine lvl
|
, mineLvl :: Int -- -1 whatever, otherwise curr. mine lvl
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ type Minion =
|
|||||||
{ x :: Int
|
{ x :: Int
|
||||||
, y :: Int
|
, y :: Int
|
||||||
, owner :: Int -- 0 = Friendly; 1 = Enemy
|
, owner :: Int -- 0 = Friendly; 1 = Enemy
|
||||||
, unitType :: Int -- -1 = QUEEN, 0 = KNIGHT, 1 = ARCHER
|
, unitType :: Int -- -1 = QUEEN, 0 = KNIGHT, 1 = ARCHER, 2 = GIANT
|
||||||
, health :: Int
|
, health :: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user