" From: baruchel@libertysurf.france (Thomas Baruchel)
" Newsgroups: comp.editors
" Date: 3 Sep 2000 18:29:36 GMT
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" SOKOBAN for Vim                                                              "
" release 1 (without the 50 levels and the 'n' key)                            "
" written by Thomas Baruchel <baruchel@libertysurf.fr>                         "
" Just type :Sokoban <level> to play                                           "
"   press 'q' to quit and 'n' to go to the next level                          "
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
command! -nargs=1 Sokoban call Sokobanf(<f-args>)
function! Sokobanf(numero)
  execute "normal \<C-w>n"
  resize
  call Sokobann(a:numero)
  nmap <Up> :call SokobanUp()<CR>
  nmap <Down> :call SokobanDown()<CR>
  nmap <Left> :call SokobanLeft()<CR>
  nmap <Right> :call SokobanRight()<CR>
  nmap q :call SokobanQuit()<CR>
endfunction()
function! SokobanQuit()
  nunmap <Up>
  nunmap <Down>
  nunmap <Left>
  nunmap <Right>
  nunmap q
  close
endfunction()
function! SokobanUp()
  execute "normal 1G/[@]/\<CR>mxk"
  execute "normal \"xyyld$"
  execute "normal :.s/^.*\\(.\\)$/:let topo=\"\\1\"\<C-v>\<C-v>\<C-v>\<CR>\<CR>"
  execute "normal 0\"yy$dd\"xP@y"
  if (topo == " ")
    execute "normal :g/@/s/@/ /\<CR>"
    execute "normal :g//s//./\<CR>"
    execute "normal `xkr@"
    call SokobanEndOfTurn()
    return
  endif
  if (topo == ".")
    execute "normal :g/@/s/@/ /\<CR>"
    execute "normal :g//s//./\<CR>"
    execute "normal `xkr"
    call SokobanEndOfTurn()
    return
  endif
  if (topo == "#")
    call SokobanEndOfTurn()
    return
  endif
  execute "normal `xkk\"xyyld$"
  execute "normal :.s/^.*\\(.\\)$/:let sup=\"\\1\"\<C-v>\<C-v>\<C-v>\<CR>\<CR>"
  execute "normal 0\"yy$dd\"xP@y"
  if (topo == "o")
    if (sup == "#")
      call SokobanEndOfTurn()
      return
    endif
    if (sup == "o")
      call SokobanEndOfTurn()
      return
    endif
    if (sup == "O")
      call SokobanEndOfTurn()
      return
    endif
    if (sup == " ")
      execute "normal :g/@/s/@/ /\<CR>"
      execute "normal :g//s//./\<CR>"
      execute "normal `xkr@kro"
      call SokobanEndOfTurn()
      return
    endif
    if (sup == ".")
      execute "normal :g/@/s/@/ /\<CR>"
      execute "normal :g//s//./\<CR>"
      execute "normal `xkr@krO"
      call SokobanEndOfTurn()
      return
    endif
  endif
  if (topo == "O")
    if (sup == "#")
      call SokobanEndOfTurn()
      return
    endif
    if (sup == "o")
      call SokobanEndOfTurn()
      return
    endif
    if (sup == "O")
      call SokobanEndOfTurn()
      return
    endif
    if (sup == " ")
      execute "normal :g/@/s/@/ /\<CR>"
      execute "normal :g//s//./\<CR>"
      execute "normal `xkrkro"
      call SokobanEndOfTurn()
      return
    endif
    if (sup == ".")
      execute "normal :g/@/s/@/ /\<CR>"
      execute "normal :g//s//./\<CR>"
      execute "normal `xkrkrO"
      call SokobanEndOfTurn()
      return
    endif
  endif
endfunction()
function! SokobanDown()
  execute "normal 1G/[@]/\<CR>mxj"
  execute "normal \"xyyld$"
  execute "normal :.s/^.*\\(.\\)$/:let topo=\"\\1\"\<C-v>\<C-v>\<C-v>\<CR>\<CR>"
  execute "normal 0\"yy$dd\"xP@y"
  if (topo == " ")
    execute "normal :g/@/s/@/ /\<CR>"
    execute "normal :g//s//./\<CR>"
    execute "normal `xjr@"
    call SokobanEndOfTurn()
    return
  endif
  if (topo == ".")
    execute "normal :g/@/s/@/ /\<CR>"
    execute "normal :g//s//./\<CR>"
    execute "normal `xjr"
    call SokobanEndOfTurn()
    return
  endif
  if (topo == "#")
    call SokobanEndOfTurn()
    return
  endif
  execute "normal `xjj\"xyyld$"
  execute "normal :.s/^.*\\(.\\)$/:let inf=\"\\1\"\<C-v>\<C-v>\<C-v>\<CR>\<CR>"
  execute "normal 0\"yy$dd\"xP@y"
  if (topo == "o")
    if (inf == "#")
      call SokobanEndOfTurn()
      return
    endif
    if (inf == "o")
      call SokobanEndOfTurn()
      return
    endif
    if (inf == "O")
      call SokobanEndOfTurn()
      return
    endif
    if (inf == " ")
      execute "normal :g/@/s/@/ /\<CR>"
      execute "normal :g//s//./\<CR>"
      execute "normal `xjr@jro"
      call SokobanEndOfTurn()
      return
    endif
    if (inf == ".")
      execute "normal :g/@/s/@/ /\<CR>"
      execute "normal :g//s//./\<CR>"
      execute "normal `xjr@jrO"
      call SokobanEndOfTurn()
      return
    endif
  endif
  if (topo == "O")
    if (inf == "#")
      call SokobanEndOfTurn()
      return
    endif
    if (inf == "o")
      call SokobanEndOfTurn()
      return
    endif
    if (inf == "O")
      call SokobanEndOfTurn()
      return
    endif
    if (inf == " ")
      execute "normal :g/@/s/@/ /\<CR>"
      execute "normal :g//s//./\<CR>"
      execute "normal `xjrjro"
      call SokobanEndOfTurn()
      return
    endif
    if (inf == ".")
      execute "normal :g/@/s/@/ /\<CR>"
      execute "normal :g//s//./\<CR>"
      execute "normal `xjrjrO"
      call SokobanEndOfTurn()
      return
    endif
  endif
