Створіть карту для шахраїв


10

Сьогодні ми будемо створювати карту для шахрайського RPG!

Прикладна карта:

##########
####    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 / F), повинні виникати з однаковою ймовірністю? Якщо так, то, здається, єдиний можливий алгоритм - генерувати карти рівномірно і випадково перевіряти, чи P може дійти до всього, відкидаючи недійсні карти, поки цього не станеться.
Грег Мартін

Чи можете ви також уточнити - "Посередині має бути деяка кількість стін", що робити, якщо я весь час розміщую лише 2 стіни?
Гурупад Мамадапур

1
@GregMartin Я теж зміню його "Кожен можливий макет повинен мати шанс виникнення", не обов'язково рівний шанс.
Павло

2
А як щодо недосяжних порожніх площ, оточених стінами? Це дійсна схема чи їх слід взагалі уникати? (Іншими словами: чи повинен бути доступний кожен порожній квадрат?)
Арнольд

Відповіді:


5

Perl, 293 байти

-9 байт завдяки @Dom Hastings

{$==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 + rand 30 ; # Випадковим чином вибрати ширину карти -2 # (-2 , тому що ми не включаємо кордону поки) @r = $ «= (); # скидання @R, і безліч $» на невизначений значення @a = ( # створити список символів, які можуть бути на дошці ( C ) x4 , №4 монети 'C' ( E ) x3 , №3 ворогів 'E' ( "#" ) x1369 , # 37 * 37 '#' (                     
                       
                                     
    
                                 
                               
                               
                          
     "" ) x1369 ); # 37 * 37 простору для $ я ( 0..7 + ранд 30 ) # створити 2D карту (7 + 30 рандів висота, яка формується тільки зараз) за $ _ ( 0 . $ = - 1 ) { 
        $ r [ $ i ] [ $ _ ] = # індекс [$ i] [$ _] отримує ... 
           зрощення @ a , rand @ a , 1 # .. випадковий символ зі списку, сформованого раніше # (символ є потім вилучено зі списку завдяки "зрощенню") } } 
    $ r [                    
                     
                                     
                                       
      
    0 ] [ $ =] = F ; # додати обробну комірку 
    $ r [- 1 ] [ 0 ] = P ; # додайте початкову клітинку 
    $ _ = $ r = # тут ми створюємо рядкове представлення карти 
          join $ /, # приєднуємо наступні елементи з новими рядками 
            $ v = "#" x ( $ = + = 3 ), # a рядок # тільки ( карта "# @ $ _ #" , @r ), # додайте # на початок і в кінець кожного рядка                                                                                                             
                       
            $ v ; # останній рядок з #                        

    Тим часом # наступний регулярний вимір замінить кожну доступну клітинку на F 
       - r = ~ s / F (. { $ =})? [^ # F ] / F $ 1F / s   # комірка праворуч або внизу F комірка замінюється   || # або 
       $ r = ~ s / [^ # F ] (. { $ =})? F / F $ 1F / s ; # клітинка зліва або вгорі клітинки F замінюється 
    $ r ! ~ / [CEP] / #, якщо на карті немає C, E або P (тобто всі вони були доступні) &&                
                                            
      /C.*C/ s          # і є щонайменше 2 монети && / E / ? # і 1 ворог останній : # карта дійсна, ми виходимо з циклу повторення # else, починаємо спочатку } 
скажімо                      # і друкуємо дошку
                  
                   
                    

Бігати потрібно багато часу, тому що список, з якого ми випадково вибираємо символів, які слід поставити на дошку ( @a), містить 1369 пробілів і #, і лише 4 монети та 3 вороги. Отже, якщо розміри ширини та висоти невеликі, місця є дуже багато, і #порівняно з монетою та ворогами, тому цілком ймовірно, що випадкова карта не буде дійсною. Ось чому «оптимізовані» версія швидше: список , з якого ми вибираємо символи просто трохи більше , ніж карта (список @a=((C)x4,(E)x3,("#")x($v=rand $=*$%),($")x($=*$%-$v)): випадкове число $vз #(нижче розміру карти), і size of the map - $vпробіли).


Я насправді не знаю perl, але, дивлячись на виділення синтаксису, у вас, здається, є незрівнянна цитата в ($ ") x $ = ** 2);. Можливо, виділення не працює правильно, і це особливість. , пробіл може бути недосяжним
Павло

1
@Pavel $"- це легітимна змінна Perl, але підсвічування синтаксису не знає про це, тому це виглядає так. Гаразд, я видалю коментар про недоступні місця.
Дада

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, а не до 39.
Павло

@Pavel виправлено; дякую за те, що помітили
Тіт

Виводить це власний вихідний код, коли я спробував у програмі Спробуйте в Інтернеті
Павло

@Pavel вам потрібно оточити код<?php .... ?>
Dada

1
Гаразд, я це зробив, і я помітив, що стіни створюються в правильні прямокутні шматки. Він повинен мати можливість генерувати щось на зразок карти на прикладі. Він також не завжди генерує Es.
Павло

3

C # (Visual C # Interactive Compiler) , 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;}

Спробуйте в Інтернеті!

Безголівки:

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 та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.