Placement de coffre Minecraft

20

Le jeu vidéo Minecraft consiste à placer et à supprimer différents types de blocs dans le réseau entier 3D qui compose le monde virtuel. Chaque point de réseau peut contenir exactement un bloc ou être vide (un bloc " aérien " officiellement). Dans ce défi, nous ne nous occuperons que d'un seul plan 2D horizontal du monde 3D, et d'un type de bloc: les coffres .

Les coffres permettent aux joueurs de stocker des objets. Lorsque deux coffres sont orthogonalement adjacents dans le même plan horizontal, leurs textures s'unissent et un coffre double avec deux fois la forme se forme. Rien de plus grand qu'un double coffre ne peut être fait; il n'y a pas de coffres triples ni de coffres quadruples.

Un bloc thoracique ne peut être placé dans un point de réseau vide que si ses quatre points adjacents orthogonalement sont tous vides, ou si exactement l'un contient un bloc thoracique qui ne fait pas déjà partie d'un double coffre. Ces règles de placement garantissent qu'il ne peut jamais y avoir d'ambiguïté sur les blocs de poitrine qui se lient pour former des doubles coffres.

Par exemple, supposons qu'il .s'agit d'un espace vide et d' Cun coffre: (Les chiffres sont également des espaces vides et uniquement à des fins d'identification.)

.......C..
.1.C2.C3..
........5C
.CC4..CC..
..........
  • Un coffre peut être placé à l'emplacement 1 car ses 4 voisins sont vides.
  • Un coffre peut être placé au point 2 car le coffre voisin ne fait pas (encore) partie d'un coffre double.
  • Un coffre ne peut pas être mis en place 3 car il y aurait ambiguïté sur la façon dont le double coffre se forme.
  • Un coffre ne peut pas être placé au point 4 car le coffre voisin fait déjà partie d'un coffre double.
  • Un coffre peut être placé à l'endroit 5. Le double coffre voisin en diagonale n'affecte rien.

En supposant que la zone au-delà de la grille est vide, changer chaque .dans la grille en *si un coffre pourrait y être placé entraîne ceci:

******.C**
***C**C.**
*..***..*C
.CC.*.CC.*
*..***..**

*Bien sûr, tous les espaces ne peuvent pas être occupés par des coffres en même temps, mais si vous n'aviez qu'un seul coffre, il pourrait être placé dans l'un d'eux.

Défi

Ecrire un programme ou une fonction qui prend une .et Cgrille et change tous .à un *si un coffre pourrait être placé là, l' impression ou de retourner la grille résultante.

  • L'entrée peut provenir de stdin ou d'un fichier ou comme argument de chaîne pour une fonction.

  • Vous pouvez supposer que l'entrée est bien formée - c'est-à-dire une grille de texte parfaitement rectangulaire, d'au moins 1 caractère de large et de haut, contenant uniquement .et Cvous pouvez éventuellement supposer qu'il y a un retour à la ligne après la dernière ligne (et il peut y en avoir un dans la sortie ).

  • Vous pouvez supposer que la disposition des coffres dans l'entrée est conforme aux règles ci-dessus. Il n'y aura jamais d'ambiguïtés sur les coffres qui forment des coffres doubles.

  • Si vous le souhaitez, vous pouvez utiliser tous les trois distincts ASCII imprimables caractères à la place ., Cet *. Vous ne pouvez pas utiliser autre chose à la place des nouvelles lignes.

  • Tous les coffres sont des coffres normaux. Coffres non piégés ou coffres ender .

Notation

La soumission avec le moins d'octets est gagnante.

Pour un défi lié à Minecraft qui est un peu plus difficile, essayez la détection de portail Nether .

Loisirs de Calvin
la source
5
D'un point de vue Minecrafting, j'ai trouvé ce jeu assez ennuyeux.
Heureusement
Lorsque vous prenez une entrée de grille depuis stdin ou un argument de chaîne unique, est-il acceptable de prendre les dimensions de la grille comme entrée supplémentaire? ou doit-il être déduit des sauts de ligne et de la longueur des chaînes?
Level River St
@steveverrill Il faut en déduire.
Calvin's Hobbies
Par simple curiosité, pourquoi chaque réponse, y compris la mienne, a-t-elle un downvote? Je peux seulement supposer que c'est la même personne, voudraient-ils expliquer?
Level River St
Pour un défi supplémentaire, on pourrait écrire un programme pour trouver le placement optimal pour les coffres; c'est-à-dire trouver une configuration qui permet de placer le nombre maximum de coffres supplémentaires sans enfreindre les règles, même entre les nouveaux coffres.
AJMansfield

Réponses:

11

CJam, 82 76 66 62 58 54 octets

qN/::~4{[8_]f/[9_]f*z{[{1$8-g)+}*]W%}%}*{_8<\2<8?}f%N*

