Ruby / egyszerű labirintus generálás

Még egy régi C64-es könyvemben volt Basic-ben egy egyszerű algoritmus labirintus generálásra, melynek természetesen nem garantált az átjárhatósága két oldalról. Az egyszerűség a szépsége.

asch Basic interpreterjéről jutott eszembe, gondoltam bedobom ide. Ruby-ban így is lehet például:

2000.times{ print (rand < 0.5) ? "\\" : "/" }

Hozzászólások

Ez egy hosszú csík \-ből és /-ből. pl. (\//\\/////\\\\\/\/\\\///\/\\\)
Hogyan kell ezt elképzelni labirintusnak?

Feltételezed, hogy a terminálon érvényben van a wrap-around. Tapasztalati úton én meg nem :-) Amúgy egy nem túl rövid (és legalább ronda) ksh/bash/POSIX-sh-beli megvalósítás:


i=0 ; while (( i < 24 )) ; do j=0 ; while (( j < 80 )) ; do (( RANDOM % 2 )) && printf / || printf \\ ; (( j++ )) ; done ; echo ; (( i++ )) ; done

Akárhogy erőltetem a ?: operátort, nem bírom rábeszélni, hogy karaktert is elfogadjon az igaz/hamis ágban. Amúgy ha valóban van wrap-around, akkor persze egyszerűbb a dolog:


while : ; do (( RANDOM % 2 )) && printf / || printf \\ ; done

Mondjuk a tiedhez ez hasonlít jobban (hosszban is).
=====
tl;dr
Egy-két mondatban leírnátok, hogy lehet ellopni egy bitcoin-t?

Alap "funkcionális" megoldás, bár a print és a foreach miatt nem teljesen az:


(1 to 2000).foreach(i => print(if (util.Random.nextDouble < 0.5) "╲" else "╱"))

Alap imperatív egy kicsit rövidebb:


for (i <- 1 to 2000) print(if (util.Random.nextDouble < 0.5) "╲" else "╱")

Két függvény definíció segítségével lehet a ruby-hoz hasonlót csinálni:


def rand = util.Random.nextDouble
def times(n: Int)(fn: => Unit) = for (i <- 1 to n) fn

times(2000) { print(if (rand < 0.5) "╲" else "╱") }

Vagy csúnya implicit-tel még hasonlóbbat:


def rand = util.Random.nextDouble
implicit def intTimes(i: Int) = new {
    def times(fn: => Unit) = (1 to i) foreach (x => fn)
}

2000 times { print(if (rand < 0.5) "╲" else "╱") }

Itt egy stream-es megoldás, még ez a legfunkcionálisabb:


def wallStream: Stream[String] = Stream.cons(if (util.Random.nextDouble < 0.5) "╲" else "╱", wallStream)
wallStream.take(2000).foreach(print)

Kicseréltem mindenhol szép (végigérő) karakterekre. Így már tényleg hasonlít labirintusra.

Szerk.: no még a végére egy keveréses megoldás:


util.Random.shuffle(List.fill(1000)("╲") ++ List.fill(1000)("╱")).foreach(print)

:)
A leglassabb megoldás címéért folyó versenyben biztosan előkelő helyen végezne! Az is elképzelhető, hogy örökké fut ;)
Illetve, ha a "szép" karaktereket (╲, ╱) akarod kiírni, akkor még egy átalakítás is kellene:


Stream.continually(util.Random.nextPrintableChar)
	.filter(c => c == '/' || c == '\\')
        .map(_ match { case '\\' => '╲'; case '/' => '╱' })
	.take(2000)
	.foreach(print)

A fenti kicsit hatékonyabb átírata:


Stream.continually(Vector("╲", "╱")(util.Random.nextInt(2)))
  .take(2000)
  .foreach(print)

Vagy egy még hatékonyabb és szebb, de nem egysoros átirata:


val walls = Vector("╲", "╱")
def randomWall = walls(util.Random.nextInt(walls.size))
Stream.continually(randomWall)
  .take(2000)
  .foreach(print)

Most látom, hogy a string unescape-elést kifelejtettem az RBASIC release-ből. A következőben fixálom. Akkor működni fog ez a program:

for i=1 to 50
for j=1 to 50
if rand<0.5 then
print("\\");
else
print("/");
end if
next j
print ""
next i

R pelda kod az algoritmusra:

cat(sample(c('\\', '/'), 1e3, replace = TRUE))

Ha a karakterek szama lenyeges, akkor a 3. argumentum lerovidiheto :)

cat(sample(c('\\','/'),1e3,1))