Task 15.1 - install maze generating program (golang, maze-master, git, challenge scenario)

This commit is contained in:
thomashaw
2018-08-16 19:11:05 +01:00
committed by ts
parent f10ba50279
commit 05c2572545
87 changed files with 2122 additions and 89 deletions

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2013 Darren Coxall
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.

View File

@@ -0,0 +1,85 @@
# Golang
Quickly and easily install the Go programming language with a customisable workspace and version.
## Usage
In order to use this module do the following:
class { 'golang':
version => '1.1.2',
workspace => '/usr/local/src/go',
}
This will install go 1.1.2 and setup your workspace in `/usr/local/go`. Your chosen workspace should include a `bin`, `pkg` and `src` directory. The golang module doesn't create these to avoid using the wrong permissions which can cause potential issues using commands like `go get`.
If you wish to add your own code into the golang workspace but not add the files directly the best method is to create a symlink as demonstrated below:
file { '/home/user/project':
ensure => link,
target => '/usr/local/src/go/src/project',
}
Your project can then be accessed by Go:
$ go test project
## Additional Options
The golang module supports some additional options:
class { 'golang':
arch => 'linux-amd64',
download_dir => '/usr/local/src',
download_url => 'https://company.intranet/downloads/golang.tar.gz',
}
#### arch
The `arch` option is a string which is used in conjunction with the default `download_url`. It is the portion of the url that points to the correct architecture specific download.
#### download_dir
`download_dir` is the location in which the golang tarball is downloaded to. This is configurable in case the default (`/usr/local/src`) is unavailable.
#### download_url
This represents the url in which to download the golang tarball. The default url is made up of `version` and `arch` from the official golang downloads.
## Contributions
This module is fairly young and has only been tested on Debian. All contributions are welcome by forking the project and creating a pull request with your changes.
## Testing
When contributing please add a test/example to confirm everything still works fine.
git clone <URL> golang
# you will also need to puppet module install -i . <dependencies>
cd golang
for i in examples/*; do; puppet apply --test --noop --modulepath=.. "$i"; done
The testing is only basic, just ensure the right steps are still executed.
## Roadmap
There are still additional features which would make this module better:
1. Tests (tut, tut me for not doing them)
2. The ability to remove go
3. A Go project resource which would automatically symlink the directory?
## License
The MIT License (MIT)
Copyright (c) 2013 Darren Coxall
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.

View File

@@ -0,0 +1,9 @@
{
"LICENSE": "f8a48fc881716de69a658fae9dbb50bf",
"README.markdown": "0950eadeb650c56ac6511e60b69a349e",
"examples/curl_conflict.pp": "7a4bcaddb50c6103fd61cd0380d72c46",
"examples/init.pp": "4de930091b7852fd738722ba9c944569",
"manifests/init.pp": "a23ed42a5f92e12961f0dd52ed5c9bf2",
"metadata.json": "b08b6b2baa8682ae8d500acdd2f2a81e",
"templates/golang.sh.erb": "e1394c9baa0deee28260a1ec2e34b48f"
}

View File

@@ -0,0 +1,3 @@
package { 'curl': ensure => 'present' } ->
class { 'golang': }

View File

@@ -0,0 +1,7 @@
# Learn more about module testing here:
# http://docs.puppetlabs.com/guides/tests_smoke.html
class { 'golang':
version => '1.7.3',
workspace => '/usr/local/src/go',
}

View File

@@ -0,0 +1,4 @@
class { "golang":
arch => 'linux-386',
version => '1.9',
}

View File

@@ -0,0 +1,68 @@
# == Class: golang
#
# Installs the go language allowing you to
# execute and compile go.
#
# === Examples
#
# class { "golang":}
#
# === Authors
#
# Darren Coxall <darren@darrencoxall.com>
#
class golang (
$version = '1.7.3',
$workspace = '/vagrant',
$arch = 'linux-amd64',
$download_dir = '/usr/local/src',
$download_url = undef,
$download_timeout = 900,
) {
if ($download_url) {
$download_location = $download_url
} else {
$download_location = "https://storage.googleapis.com/golang/go${version}.${arch}.tar.gz"
}
Exec {
path => '/usr/local/go/bin:/usr/local/bin:/usr/bin:/bin',
}
$package_prereqs = [
'curl',
'mercurial',
]
ensure_packages($package_prereqs)
exec { 'download':
command => "curl -o ${download_dir}/go-${version}.tar.gz ${download_location}",
creates => "${download_dir}/go-${version}.tar.gz",
unless => "which go && go version | grep '${version}'",
require => Package['curl'],
timeout => $download_timeout,
} ->
exec { 'unarchive':
command => "tar -C /usr/local -xzf ${download_dir}/go-${version}.tar.gz && rm ${download_dir}/go-${version}.tar.gz",
onlyif => "test -f ${download_dir}/go-${version}.tar.gz",
}
exec { 'remove-previous':
command => 'rm -r /usr/local/go',
onlyif => [
'test -d /usr/local/go',
"which go && test `go version | cut -d' ' -f 3` != 'go${version}'",
],
before => Exec['unarchive'],
}
file { '/etc/profile.d/golang.sh':
content => template('golang/golang.sh.erb'),
owner => root,
group => root,
mode => 'a+x',
}
}

View File

@@ -0,0 +1,14 @@
{
"name": "dcoxall-golang",
"version": "1.2.0",
"author": "Darren Coxall",
"summary": "A barebones Go installation",
"license": "MIT",
"source": "https://github.com/dcoxall/dcoxall-golang",
"project_page": "https://github.com/dcoxall/dcoxall-golang",
"issues_url": "https://github.com/dcoxall/dcoxall-golang/issues",
"dependencies": [
{"name":"puppetlabs/stdlib","version_requirement":">= 4.1.0 < 5.0.0"}
],
"data_provider": null
}

View File

@@ -0,0 +1,24 @@
<?xml version="1.0"?>
<utility xmlns="http://www.github/cliffe/SecGen/utility"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.github/cliffe/SecGen/utility">
<name>Go programming language</name>
<author>Darren Coxall</author>
<author>Thomas Shaw</author>
<module_license>MIT</module_license>
<description>An installation of the Go programming language</description>
<type>language</type>
<type>go</type>
<platform>linux</platform>
<!--optional details-->
<reference>https://forge.puppet.com/dcoxall/golang</reference>
<software_name>golang</software_name>
<software_license>MIT</software_license>
<requires>
<type>update</type>
</requires>
</utility>

View File

@@ -0,0 +1,3 @@
GOPATH="<%= @workspace %>"
PATH="$GOPATH/bin:/usr/local/go/bin:$PATH"
export GOPATH PATH

View File

@@ -13,6 +13,7 @@
<!--optional details-->
<reference>https://git-scm.com/</reference>
<software_name>git</software_name>
<conflict>
<name>Stretch</name>

View File

@@ -1 +0,0 @@
include echo_string::install

View File

@@ -1,17 +0,0 @@
class echo_string::install {
$secgen_params = secgen_functions::get_parameters($::base64_inputs_file)
$challenge_name = $secgen_params['challenge_name'][0]
::secgen_functions::install_setgid_script { $challenge_name:
source_module_name => $module_name,
challenge_name => $challenge_name,
script_name => "$challenge_name.rb",
script_data => $secgen_params['script_data'],
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'],
}
}

View File

@@ -1,71 +0,0 @@
<?xml version="1.0"?>
<vulnerability xmlns="http://www.github/cliffe/SecGen/vulnerability"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.github/cliffe/SecGen/vulnerability">
<name>Echo String Challenge</name>
<author>Thomas Shaw</author>
<module_license>MIT</module_license>
<description>Programming challenge which involves echoing a random string back.</description>
<type>ctf_challenge</type>
<privilege>none</privilege>
<access>local</access>
<platform>linux</platform>
<challenge_type>misc</challenge_type>
<challenge_subtype>programming</challenge_subtype>
<difficulty>low</difficulty>
<!-- script dropped in account's home directory by default with setuid configuration. -->
<read_fact>challenge_name</read_fact>
<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>

View File

@@ -0,0 +1,4 @@
/build
/goxz
.golint.txt
/vendor

View File

@@ -0,0 +1,29 @@
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

View File

@@ -0,0 +1,39 @@
# 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

View File

@@ -0,0 +1,34 @@
# 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"

View File

@@ -0,0 +1,21 @@
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.

View File

@@ -0,0 +1,41 @@
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

View File

@@ -0,0 +1,60 @@
# maze [![Travis Build Status](https://travis-ci.org/itchyny/maze.svg?branch=master)](https://travis-ci.org/itchyny/maze)
![maze](https://raw.githubusercontent.com/wiki/itchyny/maze/image/maze1.gif)
## Usage
The `maze` command without the arguments prints the random maze to the standard output.
```sh
maze
```
![maze](https://raw.githubusercontent.com/wiki/itchyny/maze/image/maze6.gif)
We can play the maze on the terminal with `--interactive`.
```sh
maze --interactive
```
![maze](https://raw.githubusercontent.com/wiki/itchyny/maze/image/maze2.gif)
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
```
![maze](https://raw.githubusercontent.com/wiki/itchyny/maze/image/maze3.gif)
We can toggle the solution with the `s` key.
![maze](https://raw.githubusercontent.com/wiki/itchyny/maze/image/maze4.gif)
If we change the font size of the terminal smaller, we get a large maze.
![maze](https://raw.githubusercontent.com/wiki/itchyny/maze/image/maze5.gif)
## 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)

View File

@@ -0,0 +1,62 @@
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
}

View File

@@ -0,0 +1,137 @@
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
}

View File

@@ -0,0 +1,57 @@
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",
},
}

View File

@@ -0,0 +1,153 @@
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)
}
}
}

View File

@@ -0,0 +1,14 @@
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))
}

View File

@@ -0,0 +1,39 @@
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
})
}

View File

@@ -0,0 +1,26 @@
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
}

View File

@@ -0,0 +1,488 @@
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"
}

View File

@@ -0,0 +1 @@
maze --seed 0 --width 10 --height 10 --solution

View File

@@ -0,0 +1,23 @@
##########################################
S:::::::##::::::##::::::::::::::::::::::##
######::##::##::##::## ##############::##
##::::::##::##::::::## ## ## ##::##
##::######::########## ## ## ######::##
##::##::::::## ## ## ::##
##::##::###### ########## ## ######::##
##::::::## ## ##::::::##
########## ###### ##############::## ##
## ## ## ## ## ##::::::::::## ##
## ## ## ## ## ## ##::########## ##
## ## ## ## ##::::::::::## ##
## ########## ########## ######::######
## ## ## ##::::::##
###### ## ## ######################::##
## ## ## ##::::::::::##
## ############## ## ## ##::##########
## ## ## ## ##::::::::::##
###### ## ## ######################::##
## ## ## :::G
##########################################

View File

@@ -0,0 +1 @@
maze --seed 0 --format color --width 10 --height 10

View File

@@ -0,0 +1,23 @@
                     
S      
                     
               
                     
           
                     
         
                     
               
                     
             
                     
         
                     
         
                     
           
                     
      G
                     

View File

@@ -0,0 +1 @@
maze --seed 0 --format color --width 10 --height 10 --solution

View File

@@ -0,0 +1,23 @@
                     
S                     
                     
                   
                     
              
                     
             
                     
                   
                     
                 
                     
           
                     
             
                     
               
                     
        G
                     

View File

@@ -0,0 +1 @@
maze --seed 0 --width 10 --height 10

View File

@@ -0,0 +1,23 @@
##########################################
S ## ## ##
###### ## ## ## ## ############## ##
## ## ## ## ## ## ## ##
## ###### ########## ## ## ###### ##
## ## ## ## ## ##
## ## ###### ########## ## ###### ##
## ## ## ## ##
########## ###### ############## ## ##
## ## ## ## ## ## ## ##
## ## ## ## ## ## ## ########## ##
## ## ## ## ## ## ##
## ########## ########## ###### ######
## ## ## ## ##
###### ## ## ###################### ##
## ## ## ## ##
## ############## ## ## ## ##########
## ## ## ## ## ##
###### ## ## ###################### ##
## ## ## G
##########################################

View File

@@ -0,0 +1 @@
maze --seed 0 --width 10 --height 10 --goal 9,5 --solution

View File

@@ -0,0 +1,23 @@
##########################################
S:::::::##::::::##::::::::::::::::::::::##
######::##::##::##::## ##############::##
##::::::##::##::::::## ## ## ##::##
##::######::########## ## ## ######::##
##::##::::::## ## ## ::##
##::##::###### ########## ## ######::##
##::::::## ## ##::::::##
########## ###### ##############::## ##
## ## ## ## ## ##::::::::::## ##
## ## ## ## ## ## ##::########## ##
## ## ## ## ##::::::::::## ##
## ########## ########## ######::######
## ## ## ##::::::##
###### ## ## ######################::##
## ## ## ##::::::::::##
## ############## ## ## ##::##########
## ## ## ## ##::::::::::##
###### ## ## ######################::##
## ## ## ::::::::::::::::::##
######################:G##################

View File

@@ -0,0 +1 @@
maze --seed 0 --width 10 --height 10 --goal 9,0 --solution

View File

@@ -0,0 +1,23 @@
##########################################
S:::::::##::::::##::::::::::::::::::::::##
######::##::##::##::## ##############::##
##::::::##::##::::::## ## ## ##::##
##::######::########## ## ## ######::##
##::##::::::## ## ## ::##
##::##::###### ########## ## ######::##
##::::::## ## ##::::::##
########## ###### ##############::## ##
## ## ## ## ## ##::::::::::## ##
## ## ## ## ## ## ##::########## ##
## ## ## ## ##:: ## ##
## ########## ##########::###### ######
## ##::::::##:::::::::::::: ## ##
######::##::##::###################### ##
##::::::##:::::: ## ## ##
##::############## ## ## ## ##########
##::::::## ## ## ## ##
######::## ## ###################### ##
G:::::::## ## ##
##########################################

View File

@@ -0,0 +1 @@
maze --seed 0 --width 10 --height 10 --goal 5,0 --solution

View File

@@ -0,0 +1,23 @@
##########################################
S:::::::##::::::##:::::: ##
######::##::##::##::##::############## ##
##::::::##::##::::::##::## ## ## ##
##::######::##########::## ## ###### ##
##::##::::::##::::::::::## ## ##
##::##::######::########## ## ###### ##
##::::::##::::::## ## ##
##########::###### ############## ## ##
##::::::##::## ## ## ## ## ##
##::##::##::## ## ## ## ########## ##
G:::##::::::## ## ## ## ##
## ########## ########## ###### ######
## ## ## ## ##
###### ## ## ###################### ##
## ## ## ## ##
## ############## ## ## ## ##########
## ## ## ## ## ##
###### ## ## ###################### ##
## ## ## ##
##########################################

View File

@@ -0,0 +1 @@
maze --seed 0 --width 10 --height 10 --goal 0,5 --solution

View File

@@ -0,0 +1,23 @@
######################G:##################
S:::::::##::::::##:::::: ##
######::##::##::##::## ############## ##
##::::::##::##::::::## ## ## ## ##
##::######::########## ## ## ###### ##
##::##::::::## ## ## ##
##::##::###### ########## ## ###### ##
##::::::## ## ## ##
########## ###### ############## ## ##
## ## ## ## ## ## ## ##
## ## ## ## ## ## ## ########## ##
## ## ## ## ## ## ##
## ########## ########## ###### ######
## ## ## ## ##
###### ## ## ###################### ##
## ## ## ## ##
## ############## ## ## ## ##########
## ## ## ## ## ##
###### ## ## ###################### ##
## ## ## ##
##########################################

View File

@@ -0,0 +1 @@
maze --seed 0 --width 10 --height 10 --goal 0,9 --solution

View File

@@ -0,0 +1,23 @@
##########################################
S:::::::##::::::##:::::::::::::::::::::::G
######::##::##::##::## ############## ##
##::::::##::##::::::## ## ## ## ##
##::######::########## ## ## ###### ##
##::##::::::## ## ## ##
##::##::###### ########## ## ###### ##
##::::::## ## ## ##
########## ###### ############## ## ##
## ## ## ## ## ## ## ##
## ## ## ## ## ## ## ########## ##
## ## ## ## ## ## ##
## ########## ########## ###### ######
## ## ## ## ##
###### ## ## ###################### ##
## ## ## ## ##
## ############## ## ## ## ##########
## ## ## ## ## ##
###### ## ## ###################### ##
## ## ## ##
##########################################

View File

@@ -0,0 +1 @@
maze --seed 0 --width 10 --height 1

View File

@@ -0,0 +1,5 @@
##########################################
S G
##########################################

View File

@@ -0,0 +1 @@
maze --seed 0 --width 10 --height 1 --solution

View File

@@ -0,0 +1,5 @@
##########################################
S::::::::::::::::::::::::::::::::::::::::G
##########################################

View File

@@ -0,0 +1,7 @@
NAME:
maze - Maze generating and solving program
USAGE:
maze [global options] [arguments...]
VERSION:

View File

@@ -0,0 +1 @@
maze --seed 0 --width 1 --height 1

View File

@@ -0,0 +1,5 @@
######
S G
######

View File

@@ -0,0 +1 @@
maze --seed 0 --width 10 --height 10 --output .tmp; cat .tmp; rm .tmp

View File

@@ -0,0 +1,23 @@
##########################################
S ## ## ##
###### ## ## ## ## ############## ##
## ## ## ## ## ## ## ##
## ###### ########## ## ## ###### ##
## ## ## ## ## ##
## ## ###### ########## ## ###### ##
## ## ## ## ##
########## ###### ############## ## ##
## ## ## ## ## ## ## ##
## ## ## ## ## ## ## ########## ##
## ## ## ## ## ## ##
## ########## ########## ###### ######
## ## ## ## ##
###### ## ## ###################### ##
## ## ## ## ##
## ############## ## ## ## ##########
## ## ## ## ## ##
###### ## ## ###################### ##
## ## ## G
##########################################

View File

@@ -0,0 +1 @@
maze --seed 1 --width 10 --height 10

View File

@@ -0,0 +1,23 @@
##########################################
S ## ## ## ## ##
## ## ###### ## ## ## ###### ## ##
## ## ## ## ## ## ##
########## ## ########## ## ###### ##
## ## ## ## ##
## ############## ############## ## ##
## ## ## ##
########## ## ## ############## ######
## ## ## ## ## ## ##
## ## ###### ########## ## ###### ##
## ## ## ## ## ##
## ########## ## ############## ## ##
## ## ## ## ## ## ##
########## ###### ## ## ## ## ## ##
## ## ## ## ## ## ## ## ##
## ## ## ## ###### ## ## ## ## ##
## ## ## ## ## ## ## ## ##
## ################## ## ###### ## ##
## ## ## G
##########################################

View File

@@ -0,0 +1 @@
maze --seed 2 --width 10 --height 10

View File

@@ -0,0 +1,23 @@
##########################################
S ## ## ## ##
## ###### ## ## ## ########## ## ##
## ## ## ## ## ## ##
## ## ## ## ## ########## ##########
## ## ## ## ## ## ##
## ## ########## ## ## ###### ## ##
## ## ## ## ## ## ## ##
## ## ## ## ## ## ############## ##
## ## ## ## ## ## ## ##
## ###### ## ############## ## ######
## ## ## ## ##
###################### ## ########## ##
## ## ## ## ##
## ## ###### ## ################## ##
## ## ## ## ## ## ##
## ## ########## ## ########## ## ##
## ## ## ## ## ## ## ##
## ## ## ## ###### ## ########## ##
## ## ## G
##########################################

View File

@@ -0,0 +1 @@
maze --seed 0 --width 3 --height 3

View File

@@ -0,0 +1,9 @@
##############
S ## ##
###### ## ##
## ## ##
## ###### ##
## G
##############

View File

@@ -0,0 +1 @@
maze --seed 0 --width 10 --height 10 --start 9,5 --solution

View File

@@ -0,0 +1,23 @@
##########################################
## ## ## ## ##
## ###### ## ###### ## ## ## ## ##
## ## ## ## ## ## ## ##
###### ########## ## ############## ##
## ## ## ## ##
## ###### ########## ###### ## ######
## ## ## ## ## ## ##
################## ## ## ## ###### ##
## ## ## ## ## ## ##
## ## ## ## ###### ## ## ## ######
## ## ## ## ## ## ## ## ##
## ########## ###### ## ## ## ## ##
## ## ## ## ## ## ## ##
## ############## ## ## ## ## ## ##
## ## ## ## ## ## ## ##
## ## ## ## ###### ########## ## ##
## ## ## ## ## ##
## ## ########## ###### ########## ##
## ## ##:::::::::::::::::::G
######################S:##################

View File

@@ -0,0 +1 @@
maze --seed 0 --width 10 --height 10 --start 9,0 --solution

View File

@@ -0,0 +1,23 @@
##########################################
## ## ## ## ##
## ## ## ########## ###### ## ## ##
## ## ## ## ## ## ## ##
## ## ## ## ## ###### ########## ##
## ## ## ## ## ## ##
###### ########## ## ########## ######
## ## ## ## ## ##
## ## ###### ###### ## ########## ##
## ## ## ## ##
## ## ## ###### ######################
## ## ## ## ## ##
###### ## ########## ## ## ###### ##
## ## ## ##::::::::::## ##
## ################## ##::######::######
## ## ## ##::::::##::::::##
## ## ########## ##########::######::##
## ## ##::::::::::## ::##
###### ##############::########## ##::##
S:::::::::::::::::::::::## ##:::G
##########################################

View File

@@ -0,0 +1 @@
maze --seed 0 --width 10 --height 10 --start 9,9 --goal 0,0 --solution

View File

@@ -0,0 +1,23 @@
##########################################
G:::##::::::##:::::::::::::: ##
##::##::##::##::##########::## ##########
##::::::##::##::## ##::## ## ##
##########::##::## ######::## ## ## ##
## ##::::::## ## ::## ## ##
## ## ########## ## ##::########## ##
## ## ## ## ##::## ## ##
## ###### ## ## ######::###### ## ##
## ## ## ## ::## ## ##
###### ## ########## ##::## ###### ##
## ## ## ##::## ## ##
## ########## ## ######::## ## ## ##
## ## ## ##::## ## ##
###### ## ## ##########::## ##########
## ## ## ## ::## ##
## ## ########## ######::########## ##
## ## ## ##::::::::::## ##
## ########## ###### ##########::######
## ## ##:::::::S
##########################################

View File

@@ -0,0 +1 @@
maze --seed 0 --width 10 --height 10 --start 5,0 --solution

View File

@@ -0,0 +1,23 @@
##########################################
## ::::::## ## ##
## ##::##::## ## ############## ######
## ##::##::## ## ## ## ##
######::##::## ########## ## ###### ##
##::::::##::## ## ## ## ## ##
##::######::## ## ## ## ## ## ######
##:: ##::## ## ## ## ##
##::######::########## ## ## ###### ##
##::::::##:: ## ## ## ## ##
######::##::## ############## ###### ##
S:::::::##::## ## ## ##
## ## ##::############## ## ## ######
## ## ##::##::::::## ## ## ## ##
## ######::##::##::## ## ## ###### ##
## ##::##::##::## ## ## ##
###### ##::##::##::## ########## ######
## ##::##::##:: ##::::::::::## ##
## ######::##::##::######::######::## ##
## ##::::::##::::::::::## :::::::G
##########################################

View File

@@ -0,0 +1 @@
maze --seed 0 --width 10 --height 10 --start 5,9 --solution

View File

@@ -0,0 +1,23 @@
##########################################
## ## ## ## ##
## ###### ## ###### ## ## ###### ##
## ## ## ## ## ## ##
## ## ########## ## ## ## ## ## ##
## ## ## ## ## ## ## ## ##
## ## ## ########## ## ## ## ## ##
## ## ## ## ## ## ## ## ##
## ###### ## ## ## ## ########## ##
## ## ## ##::::::::::## ##
## ######################::######::######
## ## ## ::::::##:::::::S
## ## ########## ##########::##########
## ## ## ##:::::: ##
## ## ############## ##::########## ##
## ## ## ## ##::::::::::## ##
## ###### ## ###### ##########::######
## ## ## ## ## ##::::::##
###### ## ###### ## ## ## ######::##
## ## ## ## :::G
##########################################

View File

@@ -0,0 +1 @@
maze --seed 0 --width 10 --height 10 --start 0,5 --solution

View File

@@ -0,0 +1,23 @@
######################S:##################
## ## ##::::::## ## ##
########## ## ##########::## ## ## ##
## ## ::::::## ## ##
## ##################::############## ##
## ## ## ##::::::::::## ##
## ## ## ## ## ## ######::## ######
## ## ## ## ##::::::## ##
## ############## ## ##::########## ##
## ## ## ## ##::## ##
## ## ## ###### ## ##::## ##########
## ## ## ## ##::## ## ##
## ########## ## ## ##::## ## ## ##
## ## ## ## ##::## ## ##
## ## ############## ##::########## ##
## ## ## ## ##::## ##::::::##
## ###### ###### ## ##::## ##::##::##
## ## ## ## ##::##::::::##::##
###### ## ## ###### ##::##::######::##
## ## ##::::::## :::G
##########################################

View File

@@ -0,0 +1 @@
maze --seed 0 --width 10 --height 10 --start 0,9 --solution

View File

@@ -0,0 +1,23 @@
##########################################
## ## ## ## ## :::S
## ## ## ###### ## ## ###### ##::##
## ## ## ## ## ## ##::##
## ## ###### ## ##################::##
## ## ## ##::::::::::::::##::##
## ###### ##########::###### ##::##::##
## ## ##::::::::::## ##::##::##
## ## ######::## ##############::##::##
## ## ::## ## ## ::::::##
## ###### ##::## ###### ## ##########
## ##::## ## ## ##
##############::################## ## ##
## ##::::::::::##::::::## ##
## ###### ##########::##::##::##########
## ## ## ::::::##::::::::::##
## ## ###### ############## ######::##
## ## ## ## ## ## ::##
## ## ########## ## ## ###### ##::##
## ## ## ## ##:::G
##########################################

View File

@@ -0,0 +1 @@
maze --version

View File

@@ -0,0 +1 @@
maze version v

View File

@@ -0,0 +1 @@
maze --seed 0 --width 1 --height 10

View File

@@ -0,0 +1,23 @@
######
S ##
## ##
## ##
## ##
## ##
## ##
## ##
## ##
## ##
## ##
## ##
## ##
## ##
## ##
## ##
## ##
## ##
## ##
## G
######

View File

@@ -0,0 +1 @@
maze --seed 0 --width 1 --height 10 --solution

View File

@@ -0,0 +1,23 @@
######
S:::##
##::##
##::##
##::##
##::##
##::##
##::##
##::##
##::##
##::##
##::##
##::##
##::##
##::##
##::##
##::##
##::##
##::##
##:::G
######

View File

@@ -0,0 +1,31 @@
class maze::install {
$secgen_params = secgen_functions::get_parameters($::base64_inputs_file)
$challenge_name = $secgen_params['test'][0]
$maze_dir = '/vagrant/src/maze'
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'],
}
file { 'copy maze dir':
path => $maze_dir,
ensure => directory,
recurse => true,
source => 'puppet:///modules/maze/maze-master',
notify => Exec['make maze'],
}
exec { 'make maze':
cwd => $maze_dir,
command => 'env DEPNOLOCK=1 make',
notify => Exec['install maze'],
}
exec { 'install maze':
cwd => "$maze_dir/build",
command => 'install maze /usr/local/bin',
}
}

View File

@@ -0,0 +1 @@
include maze::install

View File

@@ -0,0 +1,88 @@
<?xml version="1.0"?>
<vulnerability xmlns="http://www.github/cliffe/SecGen/vulnerability"
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>
<module_license>MIT</module_license>
<description>TODO</description>
<type>ctf_challenge</type>
<privilege>none</privilege>
<access>local</access>
<platform>linux</platform>
<challenge_type>misc</challenge_type>
<challenge_subtype>programming</challenge_subtype>
<difficulty>medium</difficulty>
<read_fact>test</read_fact>
<default_input into="test">
<value>asdf</value>
</default_input>
<reference>https://github.com/itchyny/maze</reference>
<requires>
<software_name>golang</software_name>
</requires>
<requires>
<software_name>git</software_name>
</requires>
<!--&lt;!&ndash; script dropped in account's home directory by default with setuid configuration. &ndash;&gt;-->
<!--<read_fact>script_data</read_fact>-->
<!--<read_fact>account</read_fact>-->
<!--<read_fact>flag</read_fact>-->
<!--<read_fact>group</read_fact>-->
<!--&lt;!&ndash; storage_directory: Blank by default. If supplied, store the files here. e.g. NFS or SMB storage location &ndash;&gt;-->
<!--<read_fact>storage_directory</read_fact>-->
<!--&lt;!&ndash; port: Blank by default. If supplied install script challenge as xinetd program running on given port-->
<!--TODO: investigate why this doesnt work with nc &ndash;&gt;-->
<!--&lt;!&ndash;<read_fact>port</read_fact>&ndash;&gt;-->
<!--<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>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0"?>
<scenario xmlns="http://www.github/cliffe/SecGen/scenario"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.github/cliffe/SecGen/scenario">
<!-- an example system with a maze solving challenge. -->
<system>
<system_name>solve_the_maze</system_name>
<base platform="linux" type="server"/>
<vulnerability module_path=".*maze.*"/>
<network type="private_network" range="dhcp"/>
</system>
</scenario>