Quelle est la grandeur de votre terre?

23

Dans ce défi, vous calculerez la taille de votre terrain.


Écrivez un programme ou une fonction qui calcule la taille de votre terrain, compte tenu d'un mur que vous avez construit. On vous donne une chaîne d'entrée non vide contenant un ensemble de 4 caractères distincts de votre choix qui représentent les quatre directions "haut", "bas", "gauche" et "droite" (je vais l'utiliser ^ v < >dans ce défi). Il n'est pas possible de faire des virages à 180 degrés ( <>ou ^v), mais vous pouvez traverser votre mur.

La façon dont vous "capturez" la terre est en l'entourant de votre mur. Le mur lui-même est également considéré comme faisant partie de votre terrain. Quelques exemples le rendront plus clair. Je vais utiliser opour un terrain qui a été entouré par le mur, xpour le mur lui-même et Spour le point de départ du mur, juste pour illustrer comment le mur est construit. La sortie doit correspondre à la taille totale de votre terrain (le nombre de o, xet Sdans les cas de test ci-dessous).

Input: >>>>
Land: Sxxxx
Output: 5

Input: <<<^^^>>>vv
Land:
xxxx
xoox
xoox
xxxS
Output: 16

Input: <<<^^^>>>v
Land:
xxxx
x  x
x  
xxxS 
Output: 11

Input: <
Land: xS
Output: 2 

Input: >>>>>>vvvvvvvvv<<<<<^^^^>>>>>>>>vvvvvvvvvv<<<<<<<<<<<<<<<^^^^^^^^^>>>vvvvvv<<<<<
Land:
        Sxxxxxx
              x
              x
              x
              x  
         xxxxxxxxx
  xxxx   xoooox  x
  xoox   xoooox  x
  xoox   xoooox  x
  xoox   xxxxxx  x
  xoox           x
  xoox           x
xxxxxx           x
  x              x
  x              x
  xxxxxxxxxxxxxxxx
Output: 101

Input: >>vvvv>>^^<<<<^
Land:
Sxx
xox
xxxxx
  xox
  xxx
Output: 17

Input: <<^^^>>>vv
Land:
xxxx
x  x
x  x
xxS
Output: 11   <- Note, diagonal edges do not close the "loop"

Précisions:

  • Vous n'avez pas besoin de dessiner le mur, la sortie ne doit être qu'un entier
  • Le format d'entrée est facultatif. Vous pouvez prendre une chaîne avec <>^v, une liste de chiffres (1, -1, i, -i), une liste de caractères, ABCDetc.

Il s'agit de donc le code le plus court dans chaque langue l' emporte. N'oubliez pas que les explications sont importantes, même dans les langues "normales"!

Stewie Griffin
la source
1
Vous devez modifier la description afin qu'elle calcule le nombre de trèfles que vous avez inclus: P
fəˈnɛtɪk
Assez lié
Arnauld
En relation?
Matthew Roh
@MatthewRoh, hmmm .
Stewie Griffin
@Stewie Oh oui, c'est aussi lié
Matthew Roh

Réponses:

6

Python 2 , 385 345 332 octets

A,I,R=max,min,range
a=b=0
p=[[a,b]]
for i in input():a+=i%2*(2-i);b+=(1-i%2)*(1-i);p+=[a,b],
k,l=zip(*p)
x=A(k)-I(k)+3
y=A(l)-I(l)+3
o=[[1]*y for _ in' '*x]
def g(m,n):
 if 0<o[m][n]and[m+I(k)-1,n+I(l)-1]not in p:o[m][n]=0;[g(i,j)for i in R(A(0,m-1),I(x,m+2))for j in R(A(0,n-1),I(y,n+2))if(i,j)!=(m,n)]
g(0,0)
print sum(map(sum,o))

Essayez-le en ligne! ou Essayez tous les cas de test

L'entrée est numérique, 0 ~ 3, l'indice 0 des symboles ici: >v<^

#starting position
a,b=0
#new list to hold the wall coordinates
p=[[a,b]]

#iterate over the input calculating
#the next coordinate and storing on p
for i in input():
 a=a+i%2*(2-i)
 b=b+(1-i%2)*(1-i)
 p+=[[a,b]]
#i%2*(2-i) and (1-i%2)*(1-i) generate the increment
#of each symbol from last position 
# >/0 : (0,1)
# v/1 : (1,0)
# </2 : (0,-1)
# ^/3 : (-1,0)

#transpose the coordinate list
k,l=zip(*p)
#calculate the difference between the max and min values
#to generate the total land size
#adding a border to avoid dead-ends
x=max(k)-min(k)+3
y=max(l)-min(l)+3

#create a matrix of 1's with the total land size
o=[([1]*y) for _ in ' '*x]

#recursive function that sets a cell to 0
#and call itself again on all surrounding cells
def g(m,n):
 #correct the indexes (like negative ones)
 a,b=m+min(k)-1,n+min(l)-1
 #if this cell contains 1 and don't belong to the wall
 if o[m][n]>0 and (a,b) not in p:
  #sets to 0
  o[m][n]=0
  #call again on surrounding cells
  for i in range(max(0,m-1),min(x,m+2)):
   for j in range(max(0,n-1), min(y,n+2)):
    if (i,j)!=(m,n):g(i,j)

#call the recursive function o origin
g(0,0)
#print the sum of the cells
print sum(map(sum,o))

Voici la matrice résultante:

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0]
[0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0]
[0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0]
[0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0]
[0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0]
[0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]
[0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]
[0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]
[0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Barre
la source
3

Octave, 83 85 83 79 octets

@(p)nnz(bwfill(accumarray([real(c=cumsum([0;p])) imag(c)]+nnz(p)+1,1),"holes"))

Essayez-le sur Octave Online!

Une fonction qui prend en entrée un vecteur de colonne contenant (1, -1, i, -i)

En utilisant l'approche de la réponse Mathematica de @ lanlock4, ajoutez la longueur de l'entrée aux coordonnées pour éviter les coordonnées non positives, au lieu de leur soustraire un minimum de coordonnées. Enregistré 4 octets.

Réponse précédente:

@(p)nnz(bwfill(accumarray((k=[real(c=cumsum([0;p])) imag(c)])-min(k)+1,1),"holes"))

Essayez-le sur Octave Online!

Modifié pour une meilleure visualisation.

Explication:

%compute position of walls
c= cumsum([0;p]) % p should be top padded with a 0
row = real(c);
col = imag(c);
k = [row col];

%offset positions so all positions become positive
pos = k - min(k) +1;
%create a binary array that is 1 for walls and 0 elsewhere
bin = ~~accumarray(pos,1);

        *******   
              *   
              *   
              *   
              *   
         *********
  ****   *    *  *
  *  *   *    *  *
  *  *   *    *  *
  *  *   ******  *
  *  *           *
  *  *           *
******           *
  *              *
  *              *
  ****************

%use flood fill to fill holes
filled = bwfill(bin, 'holes');

        *******   
              *   
              *   
              *   
              *   
         *********
  ****   ******  *
  ****   ******  *
  ****   ******  *
  ****   ******  *
  ****           *
  ****           *
******           *
  *              *
  *              *
  ****************

%count number of ones in the filled image 
result = nnz(filled) 
rahnema1
la source
2

Haskell, 579 530 octets

y=length
i=filter
u i e l=take i l++[e]++drop(i+1)l
k v(r,c)g=u r(u c v(g!!r))g
b(r,c)g=g!!r!!c
w(r,c)s g=case s of{""->j;'<':t->w(r,c-1)t j;'>':t->w(r,c+1)t j;'v':t->w(r+1,c)t j;'^':t->w(r-1,c)t j}where j=k 2(r,c)g
e[]v g=g;e(x:d)v g|elem x v||b x g/=1=e d v g|b x g==1=e(d++(i(\x->notElem x v)$i(\(r,c)->r>=0&&c>=0&&r<y g&&c<y(g!!0))$a x))(x:v)(k 0 x g)
a(r,c)=[(r+1,c+1),(r+1,c),(r+1,c-1),(r,c+1),(r,c-1),(r-1,c+1),(r-1,c),(r-1,c-1)]
m s=(y.i(/=0).concat.e[(0,0)][])(w(l+1,l+1)s(map(\_->map(\_->1)q)q))where l=y s;q=[0..2*l+2]

mest la fonction principale, qui prend une chaîne v^<>et retourne l'entier approprié.

Non golfé:

import Data.Set hiding (map, filter)

-- Generate a grid full of ones, of width and height 2x+1. We pass the length of
-- the input, and get back a grid that we could never go out of bounds from,
-- even when the input is a straight wall in any direction.
genGrid :: Int  -> [[Int]]
genGrid x = map (\_->map(\_->1) [0..2*x+2]) [0..2*x+2]

-- Update the value of a list l, such that index i now contains the value e
update :: Int -> a -> [a] -> [a]
update i e l = take i l ++ [e] ++ drop (i+1) l

-- scale update to two dimensions
set :: a -> (Int, Int) -> [[a]] -> [[a]]
set val (r,c) g = update r (update c val (g !! r)) g

-- index into a 2D array
at :: (Int, Int) -> [[a]] -> a
at (r,c) g = g !! r !! c

-- Walk the wall path. Replace any 1 we step on with a 2. Start walking from
-- given coordinates, recursively updating the spot we step on as we process
-- the input string.
walk :: (Int, Int) -> String -> [[Int]] -> [[Int]]
walk (r,c) s g = case s of
    "" -> set 2 (r,c) g
    '<':t -> walk (r,c-1) t (set 2 (r,c) g)
    '>':t -> walk (r,c+1) t (set 2 (r,c) g)
    'v':t -> walk (r+1,c) t (set 2 (r,c) g)
    '^':t -> walk (r-1,c) t (set 2 (r,c) g)

-- Given an input string, generate a grid of appropriate size and walk out the
-- wall path starting at the center.
sketch :: String -> [[Int]]
sketch s = let l = length s in walk (l+1,l+1) s (genGrid l)

-- Breadth-first exploration of the 2D grid, but do not pass through walls.
-- Will touch everything that's not part of the land, and mark it as not part
-- of the land. We use a set (a list in the golfed version) to keep track
-- of which coordinates we've already explored.
explore :: [(Int, Int)] -> Set (Int, Int) -> [[Int]] -> [[Int]]
explore [] v g = g
explore (x:cs) v g
    | member x v  = explore cs v g
    | at x g == 2 = explore cs v g
    | at x g == 0 = explore cs v g
    | at x g == 1 =
        explore (cs ++ (filter (\x-> notMember x v) $ filtBound g $ adj x))
            (insert x v) (set 0 x g)

-- Count everything marked as land to get the final total
countLand :: [[Int]] -> Int
countLand = length . filter (/=0) . concat

-- for a given list of coordinates and a 2D grid, filter those coordinates that
-- are within the grid's bounds
filtBound :: [[Int]] -> [(Int, Int)] -> [(Int, Int)]
filtBound g = filter (\(r,c) -> r >= 0 && c >= 0 && r < length g && c < length (g !! 0))

-- Given a coordinate, get all the adjacent coordinates, including diagonally
-- adjacent coordinates.
adj :: (Int, Int) -> [(Int, Int)]
adj (r,c) = [(r+1,c+1),(r+1,c),(r+1,c-1),(r,c+1),(r,c-1),(r-1,c+1),(r-1,c),(r-1,c-1)]

-- The main function
runMain :: String -> Int
runMain = countLand . explore [(0,0)] empty . sketch

-- Print a grid (for debugging & REPL convenience)
printG :: [[Int]] -> String
printG = concat . map ('\n':) . map show
AlexJ136
la source
2

Mathematica, 124 octets

Vous ne serez probablement pas surpris d'apprendre que Mathematica a une fonction intégrée pour mesurer la zone entourée par un mur. Malheureusement, il est tout à fait bytey: ComponentMeasurements[..., "FilledCount", CornerNeighbors -> False].

Dans cet esprit, voici ma réponse complète. C'est une fonction qui prend une liste de 1, i, -1 ou -i:

1/.ComponentMeasurements[SparseArray[{Re@#,Im@#}&/@FoldList[#+#2&,2(1+I)Length@#,#]->1],"FilledCount",CornerNeighbors->1<0]&

Explication:

  • FoldList[#+#2&,2(1+I)Length@#,#]construit le mur en commençant à la coordonnée 2 (1 + i) (longueur du mur) et en ajoutant successivement les éléments de la liste d'entrée. (Nous devons commencer par la coordonnée ridiculement grande 2 (1 + i) (longueur du mur) pour nous assurer que les coordonnées du mur restent positives, sinon les choses se brisent.)
  • SparseArray[{Re@#,Im@#}&/@...->1] transforme ces coordonnées de nombres complexes en paires d'entiers, et crée un tableau avec 1s où le mur est et 0s ailleurs.
  • 1/.ComponentMeasurements[...,"FilledCount",CornerNeighbors->1<0]& utilise la magie Mathematica intégrée pour mesurer la zone délimitée par le mur.
Pas un arbre
la source
"Nous devons commencer à la coordonnée ridiculement grande ..." bonne astuce!
rahnema1
1

PHP> = 5.6.2, 888 octets

Version en ligne

<?$h=$v=0;
s($v,$h,S);
for($z=0;$z<strlen($i=$_GET[0]);){
2<($b=$i[$z++])?$h--:($b>1?$v++:($b?$h++:$v--));
$e=max($h,$e);
$w=min($h,$w);
$n=min($v,$n);
$s=max($v,$s);
s($v,$h,X);}
$f=($e-$w+1)*($s-$n+1);
ksort($a);
function i($v,$h){global$a;return isset($a[$v][$h])&&$a[$v][$h]==" ";}
function s($v,$h,$l=" "){global$a;$a[$v][$h]=$l;}
function c($v,$h,$n=1){global$a;
foreach($r=range(-1,$n)as$i)
foreach($r as$j)
if(($i+$j)&&i($v+$i,$h+$j)){if($n)s($v,$h);return 1;}return;}
foreach($a as$v=>$z){
foreach(range($w,$e)as$h){
if(!isset($a[$v][$h])){
if(($v==$s)||($v==$n)||($h==$e)||($h==$w)||c($v,$h,0))s($v,$h);
else$c[]=[$v,$h];}
}ksort($a[$v]);}
while($z){$z=0;
foreach($c as$b=>$w){if(c(...$w)){$z++;unset($c[$b]);}}};
foreach($c as$b=>$w)$a[$w[0]][$w{1}]=O;
foreach($a as $k=>$v){ksort($a[$k]);$g.=join($a[$k])."\n";}echo $g;
echo $f-substr_count($g," ");
Jörg Hülsermann
la source
Vous savez que vous n'aviez qu'à produire la taille du terrain, pas le terrain lui-même, n'est-ce pas? :)
Stewie Griffin
@StewieGriffin c'est la sortie "echo $ g; "du terrain. J'ai trouvé cette approche et peut-être qu'elle existe d'une autre manière plus courte. Si j'ai trouvé cette façon, je peux améliorer ce post
Jörg Hülsermann