cosider enemies as threats

This commit is contained in:
weiss
2020-04-26 12:11:15 +02:00
parent f41d806029
commit d8b857749c
6 changed files with 51 additions and 31 deletions

View File

@@ -27,7 +27,7 @@ loop1 pos depth acc
in loop1 sim (depth - 1) acc' in loop1 sim (depth - 1) acc'
sim1 :: Pos -> (Int, Pos) sim1 :: Pos -> (Int, Pos)
sim1 pos = (\(val, (_,_, pos, _)) -> (val, pos)) (simulate board1 (0, 100, pos, singleton (0,4))) sim1 pos = (\(val, (_,_, pos, _,_)) -> (val, pos)) (simulate board1 (0, 100, pos, singleton (0,4), empty))
board1 :: Board board1 :: Board
board1 = fromList $ fmap fromList board1 = fromList $ fmap fromList

View File

@@ -32,6 +32,7 @@ dependencies:
- haskell-src-exts - haskell-src-exts
- vector - vector
- mtl - mtl
- time
library: library:
source-dirs: src source-dirs: src

View File

@@ -10,6 +10,7 @@ import System.Random
import Data.Char (digitToInt) import Data.Char (digitToInt)
import Data.List as L import Data.List as L
import qualified Data.Vector as V import qualified Data.Vector as V
import Data.Time.Clock.POSIX
import BotRunner import BotRunner
import Graph import Graph
@@ -49,6 +50,7 @@ bot readLine writeLine = do
-- game loop -- game loop
forever $ do forever $ do
t1 <- getPOSIXTime
input_line <- getLine input_line <- getLine
let entitycount = read input_line :: Int -- the number of entities let entitycount = read input_line :: Int -- the number of entities
@@ -71,6 +73,9 @@ bot readLine writeLine = do
let hero = V.head $ V.filter (\e -> case e of let hero = V.head $ V.filter (\e -> case e of
EHero id _ _ _ -> id == myId EHero id _ _ _ -> id == myId
_ -> False) heroes _ -> False) heroes
let enemies = V.filter (\e -> case e of
EHero id _ _ _ -> id /= myId
_ -> False) heroes
let mines = V.filter (\e -> case e of let mines = V.filter (\e -> case e of
EMine oId _ -> oId /= myId EMine oId _ -> oId /= myId
_ -> False) entities _ -> False) entities
@@ -81,23 +86,26 @@ bot readLine writeLine = do
EMine oId _ -> oId == myId EMine oId _ -> oId == myId
_ -> False) entities _ -> False) entities
let gs = gameState hero $ fmap posFromEntity myMines let gs = gameState hero (fmap posFromEntity myMines) (fmap posFromEntity enemies)
let oldMines = length $ getMines gs let oldMines = length $ getMines gs
let sim = simulate board gs let sim = simulate board gs
let newMines = length $ getMines $ snd sim let newMines = length $ getMines $ snd sim
let cmd = if newMines - oldMines > 0 let cmd = (\(_,(_,_,pos,_,_)) -> moveToPos pos) sim
then (\(_,(_,_,pos,_)) -> moveToPos pos) sim
else case life hero of
Just lp -> if lp < 30 then moveToPos minTavernPos else moveToEntity minEMine
Nothing -> moveToEntity minEMine
-- hPrint stderr $ newMines - oldMines -- let cmd = if newMines - oldMines > 0
-- hPrint stderr minEMine -- then (\(_,(_,_,pos,_,_)) -> moveToPos pos) sim
-- else case life hero of
-- Just lp -> if lp < 30 then moveToPos minTavernPos else moveToEntity minEMine
-- Nothing -> moveToEntity minEMine
t2 <- getPOSIXTime
hPrint stderr $ newMines - oldMines
hPrint stderr $ round $ 1000 * (t2 - t1)
putStrLn cmd putStrLn cmd
getMines :: GameState -> V.Vector Pos getMines :: GameState -> V.Vector Pos
getMines (_,_,_,m) = m getMines (_,_,_,m,_) = m
moveToEntity :: Entity -> String moveToEntity :: Entity -> String
moveToEntity e = case e of moveToEntity e = case e of
@@ -116,9 +124,9 @@ posFromEntity :: Entity -> (Int, Int)
posFromEntity (EHero _ p _ _) = p posFromEntity (EHero _ p _ _) = p
posFromEntity (EMine _ p) = p posFromEntity (EMine _ p) = p
gameState :: Entity -> V.Vector Pos -> GameState gameState :: Entity -> V.Vector Pos -> V.Vector Pos -> GameState
gameState (EHero _ pos l g) mines = (g, l, pos, mines) gameState (EHero _ pos l g) mines enemies = (g, l, pos, mines, enemies)
gameState (EMine _ pos) mines = (-1, -1, pos, mines) gameState (EMine _ pos) mines enemies = (-1, -1, pos, mines, enemies)
isTavern :: BoardEntity -> Bool isTavern :: BoardEntity -> Bool
isTavern Tavern = True isTavern Tavern = True

