Skip to content

Commit

Permalink
Creating the proceduralEngine basic app and renamed the examples dire…
Browse files Browse the repository at this point in the history
…ctory
  • Loading branch information
Jamis March committed Jan 3, 2020
1 parent affc20c commit 648c9aa
Show file tree
Hide file tree
Showing 12 changed files with 315 additions and 0 deletions.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
163 changes: 163 additions & 0 deletions basicApps/proceduralEngine/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package main

import (
"flag"
"fmt"
"log"
"math/rand"
"time"
)

const (
numberOfOptions = 4
symbolTree = "\u1F33"
symbolMountain = "\u26F0"
symbolWater = "\u1F30"
symbolGem = "\u1F48"
symbolSpace = " "
symbolHealthPotion = "\u2764"
symbolKey = "\u1F51"
symbolTreasureChest = "\u2423"
)

var (
mapSizeX int
mapSizeY int
seed int64
questItems = []string{
symbolKey,
symbolTreasureChest,
}
)

func main() {
flag.Parse()

//Minimum map size - currently based on quest items so the grid size needs to grow to at least incorporate these items.
if !(mapSizeX*mapSizeY >= len(questItems)) {
log.Fatalf("Map size must be greater than the specified rows/columns allow. Size of map: %d, Items needing placement: %d", mapSizeX*mapSizeY, len(questItems))
}

//Determines if a new seed needs creation or use the provided seed
var s int64
if seed == -1 {
s = int64(time.Now().Nanosecond())
defer fmt.Printf("New seed is: %d\n", s)
} else {
s = seed
defer fmt.Printf("Existing seed is: %d\n", s)
}
rand.Seed(s)

workflow(createBlankMap())
}

func workflow(a [][]string) {
placeQuestItems(a)

//Go through map location and tries to place a random item based on the rules.
for x := 0; x < mapSizeX; x++ {
for y := 0; y < mapSizeY; y++ {
if a[x][y] == "" {
a[x][y] = placeGeneralLocation(a, x, y)
}
}
}

//Print out the grid
for i := range a {
fmt.Println(a[i])
}
}

func placeQuestItems(a [][]string) {
for _, qi := range questItems {
//TODO Temporary way to ensure they're placed but should be better to ensure it's impossible to be caught in an infinite loop
var x, y int
for true {
x = rand.Int() % mapSizeX
y = rand.Int() % mapSizeY

if a[x][y] == "" {
break
}
}

a[x][y] = qi
}
}

func placeGeneralLocation(a [][]string, x int, y int) string {
ri := rand.Int() % numberOfOptions
switch ri {
case 0:
return symbolTree
case 1:
if y > 0 && a[x][y-1] == symbolTree {
return placeHelpfulItem()
}
return symbolWater
case 2:
return symbolSpace
case 3:
// A mountain can't be placed directly next to another mountain
if !checkPerimeterIsClear(a, x, y, symbolMountain) {
return symbolSpace
}
return symbolMountain
}

return "X"
}

func placeHelpfulItem() string {
switch rand.Int() % 2 {
case 0:
return symbolHealthPotion
case 1:
return symbolGem
}

return "X"
}

//checkPerimeterIsClear returns true or false on if a specific symbol is left, right, up or down of the current position provided.
func checkPerimeterIsClear(a [][]string, x int, y int, symbol string) bool {
//Check up
if y > 0 && a[x][y-1] == symbol {
return false
}

//Check down
if y < len(a[0])-1 && a[x][y+1] == symbol {
return false
}

//Check left
if x > 0 && a[x-1][y] == symbol {
return false
}

//Check right
if x < len(a)-1 && a[x+1][y] == symbol {
return false
}

return true
}

func createBlankMap() (a [][]string) {
//Sets up the map arrays
for i := 0; i < mapSizeX; i++ {
ta := make([]string, mapSizeY)
a = append(a, ta)
}

return
}

func init() {
flag.IntVar(&mapSizeX, "rows", 10, "Number of rows to be used.")
flag.IntVar(&mapSizeY, "columns", 10, "Number of columns to be used.")
flag.Int64Var(&seed, "seed", -1, "Uses an existing seed if it exits.")
}
152 changes: 152 additions & 0 deletions basicApps/proceduralEngine/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package main

import (
"math/rand"
"strconv"
"testing"

"github.com/stretchr/testify/assert"
)

