Version 1.0

master
Aaron Fischer 1 year ago
parent 3d58303936
commit 3871273730
  1. 12
      Dockerfile
  2. 34
      README.mkd
  3. 2
      cmd/kartograph-map-generator/main.go
  4. 1
      go.mod
  5. 7
      pkg/generator/pdf.go
  6. 33
      pkg/generator/world.go
  7. 13
      pkg/web/service.go
  8. 51
      pkg/web/static/generator.js
  9. BIN
      pkg/web/static/images/logo.jpg
  10. 36
      pkg/web/static/styles.css
  11. 39
      pkg/web/templates/index.tpl.html

@ -0,0 +1,12 @@
FROM golang:1.16.2-alpine AS builder
RUN apk update
WORKDIR /app
COPY . /app
RUN GOOS=linux go build -o kartograph cmd/kartograph-map-generator/main.go
FROM alpine:latest
RUN apk update
WORKDIR /app
COPY --from=builder /app/kartograph /app/
EXPOSE 80
ENTRYPOINT ["/app/kartograph"]

@ -0,0 +1,34 @@
# Der Kartograph Map Generator
Generate your own maps for "Der Kartograph" easily.
## Build
You need to build the source first. The simplest way is to use the
provided Dockerfile, which will build the software and create a
convenient image (This is a multi stage Dockerfile, so the resulting
image is a small Alpine Linux image with ust the map generator binary.)
$ docker build -t kartograph .
## Run
See all available options:
$ docker run -it kartograph -help
Spawn a webserver:
$ docker run -it kartograph -web
Generate a map with the seed "hey jim" and output it as a SVG image:
$ docker run -it kartograph -output=svg -seed='hey jim' > map.svg
You want an epic game? Lets generate a big map with a lot of wasteland
and ruins:
$ docker run -it kartograph -seed=aaron \
-size=20 -wastelands=100 -ruins=10 \
-output=svg > map.svg

