mirror of
https://github.com/cliffe/SecGen.git
synced 2026-02-21 11:18:06 +00:00
Task 15.3 - new approach: generators/maze/maze_generator (WiP)
This commit is contained in:
@@ -62,7 +62,7 @@ define secgen_functions::install_setgid_script (
|
||||
owner => 'root',
|
||||
group => $grp,
|
||||
mode => '2775',
|
||||
content => $script_data[0],
|
||||
content => $script_data,
|
||||
require => Group[$grp],
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ class ruby_challenge_example::install {
|
||||
source_module_name => $module_name,
|
||||
challenge_name => $challenge_name,
|
||||
script_name => 'test.rb',
|
||||
script_data => $secgen_params['script_data'],
|
||||
script_data => $secgen_params['script_data'][0],
|
||||
group => $secgen_params['group'],
|
||||
account => $secgen_params['account'],
|
||||
flag => $secgen_params['flag'],
|
||||
|
||||
@@ -6,7 +6,7 @@ class math_challenge::install {
|
||||
source_module_name => $module_name,
|
||||
challenge_name => $challenge_name,
|
||||
script_name => "$challenge_name.rb",
|
||||
script_data => $secgen_params['script_data'],
|
||||
script_data => $secgen_params['script_data'][0],
|
||||
group => $secgen_params['group'],
|
||||
account => $secgen_params['account'],
|
||||
flag => $secgen_params['flag'],
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
/build
|
||||
/goxz
|
||||
.golint.txt
|
||||
/vendor
|
||||
@@ -1,29 +0,0 @@
|
||||
sudo: false
|
||||
language: go
|
||||
go:
|
||||
- 1.9
|
||||
env: PATH=/home/travis/gopath/bin:$PATH
|
||||
script:
|
||||
- make test
|
||||
- make lint
|
||||
- make cross
|
||||
deploy:
|
||||
provider: releases
|
||||
skip_cleanup: true
|
||||
api_key:
|
||||
secure: El/qxSDFFxk0KCI4e7ed6Jyau6Lw4u8h9CejN1ke2WHez6Nyv9f41uEM+EQFxp/mfdVEAlkjAA/A+nknWP9gJeANqhCpmEaFQ5J3eaW2nECd8fglclqdVP9NZ7Fbl4qTKsQpD7xYfFUk+P++4dVKZXuutNXT9gPUjVbzOx/tCnl1CwktOEFPEpv9fy64vD00ywUg1SaJgSl5dqA2RGunNSh6hr+pELXYjQ0uQzjMG+Gpknga0EWQEZleOXspw0ClUTrMYuqTooM/8yFfmG5d/p/8wQCCvyIBEQYCSOoOL+li7CBO26GnBvuPxMTvEzQ+0jjOxaEEgc+hOLo1elB+NbxT9Wz5NkJYbkmSUSfk9OZ4vmcvRZbQR9aiqZTeLVB8x6ln/Xzk45zeORcjRQI0fXd5k/dYRLKxKc3DQcXpa3ASzM8VXjx4p3YjcmqMvt+KtKhFL+DbSGxsxjuR6ulk3QJtuM3hnnsRkz58VTZunFsknRr3b0s8pHBYpGw+wLwWJ+IOrk0GBl0MBV705upoi+8xJiqZ7LPvkAe3XRDSV2jPZUyvn5+gzTQ597zTk3zZrpzQ0809UdQRWWkQYF7udozQ4K9+qk34j8Z2IAykgn+ClRmgTdiH87DAIBsZmeSEMjvripBMs5Vkbe3ijnyKuGPREjZ4bgEKrNVl9Y5yNg0=
|
||||
file:
|
||||
- goxz/maze_darwin_386.zip
|
||||
- goxz/maze_darwin_amd64.zip
|
||||
- goxz/maze_freebsd_386.tar.gz
|
||||
- goxz/maze_freebsd_amd64.tar.gz
|
||||
- goxz/maze_linux_386.tar.gz
|
||||
- goxz/maze_linux_amd64.tar.gz
|
||||
- goxz/maze_netbsd_386.tar.gz
|
||||
- goxz/maze_netbsd_amd64.tar.gz
|
||||
- goxz/maze_windows_386.zip
|
||||
- goxz/maze_windows_amd64.zip
|
||||
on:
|
||||
repo: itchyny/maze
|
||||
tags: true
|
||||
all_branches: false
|
||||
@@ -1,39 +0,0 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/codegangsta/cli"
|
||||
packages = ["."]
|
||||
revision = "cfb38830724cc34fedffe9a2a29fb54fa9169cd1"
|
||||
version = "v1.20.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-isatty"
|
||||
packages = ["."]
|
||||
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
|
||||
version = "v0.0.3"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-runewidth"
|
||||
packages = ["."]
|
||||
revision = "9e777a8366cce605130a531d2cd6363d07ad7317"
|
||||
version = "v0.0.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/nsf/termbox-go"
|
||||
packages = ["."]
|
||||
revision = "aa4a75b1c20a2b03751b1a9f7e41d58bd6f71c43"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix"]
|
||||
revision = "83801418e1b59fb1880e363299581ee543af32ca"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "7ae4b9c97302a35f895e8e4aeaa1bfef36b827a9099b7ab07af89162f5abdee3"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
@@ -1,34 +0,0 @@
|
||||
|
||||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/codegangsta/cli"
|
||||
version = "1.20.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/mattn/go-isatty"
|
||||
version = "0.0.3"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/nsf/termbox-go"
|
||||
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 itchyny
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,41 +0,0 @@
|
||||
BIN = maze
|
||||
DIR = ./cmd/maze
|
||||
GOROOT ?= /usr/local/go
|
||||
|
||||
all: clean test build
|
||||
|
||||
build: deps
|
||||
go build -o build/$(BIN) $(DIR)
|
||||
|
||||
install: deps
|
||||
go install ./...
|
||||
|
||||
deps:
|
||||
go get -u github.com/golang/dep/cmd/dep
|
||||
dep ensure
|
||||
|
||||
cross: crossdeps
|
||||
goxz -os=linux,darwin,freebsd,netbsd,windows -arch=386,amd64 -n $(BIN) $(DIR)
|
||||
|
||||
crossdeps: deps
|
||||
go get github.com/Songmu/goxz/cmd/goxz
|
||||
|
||||
test: testdeps build
|
||||
go test -v $(DIR)...
|
||||
|
||||
testdeps:
|
||||
go get -d -v -t ./...
|
||||
|
||||
lint: lintdeps build
|
||||
go vet
|
||||
golint -set_exit_status $(go list ./... | grep -v /vendor/)
|
||||
|
||||
lintdeps:
|
||||
go get -d -v -t ./...
|
||||
go get -u github.com/golang/lint/golint
|
||||
|
||||
clean:
|
||||
rm -rf build goxz
|
||||
go clean
|
||||
|
||||
.PHONY: build install deps cross crossdeps test testdeps lint lintdeps clean
|
||||
@@ -1,60 +0,0 @@
|
||||
# maze [](https://travis-ci.org/itchyny/maze)
|
||||
|
||||

|
||||
|
||||
## Usage
|
||||
The `maze` command without the arguments prints the random maze to the standard output.
|
||||
```sh
|
||||
maze
|
||||
```
|
||||

|
||||
|
||||
We can play the maze on the terminal with `--interactive`.
|
||||
```sh
|
||||
maze --interactive
|
||||
```
|
||||

|
||||
|
||||
The `--format color` is a good option to print the colored maze. Also we can specify the size of the maze with `--width` and `--height`.
|
||||
```sh
|
||||
maze --width 20 --height 10 --format color
|
||||
```
|
||||

|
||||
|
||||
We can toggle the solution with the `s` key.
|
||||

|
||||
|
||||
If we change the font size of the terminal smaller, we get a large maze.
|
||||

|
||||
|
||||
## Installation
|
||||
### Homebrew
|
||||
```bash
|
||||
$ brew install itchyny/maze/maze
|
||||
```
|
||||
|
||||
### Download binary from GitHub Releases
|
||||
[Releases・itchyny/maze - GitHub](https://github.com/itchyny/maze/releases)
|
||||
|
||||
### Build from source
|
||||
```bash
|
||||
$ go get -u github.com/itchyny/maze/cmd/maze
|
||||
```
|
||||
|
||||
## Bug Tracker
|
||||
Report bug at [Issues・itchyny/maze - GitHub](https://github.com/itchyny/maze/issues).
|
||||
|
||||
## Author
|
||||
itchyny (https://github.com/itchyny)
|
||||
|
||||
## License
|
||||
This software is released under the MIT License, see LICENSE.
|
||||
|
||||
## Special thanks
|
||||
Special thanks to the [termbox-go](https://github.com/nsf/termbox-go) library.
|
||||
|
||||
## References
|
||||
- [Maze generation algorithm - Wikipedia, the free encyclopedia](https://en.wikipedia.org/wiki/Maze_generation_algorithm)
|
||||
- [Maze solving algorithm - Wikipedia, the free encyclopedia](https://en.wikipedia.org/wiki/Maze_solving_algorithm)
|
||||
- [lunixbochs/maze: Maze generation and salvation](https://github.com/lunixbochs/maze)
|
||||
- [willfrew/maze-generation: Some maze generation algorithms written in Go](https://github.com/willfrew/maze-generation)
|
||||
@@ -1,62 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/itchyny/maze"
|
||||
"github.com/nsf/termbox-go"
|
||||
)
|
||||
|
||||
func action(ctx *cli.Context) error {
|
||||
err := termbox.Init()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
return nil
|
||||
}
|
||||
config, errors := makeConfig(ctx)
|
||||
if errors != nil {
|
||||
hasErr := false
|
||||
termbox.Close()
|
||||
for _, err := range errors {
|
||||
if err.Error() != "" {
|
||||
fmt.Fprintf(os.Stderr, err.Error()+"\n")
|
||||
hasErr = true
|
||||
}
|
||||
}
|
||||
if hasErr {
|
||||
fmt.Fprintf(os.Stderr, "\n")
|
||||
}
|
||||
cli.ShowAppHelp(ctx)
|
||||
return nil
|
||||
}
|
||||
|
||||
maze := createMaze(config)
|
||||
if config.Interactive {
|
||||
defer termbox.Close()
|
||||
interactive(maze, config.Format)
|
||||
} else {
|
||||
termbox.Close()
|
||||
if config.Image {
|
||||
maze.PrintImage(config.Output, config.Format, config.Scale)
|
||||
} else {
|
||||
maze.Print(config.Output, config.Format)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func createMaze(config *Config) *maze.Maze {
|
||||
rand.Seed(config.Seed)
|
||||
maze := maze.NewMaze(config.Height, config.Width)
|
||||
maze.Start = config.Start
|
||||
maze.Goal = config.Goal
|
||||
maze.Cursor = config.Start
|
||||
maze.Generate()
|
||||
if config.Solution {
|
||||
maze.Solve()
|
||||
}
|
||||
return maze
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/itchyny/maze"
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/nsf/termbox-go"
|
||||
)
|
||||
|
||||
// Config is the command configuration
|
||||
type Config struct {
|
||||
Width int
|
||||
Height int
|
||||
Start *maze.Point
|
||||
Goal *maze.Point
|
||||
Interactive bool
|
||||
Image bool
|
||||
Scale int
|
||||
Solution bool
|
||||
Format *maze.Format
|
||||
Seed int64
|
||||
Output io.Writer
|
||||
}
|
||||
|
||||
func makeConfig(ctx *cli.Context) (*Config, []error) {
|
||||
var errs []error
|
||||
|
||||
if ctx.GlobalBool("help") {
|
||||
errs = append(errs, errors.New(""))
|
||||
return nil, errs
|
||||
}
|
||||
|
||||
termWidth, termHeight := termbox.Size()
|
||||
|
||||
width := ctx.GlobalInt("width")
|
||||
if width <= 0 {
|
||||
width = (termWidth - 4) / 4
|
||||
}
|
||||
|
||||
height := ctx.GlobalInt("height")
|
||||
if height <= 0 {
|
||||
height = (termHeight - 5) / 2
|
||||
}
|
||||
|
||||
start := &maze.Point{0, 0}
|
||||
starts := strings.Split(ctx.GlobalString("start"), ",")
|
||||
if len(starts) > 0 {
|
||||
if value, err := strconv.Atoi(starts[0]); err == nil {
|
||||
if 0 <= value && value < height {
|
||||
start.X = value
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(starts) > 1 {
|
||||
if value, err := strconv.Atoi(starts[1]); err == nil {
|
||||
if 0 <= value && value < width {
|
||||
start.Y = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
goal := &maze.Point{height - 1, width - 1}
|
||||
goals := strings.Split(ctx.GlobalString("goal"), ",")
|
||||
if len(goals) > 0 {
|
||||
if value, err := strconv.Atoi(goals[0]); err == nil {
|
||||
if 0 <= value && value < height {
|
||||
goal.X = value
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(goals) > 1 {
|
||||
if value, err := strconv.Atoi(goals[1]); err == nil {
|
||||
if 0 <= value && value < width {
|
||||
goal.Y = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interactive := ctx.GlobalBool("interactive")
|
||||
|
||||
solution := ctx.GlobalBool("solution")
|
||||
|
||||
format := maze.Default
|
||||
if ctx.GlobalString("format") == "color" {
|
||||
format = maze.Color
|
||||
}
|
||||
|
||||
output := ctx.App.Writer
|
||||
outfile := ctx.GlobalString("output")
|
||||
if outfile != "" {
|
||||
file, err := os.Create(outfile)
|
||||
if err != nil {
|
||||
errs = append(errs, errors.New("cannot create the output file: "+outfile))
|
||||
} else {
|
||||
output = file
|
||||
}
|
||||
}
|
||||
|
||||
image := ctx.GlobalBool("image")
|
||||
if image {
|
||||
if file, ok := output.(*os.File); ok && isatty.IsTerminal(file.Fd()) {
|
||||
errs = append(errs, errors.New("cannot write binary data into the terminal\nuse -output flag"))
|
||||
}
|
||||
}
|
||||
|
||||
scale := ctx.GlobalInt("scale")
|
||||
|
||||
seed := int64(ctx.GlobalInt("seed"))
|
||||
if !ctx.IsSet("seed") {
|
||||
seed = time.Now().UnixNano()
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return nil, errs
|
||||
}
|
||||
|
||||
return &Config{
|
||||
Width: width,
|
||||
Height: height,
|
||||
Start: start,
|
||||
Goal: goal,
|
||||
Interactive: interactive,
|
||||
Image: image,
|
||||
Scale: scale,
|
||||
Solution: solution,
|
||||
Format: format,
|
||||
Seed: seed,
|
||||
Output: output,
|
||||
}, nil
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/codegangsta/cli"
|
||||
)
|
||||
|
||||
var flags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "width",
|
||||
Usage: "The width of the maze",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "height",
|
||||
Usage: "The height of the maze",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "start",
|
||||
Usage: "The start coordinate",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "goal",
|
||||
Usage: "The goal coordinate",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "interactive",
|
||||
Usage: "Play the maze interactively",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "solution",
|
||||
Usage: "Print the maze with the solution",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "format",
|
||||
Usage: "Output format, `default` or `color`",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "output, o",
|
||||
Usage: "Output file name",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "image",
|
||||
Usage: "Generate image",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "scale",
|
||||
Usage: "Scale of the image",
|
||||
Value: 1,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "seed",
|
||||
Usage: "The random seed",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "help, h",
|
||||
Usage: "Shows the help of the command",
|
||||
},
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/itchyny/maze"
|
||||
"github.com/nsf/termbox-go"
|
||||
)
|
||||
|
||||
type keyDir struct {
|
||||
key termbox.Key
|
||||
char rune
|
||||
dir int
|
||||
}
|
||||
|
||||
var keyDirs = []*keyDir{
|
||||
{termbox.KeyArrowUp, 'k', maze.Up},
|
||||
{termbox.KeyArrowDown, 'j', maze.Down},
|
||||
{termbox.KeyArrowLeft, 'h', maze.Left},
|
||||
{termbox.KeyArrowRight, 'l', maze.Right},
|
||||
}
|
||||
|
||||
func interactive(maze *maze.Maze, format *maze.Format) {
|
||||
events := make(chan termbox.Event)
|
||||
go func() {
|
||||
for {
|
||||
events <- termbox.PollEvent()
|
||||
}
|
||||
}()
|
||||
strwriter := make(chan string)
|
||||
ticker := time.NewTicker(10 * time.Millisecond)
|
||||
go printTermbox(maze, strwriter, time.Now())
|
||||
maze.Started = true
|
||||
maze.Write(strwriter, format)
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case event := <-events:
|
||||
if event.Type == termbox.EventKey {
|
||||
if !maze.Finished {
|
||||
for _, keydir := range keyDirs {
|
||||
if event.Key == keydir.key || event.Ch == keydir.char {
|
||||
maze.Move(keydir.dir)
|
||||
if maze.Finished {
|
||||
maze.Solve()
|
||||
}
|
||||
maze.Write(strwriter, format)
|
||||
continue loop
|
||||
}
|
||||
}
|
||||
if event.Key == termbox.KeyCtrlZ || event.Ch == 'u' {
|
||||
maze.Undo()
|
||||
maze.Write(strwriter, format)
|
||||
} else if event.Ch == 's' {
|
||||
if maze.Solved {
|
||||
maze.Clear()
|
||||
} else {
|
||||
maze.Solve()
|
||||
}
|
||||
maze.Write(strwriter, format)
|
||||
}
|
||||
}
|
||||
if event.Ch == 'q' || event.Ch == 'Q' || event.Key == termbox.KeyCtrlC || event.Key == termbox.KeyCtrlD {
|
||||
break loop
|
||||
}
|
||||
}
|
||||
case <-ticker.C:
|
||||
if !maze.Finished {
|
||||
strwriter <- "\u0000"
|
||||
}
|
||||
}
|
||||
}
|
||||
ticker.Stop()
|
||||
}
|
||||
|
||||
func printTermbox(maze *maze.Maze, strwriter chan string, start time.Time) {
|
||||
x, y := 1, 0
|
||||
for {
|
||||
str := <-strwriter
|
||||
switch str {
|
||||
case "\u0000":
|
||||
printFinished(maze, time.Now().Sub(start))
|
||||
termbox.Flush()
|
||||
x, y = 1, 0
|
||||
default:
|
||||
printString(str, &x, &y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func printString(str string, x *int, y *int) {
|
||||
attr, skip, d0, d1, d := false, false, '0', '0', false
|
||||
fg, bg := termbox.ColorDefault, termbox.ColorDefault
|
||||
for _, c := range str {
|
||||
if c == '\n' {
|
||||
*x, *y = (*x)+1, 0
|
||||
} else if c == '\x1b' || attr && c == '[' {
|
||||
attr = true
|
||||
} else if attr && unicode.IsDigit(c) {
|
||||
if !skip {
|
||||
if d {
|
||||
d1 = c
|
||||
} else {
|
||||
d0, d = c, true
|
||||
}
|
||||
}
|
||||
} else if attr && c == ';' {
|
||||
skip = true
|
||||
} else if attr && c == 'm' {
|
||||
if d0 == '7' && d1 == '0' {
|
||||
fg, bg = termbox.AttrReverse, termbox.AttrReverse
|
||||
} else if d0 == '3' {
|
||||
fg, bg = termbox.Attribute(uint64(d1-'0'+1)), termbox.ColorDefault
|
||||
} else if d0 == '4' {
|
||||
fg, bg = termbox.ColorDefault, termbox.Attribute(uint64(d1-'0'+1))
|
||||
} else {
|
||||
fg, bg = termbox.ColorDefault, termbox.ColorDefault
|
||||
}
|
||||
attr, skip, d0, d1, d = false, false, '0', '0', false
|
||||
} else {
|
||||
termbox.SetCell(*y, *x, c, fg, bg)
|
||||
*y = *y + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func printFinished(maze *maze.Maze, duration time.Duration) {
|
||||
str := fmt.Sprintf("%8d.%02ds ", int64(duration/time.Second), int64((duration%time.Second)/1e7))
|
||||
fg, bg := termbox.ColorDefault, termbox.ColorDefault
|
||||
if maze.Finished {
|
||||
x, y := maze.Height, 2*maze.Width-6
|
||||
if y < 0 {
|
||||
y = 0
|
||||
}
|
||||
for j, s := range []string{
|
||||
" ",
|
||||
" Finished! ",
|
||||
str,
|
||||
" ",
|
||||
" Press q to quit ",
|
||||
" "} {
|
||||
for i, c := range s {
|
||||
termbox.SetCell(y+i, x+j, c, fg, bg)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i, c := range str {
|
||||
termbox.SetCell(4*maze.Width+i-8, 1, c, fg, bg)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
var name = "maze"
|
||||
var version = "v0.0.2"
|
||||
var description = "Maze generating and solving program"
|
||||
var author = "itchyny"
|
||||
|
||||
func main() {
|
||||
os.Exit(run(os.Args))
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMain(t *testing.T) {
|
||||
build, _ := filepath.Abs("../build")
|
||||
filepath.Walk("../test", func(path string, info os.FileInfo, err error) error {
|
||||
if strings.HasSuffix(path, ".sh") {
|
||||
cmd := exec.Command("bash", filepath.Base(path))
|
||||
cmd.Dir = filepath.Dir(path)
|
||||
cmd.Env = append(os.Environ(), "PATH="+build+":"+"/bin")
|
||||
stderr := new(bytes.Buffer)
|
||||
cmd.Stderr = stderr
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
t.Errorf("FAIL: execution failed: " + path + ": " + err.Error() + " " + stderr.String())
|
||||
} else {
|
||||
outfile := strings.TrimSuffix(path, filepath.Ext(path)) + ".txt"
|
||||
expected, err := ioutil.ReadFile(outfile)
|
||||
if err != nil {
|
||||
t.Errorf("FAIL: error on reading output file: " + outfile)
|
||||
} else if strings.HasPrefix(string(output), strings.TrimSuffix(string(expected), "\n")) {
|
||||
t.Logf("PASS: " + path + "\n")
|
||||
} else {
|
||||
t.Errorf("FAIL: output differs: " + path + "\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/codegangsta/cli"
|
||||
)
|
||||
|
||||
func run(args []string) int {
|
||||
app := newApp()
|
||||
if app.Run(args) != nil {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func newApp() *cli.App {
|
||||
app := cli.NewApp()
|
||||
app.Name = name
|
||||
app.HelpName = name
|
||||
app.Usage = description
|
||||
app.Version = version
|
||||
app.Author = author
|
||||
app.Flags = flags
|
||||
app.HideHelp = true
|
||||
app.Action = action
|
||||
return app
|
||||
}
|
||||
@@ -1,488 +0,0 @@
|
||||
package maze
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/png"
|
||||
"io"
|
||||
"math/rand"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Maze cell configurations
|
||||
// The paths of the maze is represented in the binary representation.
|
||||
const (
|
||||
Up = 1 << iota
|
||||
Down
|
||||
Left
|
||||
Right
|
||||
)
|
||||
|
||||
// The solution path is represented by (Up|Down|Left|Right) << SolutionOffset.
|
||||
// The user's path is represented by (Up|Down|Left|Right) << VisitedOffset.
|
||||
const (
|
||||
SolutionOffset = 4
|
||||
VisitedOffset = 8
|
||||
)
|
||||
|
||||
// Directions is the set of all the directions
|
||||
var Directions = []int{Up, Down, Left, Right}
|
||||
|
||||
// The differences in the x-y coordinate
|
||||
var dx = map[int]int{Up: -1, Down: 1, Left: 0, Right: 0}
|
||||
var dy = map[int]int{Up: 0, Down: 0, Left: -1, Right: 1}
|
||||
|
||||
// Opposite directions
|
||||
var Opposite = map[int]int{Up: Down, Down: Up, Left: Right, Right: Left}
|
||||
|
||||
// Point on the maze
|
||||
type Point struct {
|
||||
X, Y int
|
||||
}
|
||||
|
||||
// Equal judges the equality of the two points
|
||||
func (point *Point) Equal(target *Point) bool {
|
||||
return point.X == target.X && point.Y == target.Y
|
||||
}
|
||||
|
||||
// Advance the point forward by the argument direction
|
||||
func (point *Point) Advance(direction int) *Point {
|
||||
return &Point{point.X + dx[direction], point.Y + dy[direction]}
|
||||
}
|
||||
|
||||
// Maze represents the configuration of a maze
|
||||
type Maze struct {
|
||||
Directions [][]int
|
||||
Height int
|
||||
Width int
|
||||
Start *Point
|
||||
Goal *Point
|
||||
Cursor *Point
|
||||
Solved bool
|
||||
Started bool
|
||||
Finished bool
|
||||
}
|
||||
|
||||
// NewMaze creates a new maze
|
||||
func NewMaze(height int, width int) *Maze {
|
||||
var directions [][]int
|
||||
for x := 0; x < height; x++ {
|
||||
directions = append(directions, make([]int, width))
|
||||
}
|
||||
return &Maze{directions, height, width, &Point{0, 0}, &Point{height - 1, width - 1}, &Point{0, 0}, false, false, false}
|
||||
}
|
||||
|
||||
// Contains judges whether the argument point is inside the maze or not
|
||||
func (maze *Maze) Contains(point *Point) bool {
|
||||
return 0 <= point.X && point.X < maze.Height && 0 <= point.Y && point.Y < maze.Width
|
||||
}
|
||||
|
||||
// Neighbors gathers the nearest undecided points
|
||||
func (maze *Maze) Neighbors(point *Point) (neighbors []int) {
|
||||
for _, direction := range Directions {
|
||||
next := point.Advance(direction)
|
||||
if maze.Contains(next) && maze.Directions[next.X][next.Y] == 0 {
|
||||
neighbors = append(neighbors, direction)
|
||||
}
|
||||
}
|
||||
return neighbors
|
||||
}
|
||||
|
||||
// Connected judges whether the two points is connected by a path on the maze
|
||||
func (maze *Maze) Connected(point *Point, target *Point) bool {
|
||||
dir := maze.Directions[point.X][point.Y]
|
||||
for _, direction := range Directions {
|
||||
if dir&direction != 0 {
|
||||
next := point.Advance(direction)
|
||||
if next.X == target.X && next.Y == target.Y {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Next advances the maze path randomly and returns the new point
|
||||
func (maze *Maze) Next(point *Point) *Point {
|
||||
neighbors := maze.Neighbors(point)
|
||||
if len(neighbors) == 0 {
|
||||
return nil
|
||||
}
|
||||
direction := neighbors[rand.Int()%len(neighbors)]
|
||||
maze.Directions[point.X][point.Y] |= direction
|
||||
next := point.Advance(direction)
|
||||
maze.Directions[next.X][next.Y] |= Opposite[direction]
|
||||
return next
|
||||
}
|
||||
|
||||
// Generate the maze
|
||||
func (maze *Maze) Generate() {
|
||||
point := maze.Start
|
||||
stack := []*Point{point}
|
||||
for len(stack) > 0 {
|
||||
for {
|
||||
point = maze.Next(point)
|
||||
if point == nil {
|
||||
break
|
||||
}
|
||||
stack = append(stack, point)
|
||||
}
|
||||
i := rand.Int() % ((len(stack) + 1) / 2)
|
||||
point = stack[i]
|
||||
stack = append(stack[:i], stack[i+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
// Solve the maze
|
||||
func (maze *Maze) Solve() {
|
||||
if maze.Solved {
|
||||
return
|
||||
}
|
||||
point := maze.Start
|
||||
stack := []*Point{point}
|
||||
solution := []*Point{point}
|
||||
visited := 1 << 12
|
||||
// Repeat until we reach the goal
|
||||
for !point.Equal(maze.Goal) {
|
||||
maze.Directions[point.X][point.Y] |= visited
|
||||
for _, direction := range Directions {
|
||||
// Push the nearest points to the stack if not been visited yet
|
||||
if maze.Directions[point.X][point.Y]&direction == direction {
|
||||
next := point.Advance(direction)
|
||||
if maze.Directions[next.X][next.Y]&visited == 0 {
|
||||
stack = append(stack, next)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Pop the stack
|
||||
point = stack[len(stack)-1]
|
||||
stack = stack[:len(stack)-1]
|
||||
// We have reached to a dead end so we pop the solution
|
||||
for last := solution[len(solution)-1]; !maze.Connected(point, last); {
|
||||
solution = solution[:len(solution)-1]
|
||||
last = solution[len(solution)-1]
|
||||
}
|
||||
solution = append(solution, point)
|
||||
}
|
||||
// Fill the solution path on the maze
|
||||
for i, point := range solution {
|
||||
if i < len(solution)-1 {
|
||||
next := solution[i+1]
|
||||
for _, direction := range Directions {
|
||||
if maze.Directions[point.X][point.Y]&direction == direction {
|
||||
temp := point.Advance(direction)
|
||||
if next.X == temp.X && next.Y == temp.Y {
|
||||
maze.Directions[point.X][point.Y] |= direction << SolutionOffset
|
||||
maze.Directions[next.X][next.Y] |= Opposite[direction] << SolutionOffset
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
maze.Solved = true
|
||||
}
|
||||
|
||||
// Clear the solution
|
||||
func (maze *Maze) Clear() {
|
||||
all := Up | Down | Left | Right
|
||||
all |= all << VisitedOffset // Do not clear the user's path
|
||||
for _, directions := range maze.Directions {
|
||||
for j := range directions {
|
||||
directions[j] &= all
|
||||
}
|
||||
}
|
||||
maze.Solved = false
|
||||
}
|
||||
|
||||
// Move the cursor
|
||||
func (maze *Maze) Move(direction int) {
|
||||
point := maze.Cursor
|
||||
next := point.Advance(direction)
|
||||
// If there's a path on the maze, we can move the cursor
|
||||
if maze.Contains(next) && maze.Directions[point.X][point.Y]&direction == direction {
|
||||
maze.Directions[point.X][point.Y] ^= direction << VisitedOffset
|
||||
maze.Directions[next.X][next.Y] ^= Opposite[direction] << VisitedOffset
|
||||
maze.Cursor = next
|
||||
}
|
||||
maze.Started = true
|
||||
// Check if the cursor has reached the goal or not
|
||||
maze.Finished = maze.Cursor.Equal(maze.Goal)
|
||||
}
|
||||
|
||||
// Undo the visited path
|
||||
func (maze *Maze) Undo() {
|
||||
point := maze.Cursor
|
||||
next := point
|
||||
for {
|
||||
// Find the previous point
|
||||
for _, direction := range Directions {
|
||||
if (maze.Directions[point.X][point.Y]>>VisitedOffset)&direction != 0 {
|
||||
next = point.Advance(direction)
|
||||
maze.Directions[point.X][point.Y] ^= direction << VisitedOffset
|
||||
maze.Directions[next.X][next.Y] ^= Opposite[direction] << VisitedOffset
|
||||
break
|
||||
}
|
||||
}
|
||||
if point.Equal(next) {
|
||||
// Previous point was not found (for example: the start point)
|
||||
break
|
||||
} else {
|
||||
// Move backward
|
||||
point = next
|
||||
// If there's another path which has not been visited, stop the procedure
|
||||
count := 0
|
||||
for _, direction := range Directions {
|
||||
if maze.Directions[next.X][next.Y]&direction != 0 {
|
||||
count = count + 1
|
||||
}
|
||||
}
|
||||
// The path we came from, we visited once and another
|
||||
if count > 2 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// Move back the cursor
|
||||
maze.Cursor = point
|
||||
maze.Finished = maze.Cursor.Equal(maze.Goal)
|
||||
}
|
||||
|
||||
// Format is the printing format of the maze
|
||||
type Format struct {
|
||||
Wall string
|
||||
Path string
|
||||
StartLeft string
|
||||
StartRight string
|
||||
GoalLeft string
|
||||
GoalRight string
|
||||
Solution string
|
||||
SolutionStartLeft string
|
||||
SolutionStartRight string
|
||||
SolutionGoalLeft string
|
||||
SolutionGoalRight string
|
||||
Visited string
|
||||
VisitedStartLeft string
|
||||
VisitedStartRight string
|
||||
VisitedGoalLeft string
|
||||
VisitedGoalRight string
|
||||
Cursor string
|
||||
}
|
||||
|
||||
// Default format
|
||||
var Default = &Format{
|
||||
Wall: "##",
|
||||
Path: " ",
|
||||
StartLeft: "S ",
|
||||
StartRight: " S",
|
||||
GoalLeft: "G ",
|
||||
GoalRight: " G",
|
||||
Solution: "::",
|
||||
SolutionStartLeft: "S:",
|
||||
SolutionStartRight: ":S",
|
||||
SolutionGoalLeft: "G:",
|
||||
SolutionGoalRight: ":G",
|
||||
Visited: "..",
|
||||
VisitedStartLeft: "S.",
|
||||
VisitedStartRight: ".S",
|
||||
VisitedGoalLeft: "G.",
|
||||
VisitedGoalRight: ".G",
|
||||
Cursor: "::",
|
||||
}
|
||||
|
||||
// Color format
|
||||
var Color = &Format{
|
||||
Wall: "\x1b[7m \x1b[0m",
|
||||
Path: " ",
|
||||
StartLeft: "S ",
|
||||
StartRight: " S",
|
||||
GoalLeft: "G ",
|
||||
GoalRight: " G",
|
||||
Solution: "\x1b[44;1m \x1b[0m",
|
||||
SolutionStartLeft: "\x1b[44;1mS \x1b[0m",
|
||||
SolutionStartRight: "\x1b[44;1m S\x1b[0m",
|
||||
SolutionGoalLeft: "\x1b[44;1mG \x1b[0m",
|
||||
SolutionGoalRight: "\x1b[44;1m G\x1b[0m",
|
||||
Visited: "\x1b[42;1m \x1b[0m",
|
||||
VisitedStartLeft: "\x1b[42;1mS \x1b[0m",
|
||||
VisitedStartRight: "\x1b[42;1m S\x1b[0m",
|
||||
VisitedGoalLeft: "\x1b[42;1mG \x1b[0m",
|
||||
VisitedGoalRight: "\x1b[42;1m G\x1b[0m",
|
||||
Cursor: "\x1b[43;1m \x1b[0m",
|
||||
}
|
||||
|
||||
func plot(img *image.RGBA, x, y, scale int, c color.Color) {
|
||||
for dy := 0; dy < scale; dy++ {
|
||||
for dx := 0; dx < scale; dx++ {
|
||||
img.Set(x*scale+dx, y*scale+dy, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PrintImage outputs the maze to the IO writer as PNG image
|
||||
func (maze *Maze) PrintImage(writer io.Writer, format *Format, scale int) {
|
||||
var buf bytes.Buffer
|
||||
maze.Print(&buf, format)
|
||||
lines := strings.Split(strings.TrimSpace(buf.String()), "\n")
|
||||
for i, line := range lines {
|
||||
lines[i] = strings.TrimSpace(line)
|
||||
}
|
||||
width := len(lines[0]) / 2
|
||||
height := len(lines)
|
||||
img := image.NewRGBA(image.Rect(0, 0, width*scale, height*scale))
|
||||
red, green, yellow :=
|
||||
color.RGBA{255, 0, 0, 255},
|
||||
color.RGBA{0, 255, 0, 255},
|
||||
color.RGBA{255, 255, 0, 255}
|
||||
for y := 0; y < height; y++ {
|
||||
if y >= len(lines) {
|
||||
continue
|
||||
}
|
||||
for x := 0; x < width; x++ {
|
||||
if x*2 >= len(lines[y]) {
|
||||
continue
|
||||
}
|
||||
switch lines[y][x*2 : x*2+2] {
|
||||
case "##":
|
||||
plot(img, x, y, scale, color.Black)
|
||||
case "::":
|
||||
plot(img, x, y, scale, yellow)
|
||||
case "S ", " S", "S:", ":S":
|
||||
plot(img, x, y, scale, red)
|
||||
case "G ", " G", "G:", ":G":
|
||||
plot(img, x, y, scale, green)
|
||||
default:
|
||||
plot(img, x, y, scale, color.White)
|
||||
}
|
||||
}
|
||||
}
|
||||
png.Encode(writer, img)
|
||||
}
|
||||
|
||||
// Print out the maze to the IO writer
|
||||
func (maze *Maze) Print(writer io.Writer, format *Format) {
|
||||
strwriter := make(chan string)
|
||||
go maze.Write(strwriter, format)
|
||||
for {
|
||||
str := <-strwriter
|
||||
switch str {
|
||||
case "\u0000":
|
||||
return
|
||||
default:
|
||||
fmt.Fprint(writer, str)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write out the maze to the writer channel
|
||||
func (maze *Maze) Write(writer chan string, format *Format) {
|
||||
// If solved or started, it changes the appearance of the start and the goal
|
||||
startLeft := format.StartLeft
|
||||
if maze.Solved {
|
||||
startLeft = format.SolutionStartLeft
|
||||
} else if maze.Started {
|
||||
startLeft = format.VisitedStartLeft
|
||||
}
|
||||
startRight := format.StartRight
|
||||
if maze.Solved {
|
||||
startRight = format.SolutionStartRight
|
||||
} else if maze.Started {
|
||||
startRight = format.VisitedStartRight
|
||||
}
|
||||
goalLeft := format.GoalLeft
|
||||
if maze.Solved {
|
||||
goalLeft = format.SolutionGoalLeft
|
||||
} else if maze.Finished {
|
||||
goalLeft = format.VisitedGoalLeft
|
||||
}
|
||||
goalRight := format.GoalRight
|
||||
if maze.Solved {
|
||||
goalRight = format.SolutionGoalRight
|
||||
} else if maze.Finished {
|
||||
goalRight = format.VisitedGoalRight
|
||||
}
|
||||
// We can use & to check if the direction is the solution path or the path user has visited
|
||||
solved := (Up | Down | Left | Right) << SolutionOffset
|
||||
visited := (Up | Down | Left | Right) << VisitedOffset
|
||||
// Print out the maze
|
||||
writer <- "\n"
|
||||
for x, row := range maze.Directions {
|
||||
// There are two lines printed for each maze lines
|
||||
for _, direction := range []int{Up, Right} {
|
||||
writer <- format.Path // The left margin
|
||||
// The left wall
|
||||
if maze.Start.X == x && maze.Start.Y == 0 && direction == Right {
|
||||
writer <- startLeft
|
||||
} else if maze.Goal.X == x && maze.Goal.Y == 0 && maze.Width > 1 && direction == Right {
|
||||
writer <- goalLeft
|
||||
} else {
|
||||
writer <- format.Wall
|
||||
}
|
||||
for y, directions := range row {
|
||||
// In the `direction == Right` line, we print the path cell
|
||||
if direction == Right {
|
||||
if directions&solved != 0 {
|
||||
writer <- format.Solution
|
||||
} else if directions&visited != 0 {
|
||||
if maze.Cursor.X == x && maze.Cursor.Y == y {
|
||||
writer <- format.Cursor
|
||||
} else {
|
||||
writer <- format.Visited
|
||||
}
|
||||
} else {
|
||||
writer <- format.Path
|
||||
}
|
||||
}
|
||||
// Print the start or goal point on the right hand side
|
||||
if maze.Start.X == x && maze.Start.Y == y && y == maze.Width-1 && 0 < y && direction == Right {
|
||||
writer <- startRight
|
||||
} else if maze.Goal.X == x && maze.Goal.Y == y && y == maze.Width-1 && direction == Right {
|
||||
writer <- goalRight
|
||||
} else
|
||||
// Print the start or goal point on the top wall of the maze
|
||||
if maze.Start.X == x && maze.Start.Y == y && x == 0 && maze.Height > 1 && 0 < y && y < maze.Width-1 && direction == Up {
|
||||
writer <- startLeft
|
||||
} else if maze.Goal.X == x && maze.Goal.Y == y && x == 0 && maze.Height > 1 && 0 < y && y < maze.Width-1 && direction == Up {
|
||||
writer <- goalLeft
|
||||
} else
|
||||
// If there is a path in the direction (Up or Right) on the maze
|
||||
if directions&direction != 0 {
|
||||
// Print the path cell, or the solution cell if solved or the visited cells if the user visited
|
||||
if (directions>>SolutionOffset)&direction != 0 {
|
||||
writer <- format.Solution
|
||||
} else if (directions>>VisitedOffset)&direction != 0 {
|
||||
writer <- format.Visited
|
||||
} else {
|
||||
writer <- format.Path
|
||||
}
|
||||
} else {
|
||||
// Print the wall cell
|
||||
writer <- format.Wall
|
||||
}
|
||||
// In the `direction == Up` line, we print the wall cell
|
||||
if direction == Up {
|
||||
writer <- format.Wall
|
||||
}
|
||||
}
|
||||
writer <- "\n"
|
||||
}
|
||||
}
|
||||
// Print the bottom wall of the maze
|
||||
writer <- format.Path
|
||||
writer <- format.Wall
|
||||
for y := 0; y < maze.Width; y++ {
|
||||
if maze.Start.X == maze.Height-1 && maze.Start.Y == y && maze.Height > 1 && 0 < y && y < maze.Width-1 {
|
||||
writer <- startLeft
|
||||
} else if maze.Goal.X == maze.Height-1 && maze.Goal.Y == y && 0 < y && y < maze.Width-1 {
|
||||
writer <- goalRight
|
||||
} else {
|
||||
writer <- format.Wall
|
||||
}
|
||||
writer <- format.Wall
|
||||
}
|
||||
writer <- "\n\n"
|
||||
// Inform that we finished printing the maze
|
||||
writer <- "\u0000"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
maze --seed 0 --width 10 --height 10 --solution
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
##########################################
|
||||
S:::::::##::::::##::::::::::::::::::::::##
|
||||
######::##::##::##::## ##############::##
|
||||
##::::::##::##::::::## ## ## ##::##
|
||||
##::######::########## ## ## ######::##
|
||||
##::##::::::## ## ## ::##
|
||||
##::##::###### ########## ## ######::##
|
||||
##::::::## ## ##::::::##
|
||||
########## ###### ##############::## ##
|
||||
## ## ## ## ## ##::::::::::## ##
|
||||
## ## ## ## ## ## ##::########## ##
|
||||
## ## ## ## ##::::::::::## ##
|
||||
## ########## ########## ######::######
|
||||
## ## ## ##::::::##
|
||||
###### ## ## ######################::##
|
||||
## ## ## ##::::::::::##
|
||||
## ############## ## ## ##::##########
|
||||
## ## ## ## ##::::::::::##
|
||||
###### ## ## ######################::##
|
||||
## ## ## :::G
|
||||
##########################################
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
maze --seed 0 --format color --width 10 --height 10
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m
|
||||
S [7m [0m [7m [0m [7m [0m
|
||||
[7m [0m[7m [0m[7m [0m [7m [0m [7m [0m [7m [0m [7m [0m [7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m [7m [0m
|
||||
[7m [0m [7m [0m [7m [0m [7m [0m [7m [0m [7m [0m [7m [0m [7m [0m
|
||||
[7m [0m [7m [0m[7m [0m[7m [0m [7m [0m[7m [0m[7m [0m[7m [0m[7m [0m [7m [0m [7m [0m [7m [0m[7m [0m[7m [0m [7m [0m
|
||||
[7m [0m [7m [0m [7m [0m [7m [0m [7m [0m [7m [0m
|
||||
[7m [0m [7m [0m [7m [0m[7m [0m[7m [0m [7m [0m[7m [0m[7m [0m[7m [0m[7m [0m [7m [0m [7m [0m[7m [0m[7m [0m [7m [0m
|
||||
[7m [0m [7m [0m [7m [0m [7m [0m [7m [0m
|
||||
[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m [7m [0m[7m [0m[7m [0m [7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m [7m [0m [7m [0m
|
||||
[7m [0m [7m [0m [7m [0m [7m [0m [7m [0m [7m [0m [7m [0m [7m [0m
|
||||
[7m [0m [7m [0m [7m [0m [7m [0m [7m [0m [7m [0m [7m [0m [7m [0m[7m [0m[7m [0m[7m [0m[7m [0m [7m [0m
|
||||
[7m [0m [7m [0m [7m [0m [7m [0m [7m [0m [7m [0m [7m [0m
|
||||
[7m [0m [7m [0m[7m [0m[7m [0m[7m [0m[7m [0m [7m [0m[7m [0m[7m [0m[7m [0m[7m [0m [7m [0m[7m [0m[7m [0m [7m [0m[7m [0m[7m [0m
|
||||
[7m [0m [7m [0m [7m [0m [7m [0m [7m [0m
|
||||
[7m [0m[7m [0m[7m [0m [7m [0m [7m [0m [7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m [7m [0m
|
||||
[7m [0m [7m [0m [7m [0m [7m [0m [7m [0m
|
||||
[7m [0m [7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m [7m [0m [7m [0m [7m [0m [7m [0m[7m [0m[7m [0m[7m [0m[7m [0m
|
||||
[7m [0m [7m [0m [7m [0m [7m [0m [7m [0m [7m [0m
|
||||
[7m [0m[7m [0m[7m [0m [7m [0m [7m [0m [7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m [7m [0m
|
||||
[7m [0m [7m [0m [7m [0m G
|
||||
[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
maze --seed 0 --format color --width 10 --height 10 --solution
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m
|
||||
[44;1mS [0m[44;1m [0m[44;1m [0m[44;1m [0m[7m [0m[44;1m [0m[44;1m [0m[44;1m [0m[7m [0m[44;1m [0m[44;1m [0m[44;1m [0m[44;1m [0m[44;1m [0m[44;1m [0m[44;1m [0m[44;1m [0m[44;1m [0m[44;1m [0m[44;1m [0m[7m [0m
|
||||
[7m [0m[7m [0m[7m [0m[44;1m [0m[7m [0m[44;1m [0m[7m [0m[44;1m [0m[7m [0m[44;1m [0m[7m [0m [7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[44;1m [0m[7m [0m
|
||||
[7m [0m[44;1m [0m[44;1m [0m[44;1m [0m[7m [0m[44;1m [0m[7m [0m[44;1m [0m[44;1m [0m[44;1m [0m[7m [0m [7m [0m [7m [0m [7m [0m[44;1m [0m[7m [0m
|
||||
[7m [0m[44;1m [0m[7m [0m[7m [0m[7m [0m[44;1m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m [7m [0m [7m [0m [7m [0m[7m [0m[7m [0m[44;1m [0m[7m [0m
|
||||
[7m [0m[44;1m [0m[7m [0m[44;1m [0m[44;1m [0m[44;1m [0m[7m [0m [7m [0m [7m [0m [44;1m [0m[7m [0m
|
||||
[7m [0m[44;1m [0m[7m [0m[44;1m [0m[7m [0m[7m [0m[7m [0m [7m [0m[7m [0m[7m [0m[7m [0m[7m [0m [7m [0m [7m [0m[7m [0m[7m [0m[44;1m [0m[7m [0m
|
||||
[7m [0m[44;1m [0m[44;1m [0m[44;1m [0m[7m [0m [7m [0m [7m [0m[44;1m [0m[44;1m [0m[44;1m [0m[7m [0m
|
||||
[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m [7m [0m[7m [0m[7m [0m [7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[44;1m [0m[7m [0m [7m [0m
|
||||
[7m [0m [7m [0m [7m [0m [7m [0m [7m [0m [7m [0m[44;1m [0m[44;1m [0m[44;1m [0m[44;1m [0m[44;1m [0m[7m [0m [7m [0m
|
||||
[7m [0m [7m [0m [7m [0m [7m [0m [7m [0m [7m [0m [7m [0m[44;1m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m [7m [0m
|
||||
[7m [0m [7m [0m [7m [0m [7m [0m [7m [0m[44;1m [0m[44;1m [0m[44;1m [0m[44;1m [0m[44;1m [0m[7m [0m [7m [0m
|
||||
[7m [0m [7m [0m[7m [0m[7m [0m[7m [0m[7m [0m [7m [0m[7m [0m[7m [0m[7m [0m[7m [0m [7m [0m[7m [0m[7m [0m[44;1m [0m[7m [0m[7m [0m[7m [0m
|
||||
[7m [0m [7m [0m [7m [0m [7m [0m[44;1m [0m[44;1m [0m[44;1m [0m[7m [0m
|
||||
[7m [0m[7m [0m[7m [0m [7m [0m [7m [0m [7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[44;1m [0m[7m [0m
|
||||
[7m [0m [7m [0m [7m [0m [7m [0m[44;1m [0m[44;1m [0m[44;1m [0m[44;1m [0m[44;1m [0m[7m [0m
|
||||
[7m [0m [7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m [7m [0m [7m [0m [7m [0m[44;1m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m
|
||||
[7m [0m [7m [0m [7m [0m [7m [0m [7m [0m[44;1m [0m[44;1m [0m[44;1m [0m[44;1m [0m[44;1m [0m[7m [0m
|
||||
[7m [0m[7m [0m[7m [0m [7m [0m [7m [0m [7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[44;1m [0m[7m [0m
|
||||
[7m [0m [7m [0m [7m [0m [44;1m [0m[44;1m G[0m
|
||||
[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m[7m [0m
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
maze --seed 0 --width 10 --height 10
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
##########################################
|
||||
S ## ## ##
|
||||
###### ## ## ## ## ############## ##
|
||||
## ## ## ## ## ## ## ##
|
||||
## ###### ########## ## ## ###### ##
|
||||
## ## ## ## ## ##
|
||||
## ## ###### ########## ## ###### ##
|
||||
## ## ## ## ##
|
||||
########## ###### ############## ## ##
|
||||
## ## ## ## ## ## ## ##
|
||||
## ## ## ## ## ## ## ########## ##
|
||||
## ## ## ## ## ## ##
|
||||
## ########## ########## ###### ######
|
||||
## ## ## ## ##
|
||||
###### ## ## ###################### ##
|
||||
## ## ## ## ##
|
||||
## ############## ## ## ## ##########
|
||||
## ## ## ## ## ##
|
||||
###### ## ## ###################### ##
|
||||
## ## ## G
|
||||
##########################################
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
maze --seed 0 --width 10 --height 10 --goal 9,5 --solution
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
##########################################
|
||||
S:::::::##::::::##::::::::::::::::::::::##
|
||||
######::##::##::##::## ##############::##
|
||||
##::::::##::##::::::## ## ## ##::##
|
||||
##::######::########## ## ## ######::##
|
||||
##::##::::::## ## ## ::##
|
||||
##::##::###### ########## ## ######::##
|
||||
##::::::## ## ##::::::##
|
||||
########## ###### ##############::## ##
|
||||
## ## ## ## ## ##::::::::::## ##
|
||||
## ## ## ## ## ## ##::########## ##
|
||||
## ## ## ## ##::::::::::## ##
|
||||
## ########## ########## ######::######
|
||||
## ## ## ##::::::##
|
||||
###### ## ## ######################::##
|
||||
## ## ## ##::::::::::##
|
||||
## ############## ## ## ##::##########
|
||||
## ## ## ## ##::::::::::##
|
||||
###### ## ## ######################::##
|
||||
## ## ## ::::::::::::::::::##
|
||||
######################:G##################
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
maze --seed 0 --width 10 --height 10 --goal 9,0 --solution
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
##########################################
|
||||
S:::::::##::::::##::::::::::::::::::::::##
|
||||
######::##::##::##::## ##############::##
|
||||
##::::::##::##::::::## ## ## ##::##
|
||||
##::######::########## ## ## ######::##
|
||||
##::##::::::## ## ## ::##
|
||||
##::##::###### ########## ## ######::##
|
||||
##::::::## ## ##::::::##
|
||||
########## ###### ##############::## ##
|
||||
## ## ## ## ## ##::::::::::## ##
|
||||
## ## ## ## ## ## ##::########## ##
|
||||
## ## ## ## ##:: ## ##
|
||||
## ########## ##########::###### ######
|
||||
## ##::::::##:::::::::::::: ## ##
|
||||
######::##::##::###################### ##
|
||||
##::::::##:::::: ## ## ##
|
||||
##::############## ## ## ## ##########
|
||||
##::::::## ## ## ## ##
|
||||
######::## ## ###################### ##
|
||||
G:::::::## ## ##
|
||||
##########################################
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
maze --seed 0 --width 10 --height 10 --goal 5,0 --solution
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
##########################################
|
||||
S:::::::##::::::##:::::: ##
|
||||
######::##::##::##::##::############## ##
|
||||
##::::::##::##::::::##::## ## ## ##
|
||||
##::######::##########::## ## ###### ##
|
||||
##::##::::::##::::::::::## ## ##
|
||||
##::##::######::########## ## ###### ##
|
||||
##::::::##::::::## ## ##
|
||||
##########::###### ############## ## ##
|
||||
##::::::##::## ## ## ## ## ##
|
||||
##::##::##::## ## ## ## ########## ##
|
||||
G:::##::::::## ## ## ## ##
|
||||
## ########## ########## ###### ######
|
||||
## ## ## ## ##
|
||||
###### ## ## ###################### ##
|
||||
## ## ## ## ##
|
||||
## ############## ## ## ## ##########
|
||||
## ## ## ## ## ##
|
||||
###### ## ## ###################### ##
|
||||
## ## ## ##
|
||||
##########################################
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
maze --seed 0 --width 10 --height 10 --goal 0,5 --solution
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
######################G:##################
|
||||
S:::::::##::::::##:::::: ##
|
||||
######::##::##::##::## ############## ##
|
||||
##::::::##::##::::::## ## ## ## ##
|
||||
##::######::########## ## ## ###### ##
|
||||
##::##::::::## ## ## ##
|
||||
##::##::###### ########## ## ###### ##
|
||||
##::::::## ## ## ##
|
||||
########## ###### ############## ## ##
|
||||
## ## ## ## ## ## ## ##
|
||||
## ## ## ## ## ## ## ########## ##
|
||||
## ## ## ## ## ## ##
|
||||
## ########## ########## ###### ######
|
||||
## ## ## ## ##
|
||||
###### ## ## ###################### ##
|
||||
## ## ## ## ##
|
||||
## ############## ## ## ## ##########
|
||||
## ## ## ## ## ##
|
||||
###### ## ## ###################### ##
|
||||
## ## ## ##
|
||||
##########################################
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
maze --seed 0 --width 10 --height 10 --goal 0,9 --solution
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
##########################################
|
||||
S:::::::##::::::##:::::::::::::::::::::::G
|
||||
######::##::##::##::## ############## ##
|
||||
##::::::##::##::::::## ## ## ## ##
|
||||
##::######::########## ## ## ###### ##
|
||||
##::##::::::## ## ## ##
|
||||
##::##::###### ########## ## ###### ##
|
||||
##::::::## ## ## ##
|
||||
########## ###### ############## ## ##
|
||||
## ## ## ## ## ## ## ##
|
||||
## ## ## ## ## ## ## ########## ##
|
||||
## ## ## ## ## ## ##
|
||||
## ########## ########## ###### ######
|
||||
## ## ## ## ##
|
||||
###### ## ## ###################### ##
|
||||
## ## ## ## ##
|
||||
## ############## ## ## ## ##########
|
||||
## ## ## ## ## ##
|
||||
###### ## ## ###################### ##
|
||||
## ## ## ##
|
||||
##########################################
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
maze --seed 0 --width 10 --height 1
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
##########################################
|
||||
S G
|
||||
##########################################
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
maze --seed 0 --width 10 --height 1 --solution
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
##########################################
|
||||
S::::::::::::::::::::::::::::::::::::::::G
|
||||
##########################################
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
maze --help
|
||||
@@ -1,7 +0,0 @@
|
||||
NAME:
|
||||
maze - Maze generating and solving program
|
||||
|
||||
USAGE:
|
||||
maze [global options] [arguments...]
|
||||
|
||||
VERSION:
|
||||
@@ -1 +0,0 @@
|
||||
maze --seed 0 --width 1 --height 1
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
######
|
||||
S G
|
||||
######
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
maze --seed 0 --width 10 --height 10 --output .tmp; cat .tmp; rm .tmp
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
##########################################
|
||||
S ## ## ##
|
||||
###### ## ## ## ## ############## ##
|
||||
## ## ## ## ## ## ## ##
|
||||
## ###### ########## ## ## ###### ##
|
||||
## ## ## ## ## ##
|
||||
## ## ###### ########## ## ###### ##
|
||||
## ## ## ## ##
|
||||
########## ###### ############## ## ##
|
||||
## ## ## ## ## ## ## ##
|
||||
## ## ## ## ## ## ## ########## ##
|
||||
## ## ## ## ## ## ##
|
||||
## ########## ########## ###### ######
|
||||
## ## ## ## ##
|
||||
###### ## ## ###################### ##
|
||||
## ## ## ## ##
|
||||
## ############## ## ## ## ##########
|
||||
## ## ## ## ## ##
|
||||
###### ## ## ###################### ##
|
||||
## ## ## G
|
||||
##########################################
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
maze --seed 1 --width 10 --height 10
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
##########################################
|
||||
S ## ## ## ## ##
|
||||
## ## ###### ## ## ## ###### ## ##
|
||||
## ## ## ## ## ## ##
|
||||
########## ## ########## ## ###### ##
|
||||
## ## ## ## ##
|
||||
## ############## ############## ## ##
|
||||
## ## ## ##
|
||||
########## ## ## ############## ######
|
||||
## ## ## ## ## ## ##
|
||||
## ## ###### ########## ## ###### ##
|
||||
## ## ## ## ## ##
|
||||
## ########## ## ############## ## ##
|
||||
## ## ## ## ## ## ##
|
||||
########## ###### ## ## ## ## ## ##
|
||||
## ## ## ## ## ## ## ## ##
|
||||
## ## ## ## ###### ## ## ## ## ##
|
||||
## ## ## ## ## ## ## ## ##
|
||||
## ################## ## ###### ## ##
|
||||
## ## ## G
|
||||
##########################################
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
maze --seed 2 --width 10 --height 10
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
##########################################
|
||||
S ## ## ## ##
|
||||
## ###### ## ## ## ########## ## ##
|
||||
## ## ## ## ## ## ##
|
||||
## ## ## ## ## ########## ##########
|
||||
## ## ## ## ## ## ##
|
||||
## ## ########## ## ## ###### ## ##
|
||||
## ## ## ## ## ## ## ##
|
||||
## ## ## ## ## ## ############## ##
|
||||
## ## ## ## ## ## ## ##
|
||||
## ###### ## ############## ## ######
|
||||
## ## ## ## ##
|
||||
###################### ## ########## ##
|
||||
## ## ## ## ##
|
||||
## ## ###### ## ################## ##
|
||||
## ## ## ## ## ## ##
|
||||
## ## ########## ## ########## ## ##
|
||||
## ## ## ## ## ## ## ##
|
||||
## ## ## ## ###### ## ########## ##
|
||||
## ## ## G
|
||||
##########################################
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
maze --seed 0 --width 3 --height 3
|
||||
@@ -1,9 +0,0 @@
|
||||
|
||||
##############
|
||||
S ## ##
|
||||
###### ## ##
|
||||
## ## ##
|
||||
## ###### ##
|
||||
## G
|
||||
##############
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
maze --seed 0 --width 10 --height 10 --start 9,5 --solution
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
##########################################
|
||||
## ## ## ## ##
|
||||
## ###### ## ###### ## ## ## ## ##
|
||||
## ## ## ## ## ## ## ##
|
||||
###### ########## ## ############## ##
|
||||
## ## ## ## ##
|
||||
## ###### ########## ###### ## ######
|
||||
## ## ## ## ## ## ##
|
||||
################## ## ## ## ###### ##
|
||||
## ## ## ## ## ## ##
|
||||
## ## ## ## ###### ## ## ## ######
|
||||
## ## ## ## ## ## ## ## ##
|
||||
## ########## ###### ## ## ## ## ##
|
||||
## ## ## ## ## ## ## ##
|
||||
## ############## ## ## ## ## ## ##
|
||||
## ## ## ## ## ## ## ##
|
||||
## ## ## ## ###### ########## ## ##
|
||||
## ## ## ## ## ##
|
||||
## ## ########## ###### ########## ##
|
||||
## ## ##:::::::::::::::::::G
|
||||
######################S:##################
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
maze --seed 0 --width 10 --height 10 --start 9,0 --solution
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
##########################################
|
||||
## ## ## ## ##
|
||||
## ## ## ########## ###### ## ## ##
|
||||
## ## ## ## ## ## ## ##
|
||||
## ## ## ## ## ###### ########## ##
|
||||
## ## ## ## ## ## ##
|
||||
###### ########## ## ########## ######
|
||||
## ## ## ## ## ##
|
||||
## ## ###### ###### ## ########## ##
|
||||
## ## ## ## ##
|
||||
## ## ## ###### ######################
|
||||
## ## ## ## ## ##
|
||||
###### ## ########## ## ## ###### ##
|
||||
## ## ## ##::::::::::## ##
|
||||
## ################## ##::######::######
|
||||
## ## ## ##::::::##::::::##
|
||||
## ## ########## ##########::######::##
|
||||
## ## ##::::::::::## ::##
|
||||
###### ##############::########## ##::##
|
||||
S:::::::::::::::::::::::## ##:::G
|
||||
##########################################
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
maze --seed 0 --width 10 --height 10 --start 9,9 --goal 0,0 --solution
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
##########################################
|
||||
G:::##::::::##:::::::::::::: ##
|
||||
##::##::##::##::##########::## ##########
|
||||
##::::::##::##::## ##::## ## ##
|
||||
##########::##::## ######::## ## ## ##
|
||||
## ##::::::## ## ::## ## ##
|
||||
## ## ########## ## ##::########## ##
|
||||
## ## ## ## ##::## ## ##
|
||||
## ###### ## ## ######::###### ## ##
|
||||
## ## ## ## ::## ## ##
|
||||
###### ## ########## ##::## ###### ##
|
||||
## ## ## ##::## ## ##
|
||||
## ########## ## ######::## ## ## ##
|
||||
## ## ## ##::## ## ##
|
||||
###### ## ## ##########::## ##########
|
||||
## ## ## ## ::## ##
|
||||
## ## ########## ######::########## ##
|
||||
## ## ## ##::::::::::## ##
|
||||
## ########## ###### ##########::######
|
||||
## ## ##:::::::S
|
||||
##########################################
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
maze --seed 0 --width 10 --height 10 --start 5,0 --solution
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
##########################################
|
||||
## ::::::## ## ##
|
||||
## ##::##::## ## ############## ######
|
||||
## ##::##::## ## ## ## ##
|
||||
######::##::## ########## ## ###### ##
|
||||
##::::::##::## ## ## ## ## ##
|
||||
##::######::## ## ## ## ## ## ######
|
||||
##:: ##::## ## ## ## ##
|
||||
##::######::########## ## ## ###### ##
|
||||
##::::::##:: ## ## ## ## ##
|
||||
######::##::## ############## ###### ##
|
||||
S:::::::##::## ## ## ##
|
||||
## ## ##::############## ## ## ######
|
||||
## ## ##::##::::::## ## ## ## ##
|
||||
## ######::##::##::## ## ## ###### ##
|
||||
## ##::##::##::## ## ## ##
|
||||
###### ##::##::##::## ########## ######
|
||||
## ##::##::##:: ##::::::::::## ##
|
||||
## ######::##::##::######::######::## ##
|
||||
## ##::::::##::::::::::## :::::::G
|
||||
##########################################
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
maze --seed 0 --width 10 --height 10 --start 5,9 --solution
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
##########################################
|
||||
## ## ## ## ##
|
||||
## ###### ## ###### ## ## ###### ##
|
||||
## ## ## ## ## ## ##
|
||||
## ## ########## ## ## ## ## ## ##
|
||||
## ## ## ## ## ## ## ## ##
|
||||
## ## ## ########## ## ## ## ## ##
|
||||
## ## ## ## ## ## ## ## ##
|
||||
## ###### ## ## ## ## ########## ##
|
||||
## ## ## ##::::::::::## ##
|
||||
## ######################::######::######
|
||||
## ## ## ::::::##:::::::S
|
||||
## ## ########## ##########::##########
|
||||
## ## ## ##:::::: ##
|
||||
## ## ############## ##::########## ##
|
||||
## ## ## ## ##::::::::::## ##
|
||||
## ###### ## ###### ##########::######
|
||||
## ## ## ## ## ##::::::##
|
||||
###### ## ###### ## ## ## ######::##
|
||||
## ## ## ## :::G
|
||||
##########################################
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
maze --seed 0 --width 10 --height 10 --start 0,5 --solution
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
######################S:##################
|
||||
## ## ##::::::## ## ##
|
||||
########## ## ##########::## ## ## ##
|
||||
## ## ::::::## ## ##
|
||||
## ##################::############## ##
|
||||
## ## ## ##::::::::::## ##
|
||||
## ## ## ## ## ## ######::## ######
|
||||
## ## ## ## ##::::::## ##
|
||||
## ############## ## ##::########## ##
|
||||
## ## ## ## ##::## ##
|
||||
## ## ## ###### ## ##::## ##########
|
||||
## ## ## ## ##::## ## ##
|
||||
## ########## ## ## ##::## ## ## ##
|
||||
## ## ## ## ##::## ## ##
|
||||
## ## ############## ##::########## ##
|
||||
## ## ## ## ##::## ##::::::##
|
||||
## ###### ###### ## ##::## ##::##::##
|
||||
## ## ## ## ##::##::::::##::##
|
||||
###### ## ## ###### ##::##::######::##
|
||||
## ## ##::::::## :::G
|
||||
##########################################
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
maze --seed 0 --width 10 --height 10 --start 0,9 --solution
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
##########################################
|
||||
## ## ## ## ## :::S
|
||||
## ## ## ###### ## ## ###### ##::##
|
||||
## ## ## ## ## ## ##::##
|
||||
## ## ###### ## ##################::##
|
||||
## ## ## ##::::::::::::::##::##
|
||||
## ###### ##########::###### ##::##::##
|
||||
## ## ##::::::::::## ##::##::##
|
||||
## ## ######::## ##############::##::##
|
||||
## ## ::## ## ## ::::::##
|
||||
## ###### ##::## ###### ## ##########
|
||||
## ##::## ## ## ##
|
||||
##############::################## ## ##
|
||||
## ##::::::::::##::::::## ##
|
||||
## ###### ##########::##::##::##########
|
||||
## ## ## ::::::##::::::::::##
|
||||
## ## ###### ############## ######::##
|
||||
## ## ## ## ## ## ::##
|
||||
## ## ########## ## ## ###### ##::##
|
||||
## ## ## ## ##:::G
|
||||
##########################################
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
maze --version
|
||||
@@ -1 +0,0 @@
|
||||
maze version v
|
||||
@@ -1 +0,0 @@
|
||||
maze --seed 0 --width 1 --height 10
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
######
|
||||
S ##
|
||||
## ##
|
||||
## ##
|
||||
## ##
|
||||
## ##
|
||||
## ##
|
||||
## ##
|
||||
## ##
|
||||
## ##
|
||||
## ##
|
||||
## ##
|
||||
## ##
|
||||
## ##
|
||||
## ##
|
||||
## ##
|
||||
## ##
|
||||
## ##
|
||||
## ##
|
||||
## G
|
||||
######
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
maze --seed 0 --width 1 --height 10 --solution
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
######
|
||||
S:::##
|
||||
##::##
|
||||
##::##
|
||||
##::##
|
||||
##::##
|
||||
##::##
|
||||
##::##
|
||||
##::##
|
||||
##::##
|
||||
##::##
|
||||
##::##
|
||||
##::##
|
||||
##::##
|
||||
##::##
|
||||
##::##
|
||||
##::##
|
||||
##::##
|
||||
##::##
|
||||
##:::G
|
||||
######
|
||||
|
||||
229
modules/vulnerabilities/unix/ctf/programming/maze/files/maze.rb
Normal file
229
modules/vulnerabilities/unix/ctf/programming/maze/files/maze.rb
Normal file
@@ -0,0 +1,229 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
#
|
||||
# A node is both a member of a directed graph, and a cell on an x,y
|
||||
# plane of possibly-connected maze passages.
|
||||
#
|
||||
class Node
|
||||
attr_accessor :row, :col, :visited, :neighbors, :on_path
|
||||
|
||||
def initialize(row, col)
|
||||
@row = row
|
||||
@col = col
|
||||
@visited = false
|
||||
@on_path = false
|
||||
@neighbors = {north: nil, east: nil, south: nil, west: nil}
|
||||
end
|
||||
|
||||
# Connect this node to another node. The other node can only fit
|
||||
# in one of four cardinal directions from this node: North, South,
|
||||
# East, or West.
|
||||
def connect_to(other)
|
||||
if other.row == self.row - 1
|
||||
self.neighbors[:north] = other
|
||||
other.neighbors[:south] = self
|
||||
elsif other.row == self.row + 1
|
||||
self.neighbors[:south] = other
|
||||
other.neighbors[:north] = self
|
||||
elsif other.col == self.col + 1
|
||||
self.neighbors[:east] = other
|
||||
other.neighbors[:west] = self
|
||||
elsif other.col == self.col - 1
|
||||
self.neighbors[:west] = other
|
||||
other.neighbors[:east] = self
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# A Maze is a container for Nodes, and is responsible for:
|
||||
# - generating a maze by connecting unconnected nodes, and
|
||||
# - finding a solution through an existing maze of connected nodes.
|
||||
#
|
||||
class Maze
|
||||
|
||||
DIRECTIONS = [[-1, 0], [1, 0], [0, -1], [0, 1]]
|
||||
|
||||
def initialize(rows, cols)
|
||||
@rows = rows
|
||||
@cols = cols
|
||||
|
||||
# Initialize the maze with a bunch of un-connected nodes
|
||||
@maze = Array.new(@rows) do |r|
|
||||
Array.new(@cols) do |c|
|
||||
Node.new(r, c)
|
||||
end
|
||||
end
|
||||
|
||||
# Pick start and end nodes on opposite ends.
|
||||
@start_node = @maze[rand(@rows)][0]
|
||||
@end_node = @maze[rand(@rows)][@cols - 1]
|
||||
end
|
||||
|
||||
# Generate the maze.
|
||||
def generate
|
||||
# Make a stack of nodes along our walk
|
||||
stack = []
|
||||
|
||||
# Visit the first node
|
||||
node = @start_node
|
||||
node.visited = true
|
||||
stack.push(node)
|
||||
|
||||
# Now keep walking and finding nodes.
|
||||
while true
|
||||
next_node = get_next_unvisited(node)
|
||||
if next_node
|
||||
next_node.visited = true
|
||||
next_node.connect_to(node)
|
||||
stack.push(next_node)
|
||||
node = next_node
|
||||
else
|
||||
node = stack.pop
|
||||
break if !node
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def solve
|
||||
# Reset visited state on all nodes.
|
||||
@maze.each do |row|
|
||||
row.each do |node|
|
||||
node.visited = false
|
||||
end
|
||||
end
|
||||
|
||||
stack = []
|
||||
|
||||
# Visit the first node
|
||||
node = @start_node
|
||||
node.visited = true
|
||||
node.on_path = true
|
||||
|
||||
while true
|
||||
next_node = get_next_in_graph(node)
|
||||
|
||||
if next_node
|
||||
next_node.visited = true
|
||||
next_node.on_path = true
|
||||
|
||||
# If we're at the exit, we're done.
|
||||
break if next_node == @end_node
|
||||
|
||||
# Otherwise, push onto the stack and keep going.
|
||||
stack.push(node)
|
||||
node = next_node
|
||||
else
|
||||
# This would only happen if there were no solution.
|
||||
break if stack.size == 0
|
||||
|
||||
# 'node' has no un-visited neighbors, so it can't be on the
|
||||
# path.
|
||||
node.on_path = false
|
||||
node = stack.pop
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# When walking a completed maze, we are doing a random walk of a
|
||||
# directed graph, so it's simpler than the random walk to create the
|
||||
# maze.
|
||||
def get_next_in_graph(node)
|
||||
node.neighbors.values.compact.shuffle
|
||||
.select {|neighbor| !neighbor.visited }.first
|
||||
end
|
||||
|
||||
# When generating a new maze, we need to find the next un-visited
|
||||
# neighboring node.
|
||||
def get_next_unvisited(node)
|
||||
neighbors = []
|
||||
|
||||
DIRECTIONS.each do |dir|
|
||||
new_row = node.row + dir[0]
|
||||
new_col = node.col + dir[1]
|
||||
|
||||
if new_row >= 0 && new_row < @rows &&
|
||||
new_col >= 0 && new_col < @cols &&
|
||||
!@maze[new_row][new_col].visited
|
||||
neighbors << @maze[new_row][new_col]
|
||||
end
|
||||
end
|
||||
|
||||
neighbors[rand(neighbors.length)]
|
||||
end
|
||||
|
||||
def to_s
|
||||
buf = ""
|
||||
|
||||
@maze.each_with_index do |row, idx|
|
||||
# Pass one.
|
||||
row.each do |node|
|
||||
buf << if node.neighbors[:north]
|
||||
"+ "
|
||||
else
|
||||
"+---"
|
||||
end
|
||||
|
||||
buf << if node.col == @cols - 1
|
||||
"+"
|
||||
else
|
||||
""
|
||||
end
|
||||
end
|
||||
|
||||
buf << "\r\n"
|
||||
|
||||
# Pass two
|
||||
row.each do |node|
|
||||
buf << if node.neighbors[:west] || node == @start_node
|
||||
" "
|
||||
else
|
||||
"|"
|
||||
end
|
||||
|
||||
buf << if node.on_path
|
||||
" @ "
|
||||
else
|
||||
" "
|
||||
end
|
||||
|
||||
if node.col == @cols - 1
|
||||
buf << if node == @end_node
|
||||
" "
|
||||
else
|
||||
"|"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
buf << "\r\n"
|
||||
|
||||
# Pass three, if last row
|
||||
if idx == @rows - 1
|
||||
row.each do |node|
|
||||
buf << "+---"
|
||||
end
|
||||
buf << "+\r\n"
|
||||
end
|
||||
end
|
||||
|
||||
buf
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
rows = ARGV[0].to_i
|
||||
cols = ARGV[1].to_i
|
||||
|
||||
if rows <= 0 || cols <= 0
|
||||
puts "Usage: #{$0} <rows> <cols>"
|
||||
exit -1
|
||||
end
|
||||
|
||||
maze = Maze.new(rows, cols)
|
||||
maze.generate
|
||||
puts maze
|
||||
puts "*********"
|
||||
maze.solve
|
||||
puts maze
|
||||
@@ -0,0 +1,9 @@
|
||||
class maze::conf {
|
||||
$secgen_params = secgen_functions::get_parameters($::base64_inputs_file)
|
||||
|
||||
|
||||
# Make it generate 100 mazes + solutions
|
||||
|
||||
# Set permissions
|
||||
|
||||
}
|
||||
@@ -1,31 +1,46 @@
|
||||
class maze::install {
|
||||
$secgen_params = secgen_functions::get_parameters($::base64_inputs_file)
|
||||
$challenge_name = $secgen_params['test'][0]
|
||||
$maze_dir = '/vagrant/src/maze'
|
||||
$challenge_name = $secgen_params['challenge_name'][0]
|
||||
|
||||
Exec { path => '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/go/bin:/vagrant/bin' }
|
||||
|
||||
::secgen_functions::create_directory { "create_$challenge_directory":
|
||||
path => $maze_dir,
|
||||
notify => File['copy maze dir'],
|
||||
if ($secgen_params['account'] and $secgen_params['account'][0]) {
|
||||
$acc = parsejson($secgen_params['account'][0])
|
||||
$username = $acc['username']
|
||||
$challenge_dir = "/home/$username/$challenge_name"
|
||||
} elsif $secgen_params['storage_directory'] and $secgen_params['storage_directory'][0] {
|
||||
$storage_dir = $secgen_params['storage_directory'][0]
|
||||
$challenge_dir = "$storage_dir/$challenge_name"
|
||||
} else {
|
||||
$challenge_dir = "/root/$challenge_name"
|
||||
}
|
||||
|
||||
file { 'copy maze dir':
|
||||
path => $maze_dir,
|
||||
ensure => directory,
|
||||
recurse => true,
|
||||
source => 'puppet:///modules/maze/maze-master',
|
||||
notify => Exec['make maze'],
|
||||
if $secgen_params['group'] and $secgen_params['group'][0] {
|
||||
$group = $secgen_params['group'][0]
|
||||
} else {
|
||||
$group = $challenge_name
|
||||
}
|
||||
|
||||
exec { 'make maze':
|
||||
cwd => $maze_dir,
|
||||
command => 'env DEPNOLOCK=1 make',
|
||||
notify => Exec['install maze'],
|
||||
# Move dependent maze generation script onto box
|
||||
file { 'move maze.rb':
|
||||
path => "$challenge_dir/maze.rb",
|
||||
source => 'puppet:///modules/maze/maze.rb',
|
||||
owner => 'root',
|
||||
group => $group,
|
||||
mode => '0440',
|
||||
}
|
||||
|
||||
exec { 'install maze':
|
||||
cwd => "$maze_dir/build",
|
||||
command => 'install maze /usr/local/bin',
|
||||
# Configure setgid wrapper script
|
||||
::secgen_functions::install_setgid_script { $challenge_name:
|
||||
source_module_name => $module_name,
|
||||
challenge_name => $challenge_name,
|
||||
script_name => 'test.rb',
|
||||
script_data => template('maze/challenge_script.rb.erb'),
|
||||
group => $secgen_params['group'],
|
||||
account => $secgen_params['account'],
|
||||
flag => $secgen_params['flag'],
|
||||
port => $secgen_params['port'],
|
||||
storage_directory => $secgen_params['storage_directory'],
|
||||
strings_to_leak => $secgen_params['strings_to_leak'],
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
include maze::install
|
||||
include maze::conf
|
||||
@@ -4,8 +4,8 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/vulnerability">
|
||||
<name>Maze Solving Challenge</name>
|
||||
<author>itchyny</author>
|
||||
<author>Thomas Shaw</author>
|
||||
<author>itchyny</author>
|
||||
<module_license>MIT</module_license>
|
||||
<description>TODO</description>
|
||||
|
||||
@@ -18,71 +18,54 @@
|
||||
<challenge_subtype>programming</challenge_subtype>
|
||||
<difficulty>medium</difficulty>
|
||||
|
||||
<read_fact>test</read_fact>
|
||||
<!-- script dropped in account's home directory by default with setuid configuration. -->
|
||||
<read_fact>challenge_name</read_fact>
|
||||
<read_fact>account</read_fact>
|
||||
<read_fact>flag</read_fact>
|
||||
<!-- group: Blank by default. Uses challenge name as group name unless explicitly provided. -->
|
||||
<read_fact>group</read_fact>
|
||||
<!-- storage_directory: Blank by default. If supplied, store the files here. e.g. NFS or SMB storage location -->
|
||||
<read_fact>storage_directory</read_fact>
|
||||
<!-- port: Blank by default. If supplied install script challenge as xinetd program running on given port -->
|
||||
<read_fact>port</read_fact>
|
||||
|
||||
<default_input into="test">
|
||||
<value>asdf</value>
|
||||
<default_input into="challenge_name">
|
||||
<value>solve_a_maze</value>
|
||||
</default_input>
|
||||
<default_input into="account">
|
||||
<generator type="account">
|
||||
<input into="username">
|
||||
<value>challenges</value>
|
||||
</input>
|
||||
<input into="password">
|
||||
<value>password</value>
|
||||
</input>
|
||||
</generator>
|
||||
</default_input>
|
||||
<default_input into="flag">
|
||||
<generator type="flag_generator"/>
|
||||
</default_input>
|
||||
|
||||
<reference>https://github.com/itchyny/maze</reference>
|
||||
|
||||
<requires>
|
||||
<software_name>golang</software_name>
|
||||
<module_path>utilities/unix/system/accounts</module_path>
|
||||
</requires>
|
||||
|
||||
<requires>
|
||||
<module_path>utilities/unix/system/binary_script_container</module_path>
|
||||
</requires>
|
||||
|
||||
<requires>
|
||||
<module_path>utilities/unix/languages/ruby</module_path>
|
||||
</requires>
|
||||
|
||||
<requires>
|
||||
<module_path>utilities/unix/system/xinetd</module_path>
|
||||
</requires>
|
||||
|
||||
<requires>
|
||||
<software_name>git</software_name>
|
||||
</requires>
|
||||
|
||||
<!--<!– script dropped in account's home directory by default with setuid configuration. –>-->
|
||||
|
||||
<!--<read_fact>script_data</read_fact>-->
|
||||
<!--<read_fact>account</read_fact>-->
|
||||
<!--<read_fact>flag</read_fact>-->
|
||||
<!--<read_fact>group</read_fact>-->
|
||||
<!--<!– storage_directory: Blank by default. If supplied, store the files here. e.g. NFS or SMB storage location –>-->
|
||||
<!--<read_fact>storage_directory</read_fact>-->
|
||||
<!--<!– port: Blank by default. If supplied install script challenge as xinetd program running on given port-->
|
||||
<!--TODO: investigate why this doesnt work with nc –>-->
|
||||
<!--<!–<read_fact>port</read_fact>–>-->
|
||||
|
||||
<!--<default_input into="challenge_name">-->
|
||||
<!--<value>echo_string</value>-->
|
||||
<!--</default_input>-->
|
||||
<!--<default_input into="script_data">-->
|
||||
<!--<generator module_path=".*echo_string.*"/>-->
|
||||
<!--</default_input>-->
|
||||
<!--<default_input into="account">-->
|
||||
<!--<generator type="account">-->
|
||||
<!--<input into="username">-->
|
||||
<!--<value>challenges</value>-->
|
||||
<!--</input>-->
|
||||
<!--<input into="password">-->
|
||||
<!--<value>password</value>-->
|
||||
<!--</input>-->
|
||||
<!--</generator>-->
|
||||
<!--</default_input>-->
|
||||
<!--<default_input into="group">-->
|
||||
<!--<value>echo_string</value>-->
|
||||
<!--</default_input>-->
|
||||
<!--<default_input into="flag">-->
|
||||
<!--<generator type="flag_generator"/>-->
|
||||
<!--</default_input>-->
|
||||
|
||||
<!--<requires>-->
|
||||
<!--<module_path>utilities/unix/system/accounts</module_path>-->
|
||||
<!--</requires>-->
|
||||
|
||||
<!--<requires>-->
|
||||
<!--<module_path>utilities/unix/system/binary_script_container</module_path>-->
|
||||
<!--</requires>-->
|
||||
|
||||
<!--<requires>-->
|
||||
<!--<module_path>utilities/unix/languages/ruby</module_path>-->
|
||||
<!--</requires>-->
|
||||
|
||||
<!--<requires>-->
|
||||
<!--<module_path>utilities/unix/system/xinetd</module_path>-->
|
||||
<!--</requires>-->
|
||||
|
||||
</vulnerability>
|
||||
@@ -0,0 +1,26 @@
|
||||
#!/usr/local/bin/suid /usr/bin/ruby --
|
||||
flag_path = ''
|
||||
if ARGV[0] and File.directory? ARGV[0]
|
||||
flag_path = ARGV.shift
|
||||
if flag_path[-1] != '/'
|
||||
flag_path += '/'
|
||||
end
|
||||
end
|
||||
flag_path += 'flag'
|
||||
|
||||
puts "test"
|
||||
puts "<%=@challenge_name-%>"
|
||||
|
||||
maze_output = `ruby maze.rb 10 10 <%= @challenge_dir -%>`
|
||||
maze_arr = maze_output.split("*********")
|
||||
maze = maze_arr.first
|
||||
solution = maze_arr.last
|
||||
puts 'maze: '
|
||||
puts maze
|
||||
puts 'solution: '
|
||||
puts solution
|
||||
|
||||
# TODO: add instructions
|
||||
# TODO: add comparison between solution and maze
|
||||
# TODO: add functionality to require the solution of n>1 mazes
|
||||
# TODO: add a time restriction
|
||||
Reference in New Issue
Block a user