diff --git a/haskell/vindinium/app/Main.hs b/haskell/vindinium/app/Main.hs index 495030c..8a0cedc 100644 --- a/haskell/vindinium/app/Main.hs +++ b/haskell/vindinium/app/Main.hs @@ -21,7 +21,7 @@ loop1 pos depth acc in loop1 sim (depth - 1) acc' sim1 :: Pos -> (Int, Pos) -sim1 pos = simulate board1 pos (0, 100, singleton (0,4)) +sim1 pos = simulate board1 (0, 100, pos, singleton (0,4)) board1 :: Board board1 = fromList $ fmap fromList diff --git a/haskell/vindinium/src/Player.hs b/haskell/vindinium/src/Player.hs index fa6243b..233b8c0 100644 --- a/haskell/vindinium/src/Player.hs +++ b/haskell/vindinium/src/Player.hs @@ -79,7 +79,9 @@ bot readLine writeLine = do EMine oId _ -> oId == myId _ -> False) entities - let (val, pos) = simulate board (posFromEntity hero) (gameState hero $ fmap posFromEntity myMines) + let st = (gameState hero $ fmap posFromEntity myMines) + hPrint stderr st + let (val, pos) = simulate board st -- hPrint stderr (gameState hero $ fmap posFromEntity myMines) -- (val, pos) putStrLn $ moveToPos pos @@ -108,8 +110,8 @@ posFromEntity (EHero _ p _ _) = p posFromEntity (EMine _ p) = p gameState :: Entity -> V.Vector Pos -> GameState -gameState (EHero _ _ l g) mines = (g, l, mines) -gameState (EMine _ _) mines = (-1, -1, mines) +gameState (EHero _ pos l g) mines = (g, l, pos, mines) +gameState (EMine _ pos) mines = (-1, -1, pos, mines) isTavern :: BoardEntity -> Bool isTavern Tavern = True diff --git a/haskell/vindinium/src/Simulation/Board.hs b/haskell/vindinium/src/Simulation/Board.hs index 7b78633..1737340 100644 --- a/haskell/vindinium/src/Simulation/Board.hs +++ b/haskell/vindinium/src/Simulation/Board.hs @@ -9,8 +9,7 @@ import Control.Monad.State.Class import Data.List as L import Simulation.Data -size = 5 -- TODO: Allow for variable board sizes -searchDepth = 9 +searchDepth = 8 -- fromPlayerBoard :: Board -> BoardInternal -- fromPlayerBoard pBoardInternal = fmap (fmap $ fromEnum) asVector @@ -20,69 +19,79 @@ searchDepth = 9 -- back and forth between two fields infinitely -- Caution: if the player moved inside a Tavern or Mine he needs to be reset to his initial position afterwards -- TODO: Check if tailrec -simulate :: Board -> Pos -> GameState -> (Int, Pos) -simulate board pos = simulateMove board pos (-1,-1) searchDepth +simulate :: Board -> GameState -> (Int, Pos) +simulate board = simulateMove board (-1,-1) searchDepth -simulateMove :: Board -> Pos -> Pos -> Int -> GameState -> (Int, Pos) -simulateMove board pos prevPos depth gameState +simulateMove :: Board -> Pos -> Int -> GameState -> (Int, Pos) +simulateMove board prevPos depth state@(_,_,pos,_) | depth == 0 = - let gameState' = evalMove board pos gameState - in (evalGameState gameState', pos) + let state' = evalMove board state + in (evalGameState state', pos) | otherwise = - let gameState' = evalMove board pos gameState + let state' = evalMove board state bPos = boardPos board pos - -- pos' = if bPos == Tavern || bPos == Mine then prevPos else pos -- move back out of tavern/mine - vals = fmap (\pos'' -> simulateMove board pos'' pos (depth-1) gameState') moves -- before pos' + -- 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. + --pos' = if bPos == Tavern || bPos == Mine then prevPos else pos -- move back out of tavern/mine + vals = fmap (\pos' -> simulateMove board pos (depth-1) (updatePos pos' state')) moves -- before pos' valsWithOldPos = if depth == searchDepth then vals -- return position of submove on first level else zip (fmap fst vals) (replicate 4 pos) -- return starting position otherwise -- before pos' in L.maximumBy (\(v1, _) (v2, _) -> compare v1 v2) valsWithOldPos where moves :: [Pos] - moves = filter (posValid board) $ possibleMoves pos + moves = filter (posValid board state) $ possibleMoves pos + +updatePos :: Pos -> GameState -> GameState +updatePos pos (gold, life, _, mines) = (gold, life, pos, mines) -- update State according to hero position on board -- executed every move -evalMove :: Board -> Pos -> GameState -> GameState -evalMove board pos state@(gold, life, mines) - | entity == Air = (gold + length mines, life-1, mines) - | entity == SpawnPoint = (gold + length mines, life-1, mines) - | entity == Tavern = - if gold >= 2 then - ( gold + length mines - 2 - , min 100 (life + 50) -- TODO: Check if life is +19 - , mines - ) - else - ( gold + length mines - , life - 1 - , mines - ) - | entity == Mine = - let addMine = pos `V.notElem` mines - mines' = if addMine then V.cons pos mines else mines - in - ( gold + length mines' - , life - 1 - , mines' - ) - | entity == Wall = state -- should never happen +evalMove :: Board -> GameState -> GameState +evalMove board state@(gold, life, pos, mines) = evalBuildings where - entity = boardPos board pos + evalBuildings + | entity == Air = (gold + length mines, life-1, pos, mines) + | entity == SpawnPoint = (gold + length mines, life-1, pos, mines) + | entity == Tavern = + if gold >= 2 then + ( gold + length mines - 2 + , min 100 (life + 50) -- TODO: Check if life is +19 + , pos + , mines + ) + else + ( gold + length mines + , life - 1 + , pos + , mines + ) + | entity == Mine = + let addMine = pos `V.notElem` mines + mines' = if addMine then V.cons pos mines else mines + in + ( gold + length mines' + , life - 1 + , pos + , mines' + ) + | entity == Wall = state -- should never happen + where + entity = boardPos board pos -- retuns the evalutaion of the current move -- executed if maximum depth is reached evalGameState :: GameState -> Int -evalGameState (gold, _, _) = gold +evalGameState (gold, _, _, mines) = gold + length mines * 10 -- get BoardInternalEntity Enum of Pos on BoardInternal boardPos :: Board -> Pos -> BoardEntity --- boardPos board (x,y) = (board V.! x) V.! y boardPos board (x,y) = (board V.! y) V.! x -posValid :: Board -> Pos -> Bool -posValid board pos@(x,y) = onBoardInternal && boardPos' /= Wall +posValid :: Board -> GameState -> Pos -> Bool +posValid board (_, _, _, mines) pos@(x,y) = onBoardInternal && boardPos' /= Wall && boardPos' /= Tavern && pos `notElem` mines where + size = length board boardPos' = boardPos board pos onBoardInternal = x >= 0 && x < size && y >= 0 && y < size @@ -90,5 +99,4 @@ possibleMoves :: Pos -> [Pos] possibleMoves (x,y) = [ (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 \ No newline at end of file diff --git a/haskell/vindinium/src/Simulation/Data.hs b/haskell/vindinium/src/Simulation/Data.hs index 0986847..ecaf7bb 100644 --- a/haskell/vindinium/src/Simulation/Data.hs +++ b/haskell/vindinium/src/Simulation/Data.hs @@ -10,5 +10,5 @@ type IndexedBoard = V.Vector (Pos, BoardEntity) type Pos = (Int, Int) --- (gold, life, own mines) -type GameState = (Int, Int, V.Vector Pos) +-- (gold, life, hero pos, own mines) +type GameState = (Int, Int, Pos, V.Vector Pos)