不思議なダンジョン風マップ自動生成

参考にしたのはここ http://racanhack.sourceforge.jp/rhdoc/index.html

方針

上記の説明だけ読んでコード参考にしなかったので全然違う実装になった。

大きな空部屋を作って、部屋のクラスごとに担当する領域を持っておく。再帰構造で次の部屋の参照をもっとく。隣の部屋へのルートを書けば全部の部屋が繋がる。

コード

部屋と部屋をつなぐ部分を手抜きでやったので他の部屋跨いだりする。

{pow,sqrt,abs,random,max,min} = Math
class Room
  constructor:(@map,@depth, @ax,@ay)->
    @max_size = 4
    @next = null
    if @depth > 0
      @next = @split()

    if @ax[1]-@ax[0] < 13
      @rx = @ax
    else
      cx = ~~((@ax[0]+@ax[1])/2)
      @rx = [cx-6, cx+6]
    if @ay[1]-@ay[0] < 13
      @ry = @ay
    else
      cy = ~~((@ay[0]+@ay[1])/2)
      @ry = [cy-6, cy+6]

    @center = [
      ~~((@rx[1]+@rx[0])/2)
      ~~((@ry[1]+@ry[0])/2)
    ]

    @draw_area()

  _v : ->
    [sx , ex] = @ax
    cx = ~~( (ex-sx)*(max(0.2,1-random()/@depth) )+sx  )
    @ax = [cx,ex]
    new Room @map,--@depth, [sx,cx ],@ay

  _s : ->
    [sy , ey] = @ay
    cy = ~~( (ey-sy)*(1-random()/@depth)+sy  )
    @ay = [cy,ey]
    new Room @map,--@depth, @ax , [sy,cy]

  split:->
    if Math.random() > 0.5
      @_s()
    else
      @_v()

  draw_area : ->
    [sx,ex] = @rx
    [sy,ey] = @ry
    for i in [sx ... ex]
      for j in [sy ... ey]
        if @center[0] is i and @center[1] is j
          @map[i][j] = 2
          console.log i,j
        if (i == sx or i == (ex-1) ) or (j == sy or j == (ey-1))
          @map[i][j] = 1
        else
          @map[i][j] = 0

  draw_path : ->
    if @next
      [cx,cy] = @center
      [nx,ny] = @next.center
      while abs(cx-nx)+abs(cy-ny) > 0
        if cx>nx then cx--
        else if cx<nx then cx++
        else if cy>ny then cy--
        else if cy<ny then cy++
        @map[cx][cy] = 0
      @next.draw_path()

blank = (x,y)->
  map = []
  for i in [0 ... x]
    map[i] = []
    for j in [0 ... y]
      map[i][j] = 1
  return map

create_map = ->
  x = 30
  y = 30
  root = new Room(blank(x,y),13 ,[1,x-1],[1,y-1])
  root.draw_path()
  root.map

main = ->
  map = create_map()
  for i in map
    console.log i
      .join('')
      .split('0').join('  ')
      .split('1').join('//')
      .split('2').join('..')

main()


実行したらこんな感じ。

////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
////                    ////////////////////////////////////
////                    ////////////////////////////////////
////                    ////////////////////////////////////
//////////////  ////////////////////////////////////////////
//////////////  //////////////    ////    //////////////////
////                    //////    ////    //////////////////
////                    //////    ////    //////////////////
////                    //////    ////    //////////////////
////                    //////    ////    //////////////////
////                    ////                          //////
////                    ////      ////    //////////////////
////                    ////                              //
////                    ////      ////    //////////////  //
////                    ////      ////    //////////////  //
//////////////  ////////////      //////////////////////  //
//////////////  ////////////      //////////////////////  //
////                    ////      //////////////////////  //
//////////////  ////////////      //////////////////////  //
//////////////                    //////////////////////  //
////////////////////////////    ////////////////////////  //
////////////////////////////    ////////////////////////  //
////////////////////////////    ////////////////////////  //
//////////////////                                        //
//////////////////////////////  ////////////////////////////
//////////////////////////////  ////////////////////////////
//////////////////////////////  ////////////////////////////
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////