View File

@@ -9,8 +9,9 @@ import Control.Monad.State as S
import Control.Monad.State.Class import Control.Monad.State.Class
import Data.List as L import Data.List as L
import Simulation.Data import Simulation.Data
import Simulation.Lib
searchDepth = 9 searchDepth = 8
-- fromPlayerBoard :: Board -> BoardInternal -- fromPlayerBoard :: Board -> BoardInternal
-- fromPlayerBoard pBoardInternal = fmap (fmap $ fromEnum) asVector -- fromPlayerBoard pBoardInternal = fmap (fmap $ fromEnum) asVector
@@ -24,7 +25,7 @@ simulate :: Board -> GameState -> (Int, GameState)
simulate board = simulateMove board (-1,-1) searchDepth simulate board = simulateMove board (-1,-1) searchDepth
simulateMove :: Board -> Pos -> Int -> GameState -> (Int, GameState) simulateMove :: Board -> Pos -> Int -> GameState -> (Int, GameState)
simulateMove board prevPos depth state@(_,_,pos,_) simulateMove board prevPos depth state@(_,_,pos,_,_)
| depth == 0 = | depth == 0 =
let state' = evalMove board state let state' = evalMove board state
in (evalGameState state', state') in (evalGameState state', state')
@@ -34,37 +35,38 @@ simulateMove board prevPos depth state@(_,_,pos,_)
-- der Trick: in einem Zug muss die Minenposition zurueckgegeben werden, die Position des Helden -- der Trick: in einem Zug muss die Minenposition zurueckgegeben werden, die Position des Helden
-- aendert sich aber nicht. Im naechsten Zug will der Held dann nicht mehr die Mine erobern. -- aendert sich aber nicht. Im naechsten Zug will der Held dann nicht mehr die Mine erobern.
pos' = if bPos == Tavern || bPos == Mine then prevPos else pos -- move back out of tavern/mine pos' = if bPos == Tavern || bPos == Mine then prevPos else pos -- move back out of tavern/mine
-- pos wird nicht benutzt. Pos ist aber der Wert, der zurueckgegeben werden muss, damit sich der Held in die Taverne bewegt moves = V.filter (posValid board state) $ possibleMoves pos'
moves = filter (posValid board state) $ possibleMoves pos'
vals = fmap (\pos'' -> simulateMove board pos' (depth-1) (updatePos pos'' state')) moves vals = fmap (\pos'' -> simulateMove board pos' (depth-1) (updatePos pos'' state')) moves
valsWithOldPos = if depth == searchDepth valsWithOldPos = if depth == searchDepth
then vals -- return position of submove on first level then vals -- return position of submove on first level
else zip (fmap fst vals) $ fmap (updatePos pos . snd) vals -- return starting position otherwise -- pos' else V.zip (fmap fst vals) $ fmap (updatePos pos . snd) vals -- return starting position otherwise -- pos'
in L.maximumBy (\(v1, _) (v2, _) -> compare v1 v2) valsWithOldPos in L.maximumBy (\(v1, _) (v2, _) -> compare v1 v2) valsWithOldPos
updatePos :: Pos -> GameState -> GameState updatePos :: Pos -> GameState -> GameState
updatePos pos (gold, life, _, mines) = (gold, life, pos, mines) updatePos pos (gold, life, _, mines, enemies) = (gold, life, pos, mines, enemies)
-- update State according to hero position on board -- update State according to hero position on board
-- executed every move -- executed every move
evalMove :: Board -> GameState -> GameState evalMove :: Board -> GameState -> GameState
evalMove board state@(gold, life, pos, mines) = evalDeath evalBuildings evalMove board state@(gold, life, pos, mines, enemies) = evalDeath $ evalEnemies evalBuildings
where where
evalBuildings evalBuildings
| entity == Air = (gold + length mines, thirst life, pos, mines) | entity == Air = (gold + length mines, thirst life, pos, mines, enemies)
| entity == SpawnPoint = (gold + length mines, thirst life, pos, mines) | entity == SpawnPoint = (gold + length mines, thirst life, pos, mines, enemies)
| entity == Tavern = | entity == Tavern =
if gold >= 2 then if gold >= 2 then
( gold + length mines - 2 ( gold + length mines - 2
, min 100 (life + 50) -- TODO: Check if life is +19 , min 100 (life + 50) -- TODO: Check if life is +19
, pos , pos
, mines , mines
, enemies
) )
else else
( gold + length mines ( gold + length mines
, thirst life , thirst life
, pos , pos
, mines , mines
, enemies
) )
| entity == Mine = | entity == Mine =
let addMine = pos `V.notElem` mines let addMine = pos `V.notElem` mines
@@ -74,12 +76,18 @@ evalMove board state@(gold, life, pos, mines) = evalDeath evalBuildings
, if addMine then thirst life - 20 else thirst life , if addMine then thirst life - 20 else thirst life
, pos , pos
, mines' , mines'
, enemies
) )
| entity == Wall = state -- should never happen | entity == Wall = state -- should never happen
where where
entity = boardPos board pos entity = boardPos board pos
evalDeath state'@(gold', life', pos', mines') -- TODO: Gegner verliert auch Leben
| life' < 5 = (gold', 100, (0,0), V.empty) -- TODO: starting position is not 0,0 but spawnpoint evalEnemies :: GameState -> GameState
evalEnemies state'@(gold', life', pos', mines', enemies')
| any (<2) $ fmap (dist pos') enemies' = (gold', life' - 20, pos', mines', enemies')
| otherwise = state'
evalDeath state'@(gold', life', pos', mines', enemies')
| life' < 5 = (gold', 100, (0,0), V.empty, enemies') -- TODO: starting position is not 0,0 but spawnpoint
| otherwise = state' | otherwise = state'
thirst life = max 1 (life - 1) thirst life = max 1 (life - 1)
@@ -87,21 +95,21 @@ thirst life = max 1 (life - 1)
-- retuns the evalutaion of the current move -- retuns the evalutaion of the current move
-- executed if maximum depth is reached -- executed if maximum depth is reached
evalGameState :: GameState -> Int evalGameState :: GameState -> Int
evalGameState (gold, life, _, mines) = gold + (life `div` 10) + length mines * 2 evalGameState (gold, life, _, mines, _) = gold + (life `div` 10) + length mines * 2 -- TODO: Warum macht nur mines quatsch?
-- get BoardInternalEntity Enum of Pos on BoardInternal -- get BoardInternalEntity Enum of Pos on BoardInternal
boardPos :: Board -> Pos -> BoardEntity boardPos :: Board -> Pos -> BoardEntity
boardPos board (x,y) = (board V.! y) V.! x boardPos board (x,y) = (board V.! y) V.! x
posValid :: Board -> GameState -> Pos -> Bool posValid :: Board -> GameState -> Pos -> Bool
posValid board (_, _, _, mines) pos@(x,y) = onBoardInternal && boardPos' /= Wall && pos `notElem` mines posValid board (_, _, _, mines, _) pos@(x,y) = onBoardInternal && boardPos' /= Wall && pos `notElem` mines
where where
size = length board size = length board
boardPos' = boardPos board pos boardPos' = boardPos board pos
onBoardInternal = x >= 0 && x < size && y >= 0 && y < size onBoardInternal = x >= 0 && x < size && y >= 0 && y < size
possibleMoves :: Pos -> [Pos] possibleMoves :: Pos -> V.Vector Pos
possibleMoves (x,y) = [ (x+1, y), (x, y+1), (x-1, y), (x, y-1) ] possibleMoves (x,y) = V.fromList [ (x+1, y), (x, y+1), (x-1, y), (x, y-1) ]
data Tree v = Node v (Tree v) | Leaf v data Tree v = Node v (Tree v) | Leaf v

View File

@@ -10,5 +10,5 @@ type IndexedBoard = V.Vector (Pos, BoardEntity)
type Pos = (Int, Int) type Pos = (Int, Int)
-- (gold, life, hero pos, own mines) -- (gold, life, hero pos, own mines, enemies)
type GameState = (Int, Int, Pos, V.Vector Pos) type GameState = (Int, Int, Pos, V.Vector Pos, V.Vector Pos)

View File

@@ -4,7 +4,7 @@ cabal-version: 1.12
-- --
-- see: https://github.com/sol/hpack -- see: https://github.com/sol/hpack
-- --
-- hash: a40eac4da8b91ec478d65b8403d0b4c79040e0e5d0ae95d897222ea2c05cb732 -- hash: 417e6c9b6226b7bcecca4ed2838a83b02bcb813752e3a15911e72c73db470c74
name: stackproject name: stackproject
version: 0.1.0.0 version: 0.1.0.0
@@ -51,6 +51,7 @@ library
, haskell-src-exts , haskell-src-exts
, mtl , mtl
, random , random
, time
, vector , vector
default-language: Haskell2010 default-language: Haskell2010
@@ -74,6 +75,7 @@ executable stackproject-exe
, mtl , mtl
, random , random
, stackproject , stackproject
, time
, vector , vector
default-language: Haskell2010 default-language: Haskell2010
@@ -98,5 +100,6 @@ test-suite stackproject-test
, mtl , mtl
, random , random
, stackproject , stackproject
, time
, vector , vector
default-language: Haskell2010 default-language: Haskell2010