func TestCheckPerimeterIsClear(t *testing.T) {
var data = []struct {
result bool
array [][]string
}{
{
true,
[][]string{
{symbolTree, symbolSpace, symbolWater, symbolKey, symbolWater},
{symbolWater, symbolSpace, symbolTree, symbolMountain, symbolSpace},
{symbolTree, symbolSpace, symbolMountain, symbolSpace, symbolWater},
{symbolTree, symbolSpace, symbolTree, symbolSpace, symbolMountain},
{symbolWater, symbolWater, symbolWater, symbolWater, symbolWater},
},
},
{
false,
[][]string{
{symbolTree, symbolSpace, symbolWater, symbolKey, symbolWater},
{symbolWater, symbolSpace, symbolTree, symbolMountain, symbolSpace},
{symbolTree, symbolMountain, symbolMountain, symbolSpace, symbolWater},
{symbolTree, symbolSpace, symbolTree, symbolSpace, symbolMountain},
{symbolWater, symbolWater, symbolWater, symbolWater, symbolWater},
},
},
{
false,
[][]string{
{symbolTree, symbolSpace, symbolWater, symbolKey, symbolWater},
{symbolWater, symbolSpace, symbolMountain, symbolMountain, symbolSpace},
{symbolTree, symbolSpace, symbolMountain, symbolSpace, symbolWater},
{symbolTree, symbolSpace, symbolTree, symbolSpace, symbolMountain},
{symbolWater, symbolWater, symbolWater, symbolWater, symbolWater},
},
},
{
false,
[][]string{
{symbolTree, symbolSpace, symbolWater, symbolKey, symbolWater},
{symbolWater, symbolSpace, symbolTree, symbolMountain, symbolSpace},
{symbolTree, symbolSpace, symbolMountain, symbolMountain, symbolWater},
{symbolTree, symbolSpace, symbolTree, symbolSpace, symbolMountain},
{symbolWater, symbolWater, symbolWater, symbolWater, symbolWater},
},
},
{
false,
[][]string{
{symbolTree, symbolSpace, symbolWater, symbolKey, symbolWater},
{symbolWater, symbolSpace, symbolTree, symbolMountain, symbolSpace},
{symbolTree, symbolSpace, symbolMountain, symbolSpace, symbolWater},
{symbolTree, symbolSpace, symbolMountain, symbolSpace, symbolMountain},
{symbolWater, symbolWater, symbolWater, symbolWater, symbolWater},
},
},
}

for name, d := range data {
t.Run(strconv.Itoa(name), func(t *testing.T) {
assert.Equal(t, d.result, checkPerimeterIsClear(d.array, 2, 2, symbolMountain))
})
}
}

func TestPlaceHelpfulItem(t *testing.T) {
var data = []struct {
seed int64
result string
}{
{
1,
symbolHealthPotion,
},
{
2,
symbolGem,
},
}

for name, d := range data {
t.Run(strconv.Itoa(name), func(t *testing.T) {
rand.Seed(d.seed)
assert.Equal(t, d.result, placeHelpfulItem())
})
}
}

func TestPlaceGeneralLocation(t *testing.T) {
inputArray := [][]string{
{symbolTree, symbolSpace, symbolWater, symbolKey, symbolWater},
{symbolWater, symbolSpace, symbolTree, symbolMountain, symbolSpace},
{symbolTree, symbolSpace, symbolMountain, symbolSpace, symbolWater},
{symbolTree, symbolSpace, symbolSpace, symbolSpace, symbolMountain},
{symbolWater, symbolWater, symbolWater, symbolWater, symbolWater},
}

var data = []struct {
seed int64
expected string
}{
{
5,
symbolTree,
},
{
0,
symbolWater,
},
{
4,
symbolSpace,
},
{
7,
symbolMountain,
},
}

for name, d := range data {
t.Run(strconv.Itoa(name), func(t *testing.T) {
rand.Seed(d.seed)
assert.Equal(t, d.expected, placeGeneralLocation(inputArray, 2, 2))
})
}
}

func TestPlaceQuestItems(t *testing.T) {
inputArray := createBlankMap()
placeQuestItems(inputArray)

m := make(map[string]int)
for x := 0; x < mapSizeX; x++ {
for y := 0; y < mapSizeY; y++ {
if inputArray[x][y] != "" {
m[inputArray[x][y]]++
}
}
}
for _, qi := range questItems {
assert.Equal(t, 1, m[qi])
}
}

0 comments on commit 648c9aa

Please sign in to comment.