रग्गुलाइक के लिए एक मानचित्र तैयार करें


10

आज, हम एक roguelike आरपीजी के लिए एक नक्शा पैदा करेंगे!

उदाहरण का नक्शा:

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

#दीवारें हैं, Pखिलाड़ी का शुरुआती स्थान Fहै, खत्म होना चाहिए जो कि पहुंचना चाहिए, Cसिक्के हैं जिन्हें एकत्र किया जा सकता है, और Eवे दुश्मन हैं जिन्हें लड़ा जा सकता है।

नक्शा विनिर्देशों:

  • ऊंचाई और चौड़ाई दोनों 10 और 39 के बीच होनी चाहिए, समावेशी। ऊँचाई की चौड़ाई समान नहीं है।
  • नक्शे की सीमाओं को दीवारों से भरना चाहिए।
  • P नीचे बाएँ कोने में रखा जाना चाहिए।
  • F शीर्ष दाएं कोने में रखा जाना चाहिए।
  • 1 और 3 दुश्मनों के बीच होना चाहिए।
  • 2 और 4 के सिक्कों के बीच होना चाहिए।
  • बीच में कुछ मात्रा में दीवारें होनी चाहिए। वहाँ एक पथ से प्राप्त करने के लिए किया जाना चाहिए Pहर करने के लिए C, Eऔर Fध्यान में रखते हुए कि खिलाड़ी तिरछे स्थानांतरित नहीं कर सकते।
  • हर संभव संयोजन को होने का कुछ मौका होना चाहिए।

नियम

  • सबसे कम बाइट प्रोग्राम जीतता है।
  • आपके प्रोग्राम को कोई इनपुट नहीं लेना चाहिए।
  • आपका प्रोग्राम एक त्रुटि के साथ बाहर नहीं निकल सकता है (गैर-घातक आउटपुट STDERRठीक है, लेकिन हम पीढ़ी के बाद हमारे बदमाश की तरह दुर्घटनाग्रस्त नहीं हो सकते हैं!)
  • एक एकल अनुगामी न्यूलाइन की अनुमति है और अनुगामी स्थान की अनुमति है।
  • किसी अन्य आउटपुट की अनुमति नहीं है।

3
यह रग्गुलाइक है, बस फेय है।
Rɪᴋᴇʀ

2
क्या आप स्पष्ट कर सकते हैं "हर संभव संयोजन होने की समान संभावना होनी चाहिए"? क्या आपका शाब्दिक अर्थ है कि सभी वैध मानचित्र (विशेष रूप से, सभी मानचित्र जहां P सभी C / E / Fs तक पहुंच सकते हैं) को समान संभावना के साथ होना चाहिए? यदि ऐसा है, तो ऐसा लगता है कि केवल संभव एल्गोरिथ्म यादृच्छिक रूप से मानचित्रों को समान रूप से उत्पन्न करना है और फिर जांचें कि पी सब कुछ तक पहुंच सकता है, ऐसा होने तक अमान्य मानचित्रों को त्याग देता है।
ग्रेग मार्टिन

क्या आप यह भी स्पष्ट कर सकते हैं - "बीच में कुछ मात्रा में दीवारें होनी चाहिए", क्या होगा यदि मैं हर समय केवल 2 दीवारें रखता हूं?
गुरुपाद ममदापुर

1
@GregMartin मैं इसे भी बदल दूंगा "हर संभव लेआउट को होने का एक मौका होना चाहिए", जरूरी नहीं कि एक समान मौका।
पावेल

2
दीवारों से घिरे खाली वर्गों के बारे में क्या? क्या यह एक वैध लेआउट है या उन्हें पूरी तरह से बचा जाना चाहिए? (दूसरे शब्दों में: क्या प्रत्येक खाली वर्ग को प्राप्य होना चाहिए?)
अरनौलड

जवाबों:


5

पर्ल, 293 बाइट्स