Le format d'entrée attend 0une cellule d'air et 8une cellule thoracique. La sortie contient 1pour toutes les cellules qui peuvent être placées avec un coffre.

MISE À JOUR : correction d'un bug. Augmenté de 3 octets :( golfé plus loin :). 4 octets enregistrés grâce à @ Sp3000

Exemple d'entrée:

0000000800
0008008000
0000000008
0880008808
0000000000

Production:

1111110811
1110018010
1008800108
0880088008
1008800110

Je pense que j'ai fini de jouer au golf pour l'instant ...

Explication

qN/::~                   "This part converts the input into array of integer array";
qN/                      "Split input on new line";
   ::~                   "Parse each character in each row as integer";

4{[8_]f/[9_]f*z{[{1$8-g)+}*]W%}%}*

4{   ...z{       W%}%}*  "Run the logic 4 times, first, columns in correct order, then,";
                         "columns in reverse order, then for rows";
  [8_]f/[9_]f*           "Convert adjacent chests represented by two 8 into two 9";
                         "This happens for all the rows in the columns iterations and";
                         "for all the columns in the rows iterations";
  {               }%     "For each row/column";
   [{        }*]         "Reduce and wrap it back in the array";
     :I8-                "Store the second number in I, remove 8 from it";
         g               "Do signum. Now we have -1 for < 8 number, 0 for 8 and 1 for > 8";
          )+I            "Increment to get 0, 1 & 2. Add it to first number and put I back";

{_8<\2<8?}f%N*           "This part converts the output from previous iterations";
                         "to 3 character based final output and prints it";
{        }f%             "Map each row using the code block";
 _8<   8?                "If the value is greater than 7, make it 8, else:";
    \2<                  "If the value is greater than 1, make it 0, else 1";
            N*           "Join the arrays using new line";

Essayez-le en ligne ici

Optimiseur
la source
8

.NET Regex ( rétine ), 434 416 310 + 1 = 311 octets

Après le dernier défi auquel j'ai répondu en regex (le défi du portail Nether lié à ce défi), j'ai finalement décidé d'écrire un outil de ligne de commande, qui agit comme un interprète pour les expressions régulières de style .NET, afin que je puisse répondre aux questions avec regex sans être mis au défi qu'ils ne sont pas une langue autonome. Je l'ai nommé Retina.

