쥐 미로를 구축하는 프로그램


15

연구 조교로 고용되어 쥐 미로를 만드는 작은 프로그램을 만들도록 요청했습니다. 쥐 상자는 항상 62x22이며 쥐의 입구 (a)와 출구 (A)는 다음과 같습니다 (입력 1).

#######a######################################################
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#################################################A############

프로그램은 다음과 같이 래트 경로를 남기는 블록 (#)으로 상자를 채워야합니다 (출력 1).

#######a######################################################
####### ######################################################
####### ######################################################
####### ######################################################
####### ######################################################
#######                                           ############
################################################# ############
################################################# ############
################################################# ############
################################################# ############
################################################# ############
################################################# ############
################################################# ############
################################################# ############
################################################# ############
################################################# ############
################################################# ############
################################################# ############
################################################# ############
################################################# ############
################################################# ############
#################################################A############

생각하기 쉽다! 자신감이 넘치는 작은 프로그램을 작성하기 시작합니다. 그러나 Principle Scientist는 새로운 아이디어를 가지고있었습니다. 그는 두 마리의 쥐가 동시에 미로를 탐색하기를 원합니다. Rattanshnorter 박사는 문과 출구가 다르다고 설명합니다 (입력 2).

#b#####a######################################################
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            #
#                                                            B
#                                                            #
#################################################A############

쥐는 교차로를 통해 직선으로 움직 이도록 훈련을 받았지만 T- 교차로 인해 혼란스러워 실험이 무효화 될 것입니다. 좋은 의사가 하나의 최종 요구 사항을 설명 할 때 새롭고 복잡한 작업을 시작합니다. 쥐는 서로에게 야만적이므로 언제든 서로를 보면 쥐 싸움이 일어나고 윤리위원회 앞에 둘 것입니다. 이제 프로그램이 다음과 같은 미로를 출력해야 함을 알고 있습니다 (출력 2).

#b#####a######################################################
# ##### ######################################################
# ##### ######################################################
# ##### #######################################           ####
# ##### ####################################### ######### ####
# #####                                           ####### ####
# ############################################# # ####### ####
# ############################################# # ####### ####
# ############################################# # ####### ####
# ############################################# # ####### ####
#                                               # ####### ####
################################################# ####### ####
################################################# ####### ####
################################################# ####### ####
################################################# ####### ####
################################################# ####### ####
################################################# ####### ####
################################################# ####### ####
################################################# ####### ####
################################################# #######    B
################################################# ############
#################################################A############

쥐 B가 교차로에 도달 할 때, 쥐 A는 복도를 따라 내려가 A를 빠져 나가고 쥐 싸움은 피할 것입니다.

규칙 :

  • 프로그램은 위와 같은 입력을 읽고 (STDIN 또는 파일), 많은 공간을 제외하고 동일한 데이터를 출력 (STDOUT 또는 파일)해야합니다 (이제 해시 (#)). 입력 문자열 ;대신 단일 문자 (예 : 등 )를 사용할 수 \n있지만 출력 문자열에는 여전히 \n문자 가 필요 합니다.업데이트

  • 랫트 경로는 교차 교차를 제외하고 너비가 한 문자 너비 여야합니다 (모든 공간은 직교 적으로 0 또는 2 여야합니다. # 문자 ). 교차로를 제외하고 각 쥐는 명확한 단일 경로를 가져야합니다. T 교차로는 허용되지 않습니다.

  • 쥐는 동시에 풀리고 일정한 속도로 움직입니다. 두 마리 이상의 쥐가 서로를 볼 수 없어서는 안됩니다 ( #사이에 하나 이상의 문자가 없는 동일한 열이나 행에 있어야 함 ).

  • 해결책이없는 경우 (예 : 인접한 입구 지점) 인쇄 Impossible\n하고 종료하십시오.

  • 출입구는 어느 쪽이든 될 수 있지만 모서리에는 절대로 있지 않습니다.

  • (예 : 일치하는 입구와 출구가 인접한 경우 ##aA##), 쥐가 직접 갈 수 없습니다 aA. 미로 내부에는 작은 2 개의 공간 복도 구역이 있어야합니다.

  • 쥐가 출구 지점에 도달 한 시점 (또는 그 이후 언제라도)에서 다른 쥐에게는 더 이상 보이지 않습니다.

  • 귀하의 프로그램은 1, 2, 최대 26 마리의 쥐에 대한 미로를 계산하도록 설계되었을 수 있습니다.

  • 표준 허점은 허용되지 않습니다.

점수:

당신의 솔루션으로, 당신의 프로그램이 해결할 수있는 미로 (N) 당 몇 마리의 쥐를 지명하십시오. 점수는 코드 길이 (바이트)를이 숫자 N으로 나눈 값입니다.

귀하의 프로그램이 생산하는 것을 볼 수 있도록 귀하의 답변에 샘플 출력을 포함하십시오.


가능한 입력의 유일한 차이점은 a, A, b, B의 위치입니까?
xnor

2 쥐 버전의 경우 예. 프로그램이 최대 3 마리의 쥐를 위해 고안된 경우 가능한 모든 a, b, c, A, B, C 위치에 대처해야합니다.
로직 나이트

쥐가 T의 가로 부분만을 따라 걷는다면 T 교차점이 허용됩니까?
orlp

아닙니다.이 쥐들은 쉽게 혼동됩니다. 직선 경로, 팔꿈치 굽힘 및 교차로 만 허용됩니다.
로직 나이트

@CarpetPython 입구 / 출구가 미로의 가장자리를 따라 어디에나있을 수 있습니까? 인접 할 수 있습니까?
orlp

답변:


2

Haskell, 26 마리 쥐?, ~ 5000 바이트

이론적으로이 코드는 몇 개의 쥐에 대해서도 효과가 있지만 우주의 열사병 전에 종료 될 것이라는 보장은 없습니다. 역 추적 알고리즘을 기반으로합니다.이 알고리즘은 직선 경로를 먼저 시도한 다음 경로가 작동하지 않으면 경로를 전환합니다. 대안의 수는 경로의 길이 및 래트의 수와 관련하여 지수 적이다.

나는 그것이 너무 커서 처음부터 더 빨리 만들고 싶기 때문에 아직 골프를 신경 쓰지 않았습니다.

{-# LANGUAGE FlexibleContexts #-}
module Main (main) where

import Control.Lens
import Control.Monad
import Data.Char
import Data.Function
import Data.List
import Data.Maybe

type Pos = (Int,Int)
type Path = [Pos]
type Maze = String
type Input = [(Pos,Char)]
type MazeState = [(Path,Path)]

type ChoiceMonad a = [a]


instance (Num a, Num b) => Num (a,b) where
  (x,y)+(x',y')=(x+x',y+y')
  (x,y)-(x',y')=(x-x',y-y')
  fromInteger n = (fromInteger n,fromInteger n)


parseMaze :: Maze -> Input
parseMaze maze = maze ^@.. inner . filtered (`notElem` "# ")

inner :: IndexedTraversal' Pos Maze Char
inner = lined <.> traversed

main :: IO ()
main = do
    maze <- readFile "Sample2.in"
    putStrLn $ solveAndShow maze

fillMaze :: Maze -> Maze
fillMaze = inner.filtered(==' ').~'#'

updateMaze :: Path -> Maze -> Maze
updateMaze path = inner.indices (`elem` path).filtered(=='#') .~ ' '

isDone :: MazeState -> Bool
isDone = all (null . snd)

showMaze :: Maze -> MazeState -> Maze
showMaze maze path = updateMaze (fst =<< path) $ fillMaze maze

showSolution :: Maze -> ChoiceMonad MazeState -> String
showSolution _    []    = "Impossible"
showSolution maze (x:_) = showMaze maze x


stopCondition :: ChoiceMonad MazeState ->  Bool
stopCondition x = not $ null x || isDone (head x)

solveAndShow :: Maze -> String
solveAndShow maze = showSolution maze . solve $ mazeToState maze

solve :: ChoiceMonad MazeState -> ChoiceMonad MazeState
solve = fromJust . find (not.stopCondition) . iterate fullStep

mazeToState :: Maze -> ChoiceMonad MazeState
mazeToState maze = do
    let startsEnds = paths $ parseMaze maze
        return $ startsEnds & traverse.both %~ (:[])


fullStep :: ChoiceMonad MazeState -> ChoiceMonad MazeState
fullStep = (>>= stepAll)

stepAll :: MazeState -> ChoiceMonad MazeState
stepAll input = do
    pths <- mapM goStep input
    guard $ iall (checkVisible pths) $ map fst pths
    return $ pths
  where
    goStep :: (Path,Path) -> ChoiceMonad (Path,Path)
    goStep (curr:rest,[]) = return (curr:curr:rest,[])
    goStep (curr:these,end:ends)
       | distance curr end == 1 = return (end:curr:these,ends)

       | curr == end = goStep (curr:these,ends)
    goStep (path,end) = do
      next <- twoSteps (head end) path
      prev <- twoSteps next end
      return $ (next:path,prev:end)
    inMaze = inMazeWith input

    twoSteps :: Pos -> Path -> ChoiceMonad Pos
    twoSteps goal path = do
      next <- oneStep goal path inMaze
      guard $ not.null $ oneStep goal (next:path) (\x -> x==next || inMaze x)
      return next

checkVisible :: MazeState -> Int -> Path -> Bool
checkVisible _    _ [] = True
checkVisible pths i xs@(x:_) = checkBack && checkNow
  where
    nBack = 1 + visibleBackwards xs
    --checkBack = none (any (==x).take nBack .fst) pths
    checkBack = hasn't (folded.indices (/=i)._1.taking nBack folded.filtered (==x)) pths
    checkNow  = inone (\i' (x':_,_) -> (i/=i') && (==x') `any` take nBack xs ) pths

-- How long have you stayed on a line
visibleBackwards :: Path -> Int
visibleBackwards as = length . takeWhile ((==headDiff as) .headDiff). filter ((>=2).length) $ tails as
      where headDiff (a:a1:_) = a-a1
            headDiff x        = error $ "Bug: Too short list " ++ show x


inMazeWith :: [(Path, Path)] -> Pos -> Bool
inMazeWith = flip elem . concatMap (\x->snd x ++ fst x)

oneStep :: MonadPlus m => Pos -> Path -> (Pos -> Bool)  -> m Pos
oneStep end (curr:prev:_) inMaze =
  if distance curr end <= 1
     then return end
     else do
    let distance' :: Pos -> Double
        distance' x = fromIntegral (distance x end) + if curr - prev == x - curr then 0 else 0.4
    next <- msum . map return $ sortBy (compare`on`distance') $ neighbors curr

    -- Don't go back
    guard $ next /= prev

    -- Stay in bounds
    guard $ isInBounds next

    let dir = (next - curr)
    let lr = neighbors next \\ [curr,next+dir,end]

    -- If next is blocked, check that the one after that is free
    if inMaze next
      then do
        guard $ not . (\x->(x/=end)&&inMaze x) $ next + dir
        -- Both sides should be blocked as well
        guard $ (==2). length . filter inMaze $ lr
      else do
        -- No neighbors if empty
        guard $ null . filter inMaze $ lr

    -- All neighbors of 'curr', including 'next'
    let neigh' = filter (\i -> inMaze i || i == next) $ neighbors curr
        -- should be an even number
        guard $ even $ length neigh'

    return next
oneStep _ [start] _ = return $ inBounds start
oneStep _ _ _ = error "Too short path given"


toBounds :: (Num a, Eq a) => (a,a) -> a -> a
toBounds (low, high) x
    | x == low  = x + 1
    | x == high = x - 1
    | otherwise = x

distance :: Pos -> Pos -> Int
distance (x1,y1) (x2,y2) = abs(x1-x2)+abs(y1-y2)

-- Moves a pos to the closest one inside the bounds
inBounds :: Pos -> Pos
inBounds = bimap (toBounds (0,21)) (toBounds (0,61))

isInBounds :: Pos -> Bool
isInBounds x = x == inBounds x

neighbors :: Pos -> [Pos]
neighbors pos = [ pos & l %~ p| l <- [_1,_2], p <- [succ,pred]]

paths :: Input -> [(Pos,Pos)]
paths pos = flip unfoldr 'a' $ \x ->
  do (y,_) <- find ((==x).snd) pos
     (z,_) <- find ((==toUpper x).snd) pos
     return ((y,z),succ x)

샘플 출력, 6 마리 쥐 :

##c###B#####b#######C#######F######################f##########
##   #       #       #######                        ##########
####  ######## ###############################################
#####          ###############################################
##############################################################
##############################################################
##############################################################
##############################################################
##############################################################
##############################################################
##############################################################
##############################################################
##############################################################
##############################################################
#############       ##########################################
############# #####  #########################################
D             #    #     #####################################
##############  ## ##### #####################################
#########      #                 #############################
######### ###### # ##### ####### #############################
####      #      #     # #######                        ######
####E######a##########e#d##############################A######

2
b의 교차로에 도달 e하고 b, 그가으로 볼 수 없습니다 e? b에 도착한 것 같습니다 . 복도 t = 11e그대로 있습니다. 뭔가 빠졌습니까?
BrainSteel

@BrainSteel 예, 맞습니다. 내 대답이 유효하지 않습니다. 나는 이전에 (다른 쥐 길을 건넌 후) "시간의 거꾸로"충돌을 점검해야한다고 언급했지만 어떤 이유로 나는 그것이 필요하지 않다고 결정했다. : P
Hjulle

@BrainSteel 나는 지금 그 버그를 수정했다고 생각합니다.
Hjulle

1

하스켈, 1 마리, 681 자

단 하나의 쥐로 모든 미로에서 문제를 쉽게 해결할 수 있습니다. 이 코드는 또한 많은 수의 쥐에 "작동"하지만 사이의 상호 작용에 대한 제약 조건을 따르지 않습니다 여러 쥐와 경로 .

module Main where
import Control.Lens
import Data.List(unfoldr,find)
import Data.Char(toUpper)
parse=(^@..lined<.>folded.filtered(`notElem`"# "))
main=interact$do i<-(naive=<<).rats.parse;(lined<.>traversed).filtered(==' ').indices (`notElem`i).~'#'
    naive(start,(ex,ey))=start':unfoldr go start' where
     start'=bnds start
     (ex',ey')=bnds(ex,ey)
     go(x,y)
      |(x,y)==(ex',ey')=Nothing
      |x== ex'=ok(x,y`t`ey')
      |otherwise=ok(x`t`ex',y)
     ok z=Just(z,z)
     t x y=if x>y then x-1 else x+1
    bnd(l,h)x |x==l=x+1 |x==h=x-1 |True=x
    bnds=bimap(bnd(0,21))(bnd(0,61))
    rats pos=(`unfoldr`'a')$ \x->
  do (y,_)<-find((==x).snd)pos
     (z,_)<-find((==toUpper x).snd)pos
     return((y,z),succ x)

샘플 출력 :

#######a######################################################
####### ######################################################
####### ######################################################
####### ######################################################
####### ######################################################
####### ######################################################
####### ######################################################
####### ######################################################
####### ######################################################
####### ######################################################
####### ######################################################
####### ######################################################
####### ######################################################
####### ######################################################
####### ######################################################
####### ######################################################
####### ######################################################
####### ######################################################
####### ######################################################
####### ######################################################
#######                                           ############
#################################################A############

많은 쥐를 지원할 계획이므로 일반 코드를 작성했지만 아직 그에 대한 좋은 알고리즘을 찾지 못했습니다.

  • parse 좌표로 모든 출입구 목록을 추출합니다.
  • rats 이 목록을 가져 와서 각 쥐의 좌표 쌍으로 변환합니다.
  • bnds 가장자리에 좌표를 가져다가 미로 안의 가장 가까운 좌표로 옮깁니다.
  • naive 시작 위치와 끝 위치를 가져와 그들 사이의 간단한 경로를 반환합니다.
  • main 그런 다음 경로에없는 모든 공백을 '#'으로 바꿉니다.

@ edc65 "... 여러 쥐 사이의 제약 ". 이것은 질문에 따라 허용되는 쥐 한 마리에 대한 답변입니다.
Hjulle

알았어 내 잘못이야 쥐 한 마리에게는 다른 도전 과제라고 생각하면됩니다. 이전 의견을 삭제
하겠습니다
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.