Roguelike için bir harita oluşturun


10

Bugün, roguelike bir RPG için bir harita oluşturacağız!

Örnek Harita:

##########
####    F#
####    ##
##    C#C#
#     ## #
# C   #E #
####  #  #
#        #
#P       #
##########

#duvarlar, Poyuncunun başlangıç ​​yeri, Fulaşılması gereken bitiş,C toplanabilen paralar ve Esavaşılabilecek düşmanlardır.

Harita özellikleri:

  • Yükseklik ve Genişlik, 10 ile 39 arasında olmalıdır. Yüksekliğin eşit genişliğe sahip olması gerekmez.
  • Harita sınırları duvarlarla doldurulmalıdır.
  • P sol alt köşeye yerleştirilmelidir.
  • F sağ üst köşeye yerleştirilmelidir.
  • 1 ila 3 düşman olmalıdır.
  • 2 ila 4 madeni para olmalıdır.
  • Ortada bir miktar duvar olmalı. Dan almak için bir yol olmalıdır PEvery için C, EveF akılda tutarak oyuncu çapraz hareket edemez.
  • Her olası kombinasyonun gerçekleşme şansı olmalıdır.

kurallar

  • En az bayt programı kazanır.
  • Programınız herhangi bir girdi almamalıdır.
  • Programınız bir hata ile çıkmayabilir (ölümcül olmayan çıktı STDERR tamam, ancak harita oluşturulduktan sonra haydut benzeri çökme yapamayız!)
  • Tek bir sondaki yeni satıra izin verilir ve sondaki alana izin verilir.
  • Başka çıkışa izin verilmez.

3
Roguelike, sadece fyi.
Rɪᴋᴇʀ

2
"Her olası kombinasyonun eşit olarak meydana gelme şansı olması gerektiğini" açıklayabilir misiniz? Kelimenin tam anlamıyla, tüm geçerli haritaların (özellikle P'nin tüm C / E / F'lere ulaşabildiği tüm haritaların) eşit olasılıkla gerçekleşmesi gerektiği anlamına mı geliyorsunuz? Eğer öyleyse, mümkün olan tek algoritma rastgele düzgün bir şekilde haritalar oluşturmak ve sonra P'nin her şeye ulaşıp ulaşamayacağını kontrol etmek ve bu gerçekleşene kadar geçersiz haritaları atmak gibi görünüyor.
Greg Martin

Ayrıca "Ortada bir miktar duvar olmalı" diyebilir misiniz? Ya her zaman sadece 2 duvar yerleştirirsem?
Gurupad Mamadapur

1
@GregMartin Bunu ben de değiştireceğim, "Her olası düzenin meydana gelme şansı olmalı", mutlaka eşit bir şans değil.
Pavel

2
Duvarlarla çevrili ulaşılamaz boş karelere ne dersiniz? Geçerli bir düzen mi yoksa tamamen önlenmeli mi? (Başka bir deyişle: her boş kareye ulaşılabilir mi?)
Arnauld

Yanıtlar:


5

Perl, 293 bayt

@Dom Hastings sayesinde -9 bayt