Maintenant, ce défi ne se prête pas très bien à une soumission regex, mais je devais utiliser Retina maintenant. ;) (De plus, Sp3000 m'a mis au défi de le faire dans le chat.) Voici donc:

Fichier regex

m`(?<=(?=.(.)*).*)(?<=((?<=(?<2>C|C(?(1)!)(\n|(?<-1>.))*)?)C(?=(?<2>C|(\n|(?<-1>.))*(?(1)!)C)?)(()(?(6)!)|(?<=^(?(7)!)(?<-7>.)*C).*\n(.)*()(?(8)!)))?){2}_(?=(?<2>((?(10)!)()|(?(11)!)()(.)*\n.*(?=C(?<-12>.)*(?(12)!)$))(?<=(?<2>C|C(?(1)!)(\n|(?<-1>.))*)?)C(?=(?<2>C|(\n|(?<-1>.))*(?(1)!)C)?))?){2}(?<-2>)?(?(2)!)

Fichier de remplacement

*

Le fichier regex est principalement juste le regex, sauf qu'il `vous permet de mettre quelques options dans le fichier, dans ce cas simplement le mode multiligne. Lorsqu'on lui donne deux fichiers, Retina assume automatiquement le mode de remplacement complet. Ces deux fichiers définissent un programme qui lit l'entrée de STDIN et imprime le résultat dans STDOUT.

Vous pouvez également le tester sur RegexHero et RegexStorm . Le regex fonctionne à la fois avec et sans retour à la ligne et utilise _à la place de .. (Apparemment, RegexStorm a parfois des problèmes s'il n'y a pas de nouvelle ligne de fin, mais RegexHero semble bien gérer les deux cas.)

Il y a une horrible quantité de duplication dans l'expression régulière, et j'ai quelques idées pour le raccourcir considérablement ... Je vais essayer un peu plus tard, puis ajouter une explication. En attendant, faites-moi savoir si vous pouvez trouver des entrées qui donnent un mauvais résultat.

Martin Ender
la source
7

J, 75 73 octets

((,.|.)0 _1 0 1)(+:@](LF,@:,.~'*.C'{~>.)(2=f)+.[f]*f=.[:+/|.!.0)'C'&=;._2

Utilise le format de la question, en utilisant ./ */ Cpour l'espace / espace utilisable / coffre, respectivement.

Edit: corrige un petit bug (j'ai accidentellement utilisé un tore au lieu de traiter correctement l'environnement comme un espace vide).

Explication

## Preparation
              'C'&=;._2  NB. Map ./C to 0/1, turn into matrix
((,.|.)0 _1 0 1)         NB. Compute offsets to shift into each direction
                         NB. (i.e. [[_1 0], [1 0], [0 _1], [0 1]] in any order)


## "Part B"
(2=f)+.[f]*f=.[:+/|.!.0  NB. This part computes a matrix that is 1 for cells that
                         NB. cannot contain a chest:
              [:+/|.!.0  NB. Sum of shifts: shift in each of the four cardinal
                         NB. directions (using the array above) and then sum up.
           f=.           NB. Define this function as `f`; we'll use it some more.
         ]*              NB. Multiply by the "is chest" matrix: this isolates
                         NB. double-chests.
       [f                NB. Sum of shifts--1 for double-chest neighbours.
(2=f)                    NB. Isolate cells with two neighbouring chest.
     +.                  NB. Boolean or--either two neighbouring chests or next
                         NB. to a double-chest.

## Wrap up the result
(+:@] (fmt >.) PartB)    NB. Maximum of the array from the above and twice the "is
 +:@]      >.  PartB     NB. chest" matrix--this is 0,1,2 for '*', '.' or chest,
                         NB. respectively.

## Output formatting
LF,@:,.~'*.C'{~          NB. Format output...
        '*.C'{~          NB. Map 0,1,2 to '*.C' by using the value as index
LF   ,.~                 NB. Append line feed at end of each line
  ,@:                    NB. Ravel into one line
Luciole
la source
4

C, 193

2 nouvelles lignes inutiles pour plus de clarté. Les changements par rapport au code non golfé incluent: les caractères en tant que codes ascii au lieu des littéraux de caractères; réarrangement de v = 0, strlen et strchr pour enregistrer les caractères (strchr est le plus laid, car cela signifie qu'un calcul qui ne serait autrement effectué qu'une seule fois, est effectué 5 fois par cellule!)

Les fonctions C n'acceptent pas les chaînes comme arguments ou ne les renvoient pas comme valeurs, donc le mieux que je puisse faire est le suivant: qest un pointeur vers la chaîne d'entrée. La fonction modifie la chaîne et lorsque la fonction retourne la sortie se trouve dans la chaîne d'origine.

g(char*q){int v,j,w,l;
int f(p,d){int s=0,i=w=strchr(q,10)-q+1,r;for(;w/i;i-=i-1?w-1:2)r=p+i,r>-1&r<l&&q[r]==67&&++s&&d&&f(r,0);v|=s>d;}
for(j=l=strlen(q);j--;f(j,1),46-q[j]||v||(q[j]=42))v=0;}

Pour résumer les règles:

un carré vide (qui ne contient ni C ni nouvelle ligne) peut être converti s'il a max 1 voisin avec un C

... ET ce voisin n'a pas de voisins avec un C.

La fonction g contient une fonction f qui revient de la profondeur 1 à la profondeur 0. Avec seulement 2 niveaux de récursivité, un simple f(r,0)appel récursif fera l'affaire, il n'y a pas besoin de f(r,d-1)!

Code non golfé dans le programme de test

La chaîne de test d'entrée est codée en dur. getset scanfn'acceptera pas une chaîne d'entrée contenant des retours à la ligne; ils le coupent en morceaux à chaque nouvelle ligne.

char n[]=".......C..\n...C..C...\n.........C\n.CC...CC..\n..........";

g(char*q){

  int v,j,w,l;

  int f(p,d){                    //p=cell to be checked,d=recursion depth
    int s=0,i=w,r;               //sum of C's found so far=0, i=width
    for(;w/i;i-=i-1?w-1:2)       //For i in   w,1,-1,-w   = down,right,left,up
      r=p+i,                     //r=cell adjacent to p
      r>-1&r<l&&q[r]=='C'&&++s   //If r not out of bounds and equal to C, increment s...
        &&d&&f(r,0);             //...and if recursion depth not yet at zero, try again one level deeper. 
    v|=s>d;                      //If the local s exceeds d, set global v to true to indicate invalid.
  }

  w=strchr(q,10)-q+1;            //width equals index of first newline + 1                   
  l=strlen(q);                   //length of whole string;
  for(j=l;j--;)                  //for l-1 .. 0 
    v=0,                         //clear v
    f(j,1),                      //and scan to see if it should be set
    '.'-q[j]||v||(q[j]='*');     //if the character is a '.' and v is not invalid, change to '*'
}

main(){
  g(n);
  puts(n);
}

Sortie basée sur l'exemple de question

******.C**
***C**C.**
*..***..*C
.CC.*.CC.*
*..***..**
Level River St
la source
1

JavaScript (ES6) 124 129

Utilisation des caractères 0 (*), 6 (C), 7 (.)

F=s=>[for(c of(d=[o=~s.search('\n'),-o,1,i=-1],s))
   d.map(j=>t-=s[i+j]==6&&~d.some(k=>s[i+j+k]==6),t=i++)|c<7|t>i&&c
].join('')

Non golfé et expliqué

F=s=>
{
  o=~s.search('\n') // offset to prev row (~ is shorter than +1 and sign does not matter)
  d=[o,-o,1,-1] // array of offset to 4 neighbors
  i=-1
  result = '' // in golfed code, use array comprehension to build the result into an array, then join it
  for (c of s) // scan each char
  {
    t = i++ // set a starting value in t and increment current position in i
    d.forEach(j => // for each near cell, offset in j
    {         
      if (s[i+j]==6) // if cell contains a Chest, must increment t
      {  
        // In golfed code "~some(...)" will be -1(false) or -2(true), using decrement instead of increment
        if (d.some(k=>s[i+j+k]==6)) // look for another Cheast in the neighbor's neighbors
        {
          // more than one chest, position invalid
          t += 2
        }
        else
        {
          t += 1
        }
      }
    })
    if (c < 7 // current cell is not blank
        || t > i) // or t incremented more than once, position invalid
    {
       result += c // curent cell value, unchanged
    }
    else
    {
       result += 0 // mark a valid position 
    }
  }
  return result
}

Tester dans la console Firefox / FireBug

a='\
7777777677\n\
7776776777\n\
7777777776\n\
7667776677\n\
7777777777\n';

console.log(F(a))

Production

0000007600
0006006700
0770007706
7667076670
0770007700
edc65
la source
1

Perl, 66

Les conflits de poitrine correspondant à l'expression rationnelle se sont retrouvés sur le côté long, donc pas de concurrence avec CJam cette fois.

#!perl -p0
/.
/;$"=".{@-}";s%0%s/\G0/2/r!~/2((.$")?2(.$")?|2$"|$"2)2/s*1%eg

Utilise 0 et 2 pour les espaces vides et la poitrine sur l'entrée, 1 pour marquer les taches sur la sortie.

Essayez-le ici .

nutki
la source
0

Python 2 - 281 octets

f=lambda x,y:sum(m[y][x-1:x+2])+m[y-1][x]+m[y+1][x]
m=[];o=''
try:
 while 1:m+=[map(int,'0%s0'%raw_input())]
except:a=len(m[0]);l=len(m);m+=[[0]*a]
for y in range(l*2):
 for x in range(1,a-1):
    if y<l:m[y][x]*=f(x,y)
    else:o+=`2if m[y-l][x]else +(f(x,y-l)<5)`
 if y>=l:print o;o=''

(Les lignes 8 et 9 sont conçues avec un seul caractère de tabulation, que SE convertit en 4 espaces. Chaque ligne de ce programme a soit 0 soit 1 octet d'espaces en tête.)

Entrée: 0pour pas de poitrine, 2pour poitrine
Sortie: 0pour pas de poitrine, 2pour poitrine existante, 1pour une nouvelle poitrine possible


Dieu, c'est horrible. Je dois être sérieusement hors de pratique. J'ai lancé tous les trucs que je connais et il est sorti ... eh bien, il est sorti en 281 octets, perdant à chaque réponse sauf celle en regex , haha. Honnêtement, j'ai l'impression d'avoir bien joué au golf, donc je suppose que mon algorithme était juste loin d'être idéal.

Non golfé:

def f(x,y):
    """Given x,y coords of the board, return the sum of that point and all
    adjacent points.
    """
    return (sum(board[y][x-1:x+2]) # (x-1,y) + (x,y) + (x+1,y)
            + board[y-1][x]
            + board[y+1][x])
board=[]
output=''
try:
    while True:
        row = '0%s0' % raw_input() # line from stdin with a leading and trailing 0
        board.append(map(int, row)) # convert to list of ints
except:
    pass # exception is thrown when stdin is empty

board_width = len(board[0])
board_height = len(board)

board.append([0]*board_width) # new row of all 0s

for y in xrange(board_height*2):
    # board_height multiplied by 2 so we can use this loop to simulate two
    for x in xrange(1,board_width-1):
        if y < board_height: # "first loop"
            board[y][x] *= f(x,y) # multiply everything on the board by itself + sum
                                  # of neighbours
                                  # empty cells (0) stay 0 no matter what
                                  # lone chests (2 surrounded by 0) become 2*2==4
                                  # double chests (2 touching another 2) are weird:
                                  # - one chest becomes 2*(2+2)==8
                                  # - the other chest becomes 2*(2+8)==20
        else: # "second loop"
            if board[y - board_height][x] != 0:
                output += '2' # anything not equal to 0 is an existing chest
            else:
                valid = f(x, y - board_height) < 5 # if the sum of neighbours > 4, the
                                                   # current cell is either beside a
                                                   # double chest or more than one
                                                   # single chest
                output += '01'[valid]
    if y >= board_height: # only print during the "second loop"
        print output
        output=''
métro monorail
la source