@ बाइट हेस्टिंग्स को -9 बाइट्स धन्यवाद

{$==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इसे चलाने के लिए ध्वज जोड़ें :

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'

हालाँकि, इसे चलाने में लंबा समय लगता है, इसलिए मैं इसके बजाय इस संस्करण का उपयोग करने की सलाह देता हूं:

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'

इसे ऑनलाइन आज़माएं!

व्याख्या

{{ एक ब्लॉक दर्ज करें (जिसे लूप के रूप में उपयोग किया जाता है) { $ == 7 + रैंड 30 ; # बेतरतीब ढंग से नक्शे की चौड़ाई -2 चयन # (-2 क्योंकि हमें अभी तक सीमाओं शामिल न करें) @r = $ , "# रीसेट @r, और सेट $ = ()" को undef @a = ( # बनाने चरित्र की एक सूची जो बोर्ड पर हो सकती है ( C ) x4 , # 4 सिक्के 'C' ( E ) x3 , # 3 शत्रु 'E' ( "#" ) x1369 , # 37 * 37 '#' (                     
                       
                                     
    
                                 
                               
                               
                          
     "" ) x1369 ); # 37 * 37 रिक्त स्थान के लिए $ मैं ( 0..7 + रैंड 30 ) # 2 डी नक्शा बनाने (7 + रैंड 30 ऊंचाई है, जो अभी-अभी उत्पन्न किया जाता है) के लिए $ _ ( 0. $ = - 1 ) { 
        $ r [ $ i ] [ $ _ ] = # सूचकांक [$ i] [$ _] प्राप्त करता है ... 
           ब्याह @ ए , रांड @ ए , # .. पहले से उत्पन्न सूची से एक यादृच्छिक चरित्र # (चरित्र है) फिर सूची से 'ब्याह' के लिए धन्यवाद) } } 
    $ r हटा दिया [                    
                     
                                     
                                       
      
    0 ] [ $ =] = एफ ; # फिनिश सेल 
    $ r [- 1 ] [ 0 ] = P जोड़ें ; # प्रारंभ सेल जोड़ें 
    $ _ = $ r = # यहां हम मानचित्र का एक स्ट्रिंग प्रतिनिधित्व उत्पन्न करते हैं 
          $ , # जुड़ते हैं, नए तत्वों के साथ निम्नलिखित तत्वों में शामिल होते हैं 
            $ v = "#" x ( $ = + = 3 ), # पहला # केवल लाइन ( मानचित्र "# # $ _ #" , @ ), # प्रत्येक पंक्ति की शुरुआत और अंत में एक # जोड़ें                                                                                                             
                       
            $ वी ; # आखिरी लाइन #                        

    1 योर # निम्न रीगेक्स हर एक्सेस सेल को F 
       $ r = ~ s / F ((। { $ =}) से बदल देगा? [^ # F ] / F $ 1F / s   # सेल को दाईं ओर या नीचे a? एफ सेल को बदल दिया गया है   || # या 
       $ r = ~ s / [^ # F ] (? { $ =})? एफ / एफ $ 1 एफ / एस ; # बाईं ओर या F सेल के शीर्ष पर स्थित एक सेल को 
    $ r से बदल दिया जाता है ! ~ / [CEP] / # यदि मानचित्र पर कोई C, E या P नहीं है (जिसका अर्थ है कि वे सभी सुलभ थे) और&                
                                            
      /C.*C / s          # और कम से कम 2 सिक्के हैं && / E / ? # और 1 शत्रु अंतिम : # नक्शा वैध है, हम लूप से बाहर निकलते हैं # और, स्टार्ट ओवर } 
कहते हैं                      # और प्रिंट बोर्ड
                  
                   
                    

इसे चलाने में एक लंबा समय लगता है, क्योंकि जिस सूची से हम अक्षर को बोर्ड पर रखने के लिए यादृच्छिक रूप से चुनते हैं ( @a) में 1369 व्हाट्सएप और #, और केवल 4 सिक्के और 3 दुश्मन हैं। इसलिए यदि चौड़ाई और ऊंचाई का आकार छोटा है, तो बहुत सारे स्थान हैं और #सिक्के और दुश्मनों की तुलना में है, इसलिए यह काफी संभावना है कि एक यादृच्छिक नक्शा मान्य नहीं होगा। (सूची है: क्यों "अनुकूलित" संस्करण तेजी से होता है कि सूची जिससे हम पात्रों लेने बस थोड़ी नक्शे से बड़ा है @a=((C)x4,(E)x3,("#")x($v=rand $=*$%),($")x($=*$%-$v)): एक यादृच्छिक संख्या $vकी #(नक्शे के आकार से हीन), और size of the map - $vव्हाइटस्पेस)।


मैं वास्तव में नहीं जानता, लेकिन वाक्यविन्यास पर प्रकाश डालते हुए आप ($ ") x $ = ** 2) में एक बेजोड़ उद्धरण प्रतीत होता है; - शायद प्रकाश डाला सही काम नहीं करता है और यह एक विशेषता है।" , व्हॉट्सएप अप्राप्य हो सकता है।
पावेल

1
@ पावेल $"एक कानूनी पर्ल वैरिएबल है, लेकिन सिंटैक्स हाइलाइटिंग इसके बारे में नहीं जानता है, इसीलिए यह ऐसा दिखता है। ठीक है, मैं अप्राप्य रिक्त स्थान के बारे में टिप्पणी हटा दूंगा।
दादा

5

PHP, 422 417 415 309 373 369 364 361 बाइट्स

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);

लाइनब्रेक के बिना एक स्ट्रिंग पर काम करता है; एक्स्ट्रा के बीच यादृच्छिक पथ खोदता है। के साथ चला -r

नोट: रास्तों का निर्माण यादृच्छिक दिशाओं में चलने से होता है। हर चरण के लिए दिशा का विकल्प ज्यादातर ऐसे नक्शे उत्पन्न करेगा जो व्यापक खुले हैं; और उदाहरण का नक्शा दिखाई देने की बहुत संभावना नहीं है; लेकिन यह है संभव।

टूट - फूट

// 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);

आपकी व्याख्या में आप 37 की ऊंचाई और चौड़ाई 37 से नहीं, 39 तक बना रहे हैं।
Pavel

@ पावेल तय; ध्यान देने के लिए धन्यवाद
टाइटस

जब मैंने इसे ऑनलाइन
Pavel

@ फावड़ा आपको कोड को घेरने की जरूरत है<?php .... ?>
दादा

1
ठीक है, मैंने ऐसा किया, और मैंने देखा कि दीवारें नियमित आयताकार टुकड़ों में उत्पन्न होती हैं। यह उदाहरण मानचित्र की तरह कुछ उत्पन्न करने में सक्षम होना चाहिए। यह भी हमेशा उत्पन्न नहीं करता है E
पावेल

3

सी # (विजुअल सी # इंटरएक्टिव कंपाइलर) , 730 बाइट्स

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;}

इसे ऑनलाइन आज़माएं!

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;
}

संपादित करें: 8 बाइट्स को बचाया, 99 पुनरावृत्तियों के लिए खिलाड़ी सुलभ टेस्ट लूप को लॉक करके इसे थोड़ा कम कुशल बनाया। मुझे पता है कि यह वास्तव में यहाँ अन्य उत्तरों के साथ प्रतिस्पर्धा नहीं करेगा, लेकिन मुझे मज़ा आ रहा है!


@GregMartin अब F # ;-) में इसे लागू करने की आपकी बारी है
बेंस जोफुल

2
उपडोमिनेंट के लिए एक सरल मॉड्यूलेशन, कोई समस्या नहीं है :)
ग्रेग मार्टिन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.