{$==7+rand 30;@r=$"=();@a=((C)x4,(E)x3,("#")x1369,(" ")x1369);for$i(0..7+rand 30){$r[$i][$_]=splice@a,rand@a,1for 0..$=}$r[0][$=]=F;$r[-1][0]=P;$_=$r=join$/,$v="#"x($=+=3),(map"#@$_#",@r),$v;1while$r=~s/F(.{$=})?[^#F]/F$1F/s||$r=~s/[^#F](.{$=})?F/F$1F/s;$r!~/[CEP]/&&/C.*C/s&&/E/?last:redo}say

-EÇalıştırmak için bayrak ekleyin :

perl -E '{$==7+rand 30;@r=$"=();@a=((C)x4,(E)x3,("#")x1369,(" ")x1369);for$i(0..7+rand 30){$r[$i][$_]=splice@a,rand@a,1for 0..$=}$r[0][$=]=F;$r[-1][0]=P;$_=$r=join$/,$v="#"x($=+=3),(map"#@$_#",@r),$v;1while$r=~s/F(.{$=})?[^#F]/F$1F/s||$r=~s/[^#F](.{$=})?F/F$1F/s;$r!~/[CEP]/&&/C.*C/s&&/E/?last:redo}say'

Ancak, çalışması uzun zaman alıyor, bu yüzden bunun yerine bu sürümü kullanmanızı öneririz:

perl -E '{${$_}=8+rand 30for"=","%";@r=$"=();@a=((C)x4,(E)x3,("#")x($v=rand $=*$%),(" ")x($=*$%-$v));for$i(0..$%-1){$r[$i][$_]=splice@a,rand@a,1for 0..$=-1}$r[0][$=-1]=F;$r[$%-1][0]=P;$_=$r=join$/,$v="#"x($=+=2),(map"#@$_#",@r),$v;1while$r=~s/F(.{$=})?[^#F]/F$1F/s||$r=~s/[^#F](.{$=})?F/F$1F/s;$r!~/[CEP]/&&/C.*C/s&&/E/?last:redo}say'

Çevrimiçi deneyin!

açıklama

{ # bir blok girin (döngü olarak kullanılır) { $ == 7 + rand 30 ; # haritanın genişliğini rastgele seçin -2 # (-2 çünkü sınırları henüz eklemiyoruz ) @r = $ "= (); # reset @r ve $" değerini undef @a = ( # create olarak ayarlayın tahtada olabilecek karakterin bir listesi ( C ) x4 , # 4 jeton 'C' ( E ) x3 , # 3 düşman 'E' ( "#" ) x1369 , # 37 * 37 '#' "                     
                       
                                     
    
                                 
                               
                               
                          
      ( ) x1369 } 
    $ r [); # 37 * 37 boşluklar için $ i ( 0..7 + rand 30 ) # 2B haritası oluşturmak (7 Rand 30 şimdi oluşturulur yüksekliği ise +) için $ _ ( 0. . $ = - 1 ) { 
        $ r [ $ i ] [ $ _ ] = # dizin [$ i] [$ _] ... 
           eki @ a , rand @ a , 1 # .. daha önce oluşturulan # listesinden rastgele bir karakter alıyor (karakter daha sonra 'ekleme' sayesinde listeden çıkarıldı) } 0 $ =] = F ;                    
                     
                                     
                                       
      
     ] [                       # bitiş hücresini ekleyin 
    $ r [- 1 ] [ 0 ] = P ; # Eklemek başlangıç hücre 
    $ _ = $ r = # burada haritanın bir dize temsilini oluşturmak 
          katılmak $ /, # yeni satırlar ile aşağıdaki unsurları katılmak 
            $ v = "#" x ( $ = + = 3 ), # birinci # hattı sadece ( map "# @ $ _ #" , @r ), # başında ve her satırın sonuna bir # eklemek                                                                                      
                       
            $ v ; # # satırının son satırı                        

    1 # aşağıdaki regex, erişilebilir her hücreyi F 
       $ r = ~ s / F (. { $ =}) İle değiştirir ? [^ # F ] / F $ 1F / s   # bir F hücresi değiştirilir   || # veya 
       $ r = ~ s / [^ # F ] (. { $ =})? F / F $ 1F / s ; # F hücresinin solundaki veya üstündeki bir hücre değiştirilir 
    $ r ! ~ / [CEP] / # Haritada C, E veya P yoksa (hepsinin erişilebilir olduğu anlamına gelir)                
                                            
      && /C.*C/ s          # ve en az 2 jeton var && / E / ? # Ve 1 düşman son : haritası geçerlidir #, biz döngü çıkmak kokan başka # baştan başlamak } 
söylemek                      # ve tahta baskı
                  
                   
                    

Çalıştırmak uzun zaman alıyor, çünkü tahtaya koymak için rastgele karakterler seçtiğimiz liste ( @a) 1369 boşluk #ve sadece 4 sikke ve 3 düşman içeriyor . Genişlik ve yüksekliğin boyutu küçükse, #madeni para ve düşmanlarla karşılaştırıldığında çok fazla alan vardır , bu yüzden rastgele bir haritanın geçerli olmayacağı muhtemeldir. "Optimize" sürüm daha hızlı olmasının nedeni budur: Biz karakterleri almak hangi liste haritadan daha sadece biraz daha büyük (listesidir @a=((C)x4,(E)x3,("#")x($v=rand $=*$%),($")x($=*$%-$v)): rastgele bir sayı $vait #haritanın büyüklüğüne aşağı () ve size of the map - $vboşlukların).


Gerçekten perl bilmiyorum, ancak sözdizimi vurgulama bakarak ($ ​​") x $ = ** 2) eşsiz bir teklif var gibi görünüyor. Dışarı belki vurgulama işe yaramaz ve bu bir özellik. , boşluklara ulaşılamaz
Pavel

1
@Pavel $"yasal bir Perl değişkeni, ancak sözdizimi vurgulaması bunu bilmiyor, bu yüzden böyle görünüyor. Tamam, ulaşılamayan alanlarla ilgili yorumu sileceğim.
Dada

5

PHP, 422 417 415 309 373 369 364 361 bayt

function w($p){global$r,$h,$w;for($q=$p;$r[$q]<A;)for($r[$p=$q]=" ";($q=$p+(1-(2&$m=rand()))*($m&1?:$w))%$w%($w-1)<1|$q/$w%$h<1;);}$r=str_pad("",($w=rand(10,39))*$h=rand(10,39),"#");$r[$w*2-2]=F;w($p=$q=$w*(--$h-1)+1);$r[$p]=P;for($c=rand(2,4);$i<$c+rand(1,3);$p=rand($w,$h*$w))if($r[$p]<A&&$p%$w%($w-1)){w($p);$r[$p]=EC[$i++<$c];w($p);}echo chunk_split($r,$w);

satır sonu olmayan bir dizede çalışır; ekstralar arasındaki rastgele yolları kazar. Şununla koş:-r .

Not: Yollar rastgele yönlerde yürüyerek oluşturulur. Her adım için yön seçimi çoğunlukla açık olan haritalar oluşturur; ve örnek haritanın görünmesi pek olası değildir; ama bir mümkün.

Yıkmak

// aux function: randomly walk away from $p placing spaces, stop when a special is reached
function w($p)
{global$r,$h,$w;
    for($q=$p;
        $r[$q]<A;                               // while $q is not special
    )
        for($r[$p=$q]=" ";                          // 3. replace with space
            ($q=$p+(1-(2&$m=rand()))*($m&1?:$w))    // 1. pick random $q next to $p
            %$w%($w-1)<1|$q/$w%$h<1;                // 2. that is not on the borders
        );
}

// initialize map
$r=str_pad("",
    ($w=rand(10,39))*$h=rand(10,39) // random width and height
    ,"#");                          // fill with "#"
$r[$w*2-2]=F;                       // place Finish
w($p=$q=$w*(--$h-1)+1);             // build path from Player position to F
// $h is now height -1 !
$r[$p]=P;                           // place Player

// place Coins ans Enemies
for($c=rand(2,4);$i<$c+rand(1,3);   // while $i has not reached no. of coins+no. of enemies
    $p=rand($w,$h*$w))              // pick a random position
    if($r[$p]<A&&$p%$w%($w-1))      // that is neither special nor out of bounds
    {
        w($p);                      // build path from there to another special
        $r[$p]=EC[$i++<$c];         // place this special
        w($p);      // additional path to allow special in the middle of a dead end tunnel
    }

// insert linebreaks and print
echo chunk_split($r,$w);

Açıklamanızda 39'a değil 37'ye yükseklik ve genişlik üretiyorsunuz.
Pavel

@Pavel düzeltildi; teşekkür için teşekkürler
Titus

Denediğimde kendi kaynak kodunu çıkar Çevrimiçi deneyin
Pavel

@Pavel kodu çevrelemeniz gerekiyor<?php .... ?>
Dada

1
Tamam, bunu yaptım ve duvarların düzenli dikdörtgen parçalar halinde üretildiğini fark ettim. Örnek harita gibi bir şey üretebilmelidir. Ayrıca her zaman Es üretmez.
Pavel

3

C # (Visual C # Etkileşimli Derleyici) , 730 bayt

var R=new Random();for(;;){char P='P',C='C',E='E',Q='#';int w=R.Next(8,37),h=R.Next(8,37),H=h,t,g=99,W,i,j,r;string l,s,p=new string(Q,w+2);var m=new List<string>();for(;H>0;H--){l="";for(W=w;W>0;W--){r=R.Next(999);l+=r<3?C:r<6?E:r<g?Q:' ';}m.Add(l);}m[0]=m[0].Substring(0,w-1)+'F';m[h-1]=P+m[h-1].Substring(1);s=String.Join("#\n#",m);t=s.Split(E).Length-1;if(t<1||t>3)continue;t=s.Split(C).Length-1;if(t<2||t>4)continue;while(g>0){g--;for(i=0;i<h;i++)for(j=0;j<w;j++)if(m[i][j]!=Q&&m[i][j]!=P&&(i>0&&m[i-1][j]==P)||(i<h-1&&m[i+1][j]==P)||(j>0&&m[i][j-1]==P)||(j<w-1&&m[i][j+1]==P))m[i]=m[i].Substring(0,j)+P+m[i].Substring(j+1,w-j-1);}if(String.Join("",m).Split(E,C,'F').Length>1)continue;Console.Write(p+"\n#"+s+"#\n"+p);break;}

Çevrimiçi deneyin!

Ungolfed:

var R = new Random();
for (;;)
{
    char P = 'P', C = 'C', E = 'E', poundSymbol = '#';
    int width = R.Next(8, 37), height = R.Next(8, 37), HeightTemp = height, testVariable, goThroughLoop = 99, WidthTemp, i, j, rand;
    string line, strMap, poundSymbolPadding = new string(poundSymbol, width + 2);

    var map = new List<string>(); //initialize map
    for (; HeightTemp > 0; HeightTemp--)
    {
        line = "";
        for (WidthTemp = width; WidthTemp > 0; WidthTemp--)
        {
            rand = R.Next(999);
            //add a character randomly.  Re-use the goThroughLoop variable here, which gives approx. 1 wall per 10 spaces.
            line += rand < 3 ? C : rand < 6 ? E : rand < goThroughLoop ? poundSymbol : ' ';
        }
        map.Add(line);
    }
    //add finish and player
    map[0] = map[0].Substring(0, width - 1) + 'F';
    map[height - 1] = P + map[height - 1].Substring(1);

    strMap = String.Join("#\n#", map);
    //check proper # of enemies, regenerate if invalid
    testVariable = strMap.Split(E).Length - 1;
    if (testVariable < 1 || testVariable > 3)
        continue;
    //check proper # of coins, regenerate if invalid
    testVariable = strMap.Split(C).Length - 1;
    if (testVariable < 2 || testVariable > 4)
        continue;
    //map out areas Player can access.  Iterates until all accessible places have been marked as such.
    while (goThroughLoop > 0)
    {
        goThroughLoop--;
        for (i = 0; i < height; i++)
            for (j = 0; j < width; j++)
                if (map[i][j] != poundSymbol && map[i][j] != P && ((i > 0 && map[i - 1][j] == P) || (i < height - 1 && map[i + 1][j] == P) || (j > 0 && map[i][j - 1] == P) || (j < width - 1 && map[i][j + 1] == P)))
                    //mark this space as accessible
                    map[i] = map[i].Substring(0, j) + P + map[i].Substring(j + 1, width - j - 1);
    }
    //if player cannot access all features (defeated enmies, collected coins, arrived at finish), regenerate map.
    if (String.Join("", map).Split(E, C, 'F').Length > 1)
        continue;

    //output our final map
    Console.Write(poundSymbolPadding + "\n#" + strMap + "#\n" + poundSymbolPadding);

    break;
}

Düzenleme: 8 bayt kaydedildi, oynatıcıya erişilebilir test döngüsünü 99 yinelemeye kilitleyerek biraz daha az verimli hale getirdi. Buradaki diğer cevaplarla asla gerçekten rekabet etmeyeceğini biliyorum, ama eğleniyorum!


@GregMartin Şimdi F # ;-)
Bence Joful

2
Subdominant için basit bir modülasyon, sorun yok :)
Greg Martin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.