endfunction()
function! SokobanLeft()
  execute "normal :g/ o\\=@.*[^!]$/s/ \\(o\\=\\)@\\(.*\\)$/\\1@ \\2!/\<CR>"
  execute "normal :g/ .*[^!]$/s/ \\(.*\\)$/@.\\1!/\<CR>"
  execute "normal :g/\\.@.*[^!]$/s/\\.@\\(.*\\)$/ \\1!/\<CR>"
  execute "normal :g/\\..*[^!]$/s/\\.\\(.*\\)$/.\\1!/\<CR>"
  execute "normal :g/\\.o@.*[^!]$/s/\\.o@\\(.*\\)$/O@ \\1!/\<CR>"
  execute "normal :g/\\.o.*[^!]$/s/\\.o\\(.*\\)$/O@.\\1!/\<CR>"
  execute "normal :g/\\.O@.*[^!]$/s/\\.O@\\(.*\\)$/O \\1!/\<CR>"
  execute "normal :g/\\.O.*[^!]$/s/\\.O\\(.*\\)$/O.\\1!/\<CR>"
  execute "normal :g/ O@.*[^!]$/s/ O@\\(.*\\)$/o \\1!/\<CR>"
  execute "normal :g/ O.*[^!]$/s/ O\\(.*\\)$/o.\\1!/\<CR>"
  call SokobanEndOfTurn()
endfunction()
function! SokobanRight()
  execute "normal :g/@o\\= .*[^!]$/s/@\\(o\\=\\) \\(.*\\)$/ @\\1\\2!/\<CR>"
  execute "normal :g/ .*[^!]$/s/ \\(.*\\)$/.@\\1!/\<CR>"
  execute "normal :g/@\\..*[^!]$/s/@\\.\\(.*\\)$/ \\1!/\<CR>"
  execute "normal :g/\\..*[^!]$/s/\\.\\(.*\\)$/.\\1!/\<CR>"
  execute "normal :g/@o\\..*[^!]$/s/@o\\.\\(.*\\)$/ @O\\1!/\<CR>"
  execute "normal :g/o\\..*[^!]$/s/o\\.\\(.*\\)$/.@O\\1!/\<CR>"
  execute "normal :g/@O\\..*[^!]$/s/@O\\.\\(.*\\)$/ O\\1!/\<CR>"
  execute "normal :g/O\\..*[^!]$/s/O\\.\\(.*\\)$/.O\\1!/\<CR>"
  execute "normal :g/@O .*[^!]$/s/@O \\(.*\\)$/ o\\1!/\<CR>"
  execute "normal :g/O .*[^!]$/s/O \\(.*\\)$/.o\\1!/\<CR>"
  call SokobanEndOfTurn()
endfunction()
function! SokobanEndOfTurn()
  execute "normal :g/!/s/!//\<CR>"
  execute "normal :echo \"SOKOBAN (written by Thomas Baruchel)\"\<CR>"
  execute "normal 1Gjj"
endfunction()
function! Sokobann(numero)
  execute "normal :%d\<CR>"
  set noautoindent
  syntax match Rock /[Oo]/
  syntax match Wall /#/
  syntax match Soko /[@]/
  syntax match Level /Level.*$/
  syntax match Level /=/
  hi Level cterm=bold term=bold gui=bold
  hi Rock ctermfg=green guifg=green
  hi Wall ctermfg=brown ctermbg=brown guifg=brown guibg=brown
  hi Soko ctermfg=blue guifg=blue
  execute "normal :call Sokobann" . a:numero . "()\<CR>"
  execute "normal 1GccLevel " . a:numero . "\<ESC>"
  execute "normal yyp:.s/./=/g\<CR>Go(q=quit, n=next)\<ESC>1Gjj"
  execute "normal :echo \"SOKOBAN (written by Thomas Baruchel)\"\<CR>"
endfunction()
"
" Levels
"
function! Sokobann1()
  execute "normal o     #####\<ESC>"
  execute "normal o     #   #\<ESC>"
  execute "normal o     #o  #\<ESC>"
  execute "normal o   ###  o##\<ESC>"
  execute "normal o   #  o o #\<ESC>"
  execute "normal o ### # ## #   ######\<ESC>"
  execute "normal o #   # ## #####  ..#\<ESC>"
  execute "normal o # o  o          ..#\<ESC>"
  execute "normal o ##### ### #@##  ..#\<ESC>"
  execute "normal o     #     #########\<ESC>"
  execute "normal o     #######\<ESC>"
endfunction()

