โปรแกรมสร้างเขาวงกตหนู


15

คุณได้รับการว่าจ้างเป็นผู้ช่วยวิจัยและขอให้สร้างโปรแกรมขนาดเล็กที่จะสร้างเขาวงกตหนู กล่องหนูอยู่เสมอ 62x22 และมีทางเข้า (a) และทางออก (A) สำหรับหนูเช่นนี้ (อินพุต 1):

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

โปรแกรมของคุณจะต้องกรอกกล่องด้วยบล็อก (#) ออกจากเส้นทางสำหรับหนูเช่นนี้ (ผลลัพธ์ 1)

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

นี่เป็นเรื่องง่ายที่คุณคิด! คุณเริ่มเขียนโปรแกรมขนาดเล็กเต็มไปด้วยความมั่นใจ อย่างไรก็ตามหลักการนักวิทยาศาสตร์มีความคิดใหม่ - เขาต้องการหนูสองตัวเพื่อนำทางเขาวงกตในเวลาเดียวกัน Dr Rattanshnorter อธิบายว่าพวกเขามีประตูและทางออกที่แตกต่างกัน (อินพุต 2):

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

หนูได้รับการฝึกฝนให้เคลื่อนที่ผ่านทางแยก แต่ T-intersection ปล่อยให้พวกมันสับสนอย่างสิ้นหวังและจะทำให้การทดลองเป็นโมฆะ คุณเริ่มงานใหม่ที่ซับซ้อนมากขึ้นเมื่อแพทย์ที่ดีอธิบายถึงข้อกำหนดสุดท้าย: หนูเป็นสัตว์ป่าที่ดุร้ายต่อกันดังนั้นหากพวกเขาเห็นซึ่งกันและกัน ณ จุดใดเวลาหนึ่งการต่อสู้ของหนูจะแตกออกและคุณทั้งคู่จะอยู่ต่อหน้าคณะกรรมการจริยธรรม ตอนนี้คุณรู้ตัวว่าโปรแกรมของคุณควรสร้างเขาวงกตแบบนี้ (เอาท์พุท 2):

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

เมื่อถึงเวลาที่หนูบีถึงสี่แยกหนูจะต้องเดินทางไปตามทางเดินเพื่อออกจาก A และจะหลีกเลี่ยงการต่อสู้ของหนู

กฎ:

  • โปรแกรมของคุณควรอ่าน (STDIN หรือไฟล์) อินพุตเหมือนที่กล่าวมาข้างต้นและเอาต์พุต (STDOUT หรือไฟล์) เป็นข้อมูลเดียวกันยกเว้นว่าช่องว่างจำนวนมากจะถูกแฮช (#) คุณสามารถแทนที่อักขระเดี่ยวใด ๆ (เช่น;) แทน\nในสตริงอินพุต แต่สตริงเอาต์พุตยังคงต้องการ\nอักขระ ปรับปรุง

  • ทางเดินของหนูต้องกว้างหนึ่งตัวกว้างยกเว้นจุดตัดขวาง (ทุกช่องว่างต้องมี#อักขระศูนย์หรือสองตัวติดกัน orthogonally ) หนูแต่ละคนจะต้องมีเส้นทางเดียวที่ชัดเจนยกเว้นสำหรับทางแยก ไม่อนุญาตให้ใช้ทางแยก T

  • หนูจะถูกปล่อยพร้อมกันและเคลื่อนที่ด้วยอัตราคงที่ ในเวลาไม่ควรหนูสองตัวหรือมากกว่านั้นจะเห็นซึ่งกันและกัน (อยู่ในคอลัมน์หรือแถวเดียวกันโดยไม่ต้องมี#ตัวละครมากกว่าหนึ่งตัว)

  • หากไม่สามารถแก้ปัญหาได้ (เช่นจุดทางเข้าที่อยู่ติดกัน) ให้พิมพ์ Impossible\nและออก

  • ทางเข้าและทางออกสามารถอยู่ด้านใดก็ได้ แต่จะไม่มีมุม

  • หากมีการจับคู่ทางเข้าและทางออกอยู่ติด (เช่น##aA##) หนูไม่สามารถไปได้โดยตรงจากการa Aจะต้องมีพื้นที่ทางเดินเล็ก ๆ 2 ส่วนภายในบริเวณเขาวงกต

  • เมื่อถึงจุดที่หนูไปถึงจุดออก (หรือหลังจากนั้น) หนูจะไม่สามารถมองเห็นหนูตัวอื่นได้อีกต่อไป

  • โปรแกรมของคุณอาจได้รับการออกแบบมาเพื่อคำนวณเขาวงกตเป็นเวลา 1, 2, มากถึง 26 หนู

  • ช่องโหว่มาตรฐานไม่ได้รับอนุญาต

คะแนน:

ด้วยโซลูชันของคุณให้ระบุจำนวนหนูต่อเขาวงกต (N) ที่โปรแกรมของคุณสามารถแก้ไขได้ คะแนนของคุณคือความยาวรหัสของคุณเป็นไบต์หารด้วยหมายเลขนี้ N

โปรดรวมเอาท์พุทตัวอย่างในคำตอบของคุณเพื่อให้เราสามารถเห็นสิ่งที่โปรแกรมของคุณผลิต


ความแตกต่างเพียงอย่างเดียวในการป้อนตำแหน่งที่เป็นไปได้ของ a, A, b, B คืออะไร?
xnor

สำหรับรุ่น 2 หนูใช่ หากโปรแกรมของคุณถูกออกแบบมาสำหรับหนูสูงสุด 3 ตัวคุณจะต้องรับมือกับตำแหน่งที่เป็นไปได้ทั้งหมดของ a, b, c, A, B, C
Logic Knight อัศวิน

อนุญาตให้มีทางแยก T ได้ไหมถ้าหนูจะเดินเคียงข้างส่วนแนวนอนของ T?
orlp

ไม่หนูเหล่านี้สับสนง่าย อนุญาตให้ใช้ทางตรงโค้งงอและทางแยกเท่านั้น
Logic Knight

@CarpetPython ทางเข้า / ออกสามารถอยู่ที่ใดก็ได้ตามแนวเขาวงกตหรือไม่? พวกมันอยู่ติดกันได้ไหม
orlp

คำตอบ:


2

Haskell, 26 rats?, ~ 5,000 bytes

ในทางทฤษฎีรหัสนี้ควรใช้กับหนูทุกจำนวน แต่ฉันไม่รับประกันว่ามันจะยุติลงก่อนที่ความร้อนจากจักรวาลจะตาย มันขึ้นอยู่กับอัลกอริทึมย้อนรอยซึ่งพยายามที่จะไปเส้นทางตรงก่อนจากนั้นสลับเส้นทางหากเส้นทางไม่ทำงาน จำนวนทางเลือกเป็นเลขชี้กำลังตามความยาวของเส้นทางและจำนวนของหนู

ฉันยังไม่ได้สนใจที่จะเล่นกอล์ฟเนื่องจากยังมีขนาดใหญ่และเนื่องจากฉันต้องการทำให้เร็วขึ้นเป็นลำดับแรก

{-# 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 = 11ซึ่งจะeยังคงอยู่ในทางเดินนั้น ฉันพลาดอะไรไปรึเปล่า?
BrainSteel

@BrainSteel ใช่ถูกต้องแล้ว คำตอบของฉันไม่ถูกต้อง ฉันสังเกตเห็นตัวเองก่อนหน้านี้ว่าฉันต้องตรวจสอบการชนกันของ "ย้อนหลังตรงเวลา" เช่นกัน (หลังจากข้ามเส้นทางหนูอื่น) แต่ด้วยเหตุผลบางอย่างฉันตัดสินใจว่าไม่จำเป็น : P
Hjulle

@BrainSteel ฉันเชื่อว่าฉันได้แก้ไขข้อผิดพลาดนั้นแล้ว
Hjulle

1

Haskell 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 "... ข้อ จำกัด ระหว่างหนูหลายตัว " นี่คือคำตอบเพียง 1 หนูซึ่งได้รับอนุญาตตามคำถาม
Hjulle

ตกลงความผิดของฉัน แค่คิดว่าสำหรับ 1 หนูมันเป็นความท้าทายที่แตกต่าง ฉันจะลบความคิดเห็นก่อนหน้าของฉัน
edc65
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.