@ -45,7 +45,7 @@ func main() {
func init() {
flag.BoolVar(&startWebserver, "web", false, "Spawn a webserver")
flag.StringVar(&address, "address", "0.0.0.0", "IP to bin the service to")
flag.StringVar(&address, "address", "0.0.0.0", "IP to bind the service to")
flag.IntVar(&port, "port", 80, "Port to bind the service to")
flag.StringVar(&output, "output", "svg", "Output format (svg, ascii, json)")

@ -4,5 +4,4 @@ go 1.16
require (
github.com/ajstarks/svgo v0.0.0-20200725142600-7a3c8b57fecb
github.com/jung-kurt/gofpdf v1.16.2
)

@ -1,7 +0,0 @@
package generator
import ()
func (w World) PDF() {
}

@ -9,6 +9,7 @@ import (
"io"
"math"
"math/rand"
"time"
)
type TerritoryType int
@ -69,7 +70,7 @@ type World struct {
Mountains int `json:"mountains"`
World []Tile `json:"tiles"`
Seed int
Seed string
}
func (w World) Plot() string {
@ -90,23 +91,15 @@ func (w World) JSON() string {
return string(output)
}
func (w World) ExportToPDF(filename string) error {
// TODO: Draw the PDF
return nil
}
func New(size int, numWastelands int, numMountains int, numRuins int, seed string) World {
// Fix seed
h := md5.New()
io.WriteString(h, seed)
var intSeed uint64 = binary.BigEndian.Uint64(h.Sum(nil))
rand.Seed(int64(intSeed))
InitSeed(seed)
w := World{
Size: size,
Wastelands: numWastelands,
Mountains: numMountains,
Ruins: numRuins,
Seed: seed,
}
// All empty for start
@ -174,6 +167,24 @@ func New(size int, numWastelands int, numMountains int, numRuins int, seed strin
return w
}
func InitSeed(seed string) {
h := md5.New()
io.WriteString(h, seed)
var intSeed uint64 = binary.BigEndian.Uint64(h.Sum(nil))
rand.Seed(int64(intSeed))
}
func RandomSeed() string {
InitSeed(time.Now().String())
chars := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
var seed []byte
for i := 0; i < 10; i++ {
seed = append(seed, chars[roll(25)])
}
return string(seed)
}
func (w World) neighbour(direction int, pos int) (int, error) {
switch direction {
case UpDirection:

@ -41,15 +41,15 @@ func mapHandler(w http.ResponseWriter, req *http.Request) {
if seed == "" {
seed = time.Now().String()
}
wastelands, err := strconv.Atoi(req.URL.Query().Get("wastelands"))
wastelands, err := strconv.Atoi(req.URL.Query().Get("w"))
if err != nil {
wastelands = 7
}
mountains, err := strconv.Atoi(req.URL.Query().Get("mountains"))
mountains, err := strconv.Atoi(req.URL.Query().Get("m"))
if err != nil {
mountains = 5
}
ruins, err := strconv.Atoi(req.URL.Query().Get("ruins"))
ruins, err := strconv.Atoi(req.URL.Query().Get("r"))
if err != nil {
ruins = 6
}
@ -63,12 +63,15 @@ func mapHandler(w http.ResponseWriter, req *http.Request) {
}
func indexHandler(w http.ResponseWriter, req *http.Request) {
log.Printf("GET / (%v)", req.RemoteAddr)
seed := generator.RandomSeed()
world := generator.New(11, 7, 5, 6, seed)
log.Printf("GET / (%v) Seed: %v", req.RemoteAddr, seed)
tpl, err := template.ParseFS(templateFiles, "templates/index.tpl.html")
if err != nil {
log.Fatal(err)
}
tpl.Execute(w, nil)
tpl.Execute(w, world)
}

@ -0,0 +1,51 @@
document.addEventListener('DOMContentLoaded', function() {
let generate = function(seed) {
let size = document.querySelector('input[name="size"]').value
let wastelands = document.querySelector('input[name="wastelands"]').value
let mountains = document.querySelector('input[name="mountains"]').value
let ruins = document.querySelector('input[name="ruins"]').value
let map = document.querySelector('.map')
// Generate new random seed
let newMapUrl = '/map.svg?seed=' + seed +
'&s=' + size +
'&w=' + wastelands +
'&m=' + mountains +
'&r=' + ruins
document.querySelector('.map').setAttribute('src', newMapUrl);
document.querySelector('#map-link').setAttribute('href', newMapUrl);
};
let buttons = document.querySelectorAll('input[type="button"]')
Array.prototype.forEach.call(buttons, function(button, i) {
button.addEventListener('click', function(e) {
// Reset to default buttons
if (e.target.hasAttribute('data-default')) {
let defaultValue = e.target.getAttribute('data-default');
let name = e.target.getAttribute('name').substr(8);
let targetInput = document.querySelector('input[type="text"][name="'+name+'"]')
targetInput.value = defaultValue;
}
// Roll the dice
if (e.target.getAttribute('name') === 'random-seed') {
let chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
let seed = '';
for (let i=0; i<10; i++) {
let index = Math.floor(Math.random() * 25)
seed += chars[index]
}
let seedElement = document.querySelector('input[name="seed"]');
seedElement.value = seed;
generate(seed);
}
// Refresh
if (e.target.getAttribute('name') === 'refresh') {
let seed = document.querySelector('input[name="seed"]').value;
generate(seed);
}
})
});
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 31 KiB

@ -1,10 +1,38 @@
body {
width: 900px;
margin: auto;
}
h1 {
text-align: center;
}
p > img {
float: left;
width: 100px;
margin: 10px;
}
.map {
float: right;
width: 450px;
margin: 20px;
}
label {
width: 100px;
display: inline-block;
text-align: right;
}
input[type="text"] {
width: 90px;
}
input[name="seed"] {
width: 250px;
}
.map {
margin: auto;
display: block;
width: 350px;
fieldset {
width: 370px;
margin: 10px 0;
}

@ -7,9 +7,11 @@
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/static/styles.css" rel="stylesheet" type="text/css" media="all">
<script src="/static/generator.js"></script>
</head>
<body>
<h1>Map Generator für "Der Kartograph"</h1>
<a id="map-link" href="/map.svg?seed={{ .Seed }}&s={{ .Size }}&w={{ .Wastelands }}&r={{ .Ruins }}&m={{ .Mountains }}"><img src="/map.svg?seed={{ .Seed }}&s={{ .Size }}&w={{ .Wastelands }}&r={{ .Ruins }}&m={{ .Mountains }}" class="map"></a>
<p><img src="/static/images/logo.jpg">
Wem der beigelegte Block zu eintönig wird oder schon leergespielt hat, kann sich
entweder die Mini-Erweiterung kaufen, in dem ein weiterer Block enthalten ist,
@ -17,8 +19,39 @@
Die generierten Karten entsprechen den erweiterten Regeln, können aber für etwas
mehr Spaß angepasst werden.</p>
<a href="/">Neue Map generieren</a>
<br><br>
<img src="/map.svg" class="map">
{{ with . }}
<form>
<fieldset>
<legend>Seed</legend>
<input type="text" name="seed" value="{{ .Seed }}">
<input type="button" name="random-seed" value="Zufall">
</fieldset>
<fieldset>
<legend>Spielfeldgröße</legend>
<input type="text" name="size" value="{{ .Size }}">
<input type="button" name="default-size" value="Standard (11)" class="default-button" data-default="11">
</fieldset>
<fieldset>
<legend>Parameter</legend>
<label for="wastelands">Ödland:</label>
<input type="text" name="wastelands" value="{{ .Wastelands }}">
<input type="button" name="default-wastelands" value="Standard (7)" class="default-button" data-default="7">
<br>
<label for="mountains">Berge:</label>
<input type="text" name="mountains" value="{{ .Mountains }}">
<input type="button" name="default-mountains" value="Standard (5)" class="default-button" data-default="5">
<br>
<label for="ruins">Ruinen:</label>
<input type="text" name="ruins" value="{{ .Ruins }}">
<input type="button" name="default-ruins" value="Standard (6)" class="default-button" data-default="6">
<br>
</fieldset>
<input type="button" name="refresh" value="Neu generieren">
<input type="button" name="print" value="Drucken">
</form>
{{ end }}
</body>
</html>

Loading…
Cancel
Save