Add session and Complete Split

This commit is contained in:
Rubydragon 2024-04-18 01:34:38 +02:00
parent 66d98098c5
commit 2dc039dff1
6 changed files with 230 additions and 120 deletions

45
api.go Normal file
View File

@ -0,0 +1,45 @@
package main
import (
"errors"
"fmt"
)
// CompleteSplit marks a split as finished and unlocks its dependent splits if they have no other dependencies
func CompleteSplit(session *Session, split *Split) error {
fmt.Printf("Splitting split %s (%s)\n", split.Name, split.State)
if split.State == Locked {
fmt.Println("Death!!")
return errors.New("cannot complete a split that is locked")
}
// Set provided split to finished
split.State = Finished
// Iterate over dependencies
for _, dep := range split.Dependencies {
// Check if dependency has no other dependencies
hasOtherDependencies := false
for _, otherDep := range session.Graph.Splits {
if otherDep == dep || otherDep.State == Finished {
continue
}
for _, otherDep2 := range otherDep.Dependencies {
if otherDep2 == dep {
hasOtherDependencies = true
break
}
}
if hasOtherDependencies {
break
}
}
// If no other dependencies, set dependency to unlocked
if !hasOtherDependencies {
dep.State = Unlocked
}
}
return nil
}

124
graph.go Normal file
View File

@ -0,0 +1,124 @@
package main
import (
"bufio"
"errors"
"fmt"
"math/rand"
"os"
"strings"
"time"
)
// SplitState represents the state of a split
type SplitState string
const (
Locked SplitState = "locked"
Unlocked SplitState = "unlocked"
Started SplitState = "started"
Finished SplitState = "finished"
)
// Split represents a split in the speedrun graph
type Split struct {
ID int
Name string
Icon string
Dependencies []*Split
Timestamp time.Time
State SplitState
}
// Graph represents the speedrun graph
type Graph struct {
Splits []*Split
Start *Split
Final *Split
}
// NewSplit creates a new split
func NewSplit(name, icon string) *Split {
return &Split{
ID: rand.Intn(1000000), // Randomly generating ID
Name: name,
Icon: icon,
Timestamp: time.Time{},
State: Locked,
}
}
// AddDependency adds a dependency to a split
func (s *Split) AddDependency(dep *Split) {
s.Dependencies = append(s.Dependencies, dep)
}
// ReadGraphFromFile reads graph from file representation
func ReadGraphFromFile(filename string) (*Graph, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
scanner := bufio.NewScanner(file)
splits := make(map[string]*Split)
// Read lines from file
for scanner.Scan() {
line := scanner.Text()
parts := strings.Split(line, ",")
name := parts[0]
icon := parts[1]
dependencies := strings.Split(parts[2], "|")
// Create split
split := NewSplit(name, icon)
splits[name] = split
// Create dependencies
for _, depName := range dependencies {
dep := splits[depName]
if dep != nil {
split.AddDependency(dep)
}
}
}
// Set start and final splits
var start, final *Split
for _, split := range splits {
if split.Name == "Start" {
start = split
} else if len(split.Dependencies) == 0 {
if final != nil {
fmt.Println(final.Name)
return nil, errors.New("more than one final split found, only one split with no dependencies can exist")
}
final = split
}
}
if start == nil {
return nil, errors.New("no start split found, there should be a split with name 'Start'")
}
if final == nil {
return nil, errors.New("no final split found, there should be the only split with no dependencies")
}
// Create graph
graph := &Graph{
Splits: make([]*Split, 0, len(splits)),
Start: start,
Final: final,
}
graph.Start.State = Unlocked
// Append splits to graph
for _, split := range splits {
graph.Splits = append(graph.Splits, split)
}
return graph, nil
}

138
main.go
View File

@ -1,127 +1,16 @@
package main
import (
"bufio"
"errors"
"fmt"
"math/rand"
"os"
"strings"
"time"
)
// SplitState represents the state of a split
type SplitState string
const (
Locked SplitState = "locked"
Unlocked SplitState = "unlocked"
Started SplitState = "started"
Finished SplitState = "finished"
)
// Split represents a split in the speedrun graph
type Split struct {
ID int
Name string
Icon string
Dependencies []*Split
Timestamp time.Time
State SplitState
}
// Graph represents the speedrun graph
type Graph struct {
Splits []*Split
Start *Split
Final *Split
}
// NewSplit creates a new split
func NewSplit(name, icon string) *Split {
return &Split{
ID: rand.Intn(1000), // Randomly generating ID
Name: name,
Icon: icon,
Timestamp: time.Time{},
State: Locked,
}
}
// AddDependency adds a dependency to a split
func (s *Split) AddDependency(dep *Split) {
s.Dependencies = append(s.Dependencies, dep)
}
// ReadGraphFromFile reads graph from file representation
func ReadGraphFromFile(filename string) (*Graph, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
scanner := bufio.NewScanner(file)
splits := make(map[string]*Split)
// Read lines from file
for scanner.Scan() {
line := scanner.Text()
parts := strings.Split(line, ",")
name := parts[0]
icon := parts[1]
dependencies := strings.Split(parts[2], "|")
// Create split
split := NewSplit(name, icon)
splits[name] = split
// Create dependencies
for _, depName := range dependencies {
dep := splits[depName]
if dep != nil {
split.AddDependency(dep)
}
}
}
// Set start and final splits
var start, final *Split
for _, split := range splits {
if split.Name == "Start" {
start = split
} else if len(split.Dependencies) == 0 {
if final != nil {
fmt.Println(final.Name)
return nil, errors.New("more than one final split found, only one split with no dependencies can exist")
}
final = split
}
}
if start == nil {
return nil, errors.New("no start split found, there should be a split with name 'Start'")
}
if final == nil {
return nil, errors.New("no final split found, there should be the only split with no dependencies")
}
// Create graph
graph := &Graph{
Splits: make([]*Split, 0, len(splits)),
Start: start,
Final: final,
}
// Append splits to graph
for _, split := range splits {
graph.Splits = append(graph.Splits, split)
}
return graph, nil
}
func main() {
// Create a session with a random ID and read the graph from file
session := &Session{
ID: generateRandomID(),
Graph: nil,
}
// Read graph from file
graph, err := ReadGraphFromFile("graph.txt")
if err != nil {
@ -129,8 +18,17 @@ func main() {
return
}
// Example usage
// Set the graph for the session
session.Graph = graph
fmt.Println("Session ID:", session.ID)
fmt.Println("Graph:")
fmt.Println("Start:", graph.Start.Name)
fmt.Println("Final:", graph.Final.Name)
PrettyPrintGraph(graph)
CompleteSplit(session, graph.Start)
CompleteSplit(session, graph.Splits[1])
CompleteSplit(session, graph.Splits[2])
PrettyPrintGraph(graph)
fmt.Println("Done.")
}

23
print.go Normal file
View File

@ -0,0 +1,23 @@
package main
import (
"fmt"
"strings"
)
// PrettyPrintGraph prints the entire graph in a readable format
func PrettyPrintGraph(graph *Graph) {
// Print start split
printSplit(graph.Start, 0)
}
// printSplit prints a split and its dependencies recursively with proper indentation
func printSplit(split *Split, indent int) {
// Print split information
fmt.Printf("%s- %s (%s)\n", strings.Repeat(" ", indent), split.Name, split.State)
// Recursively print dependencies
for _, dep := range split.Dependencies {
printSplit(dep, indent+1)
}
}

7
session.go Normal file
View File

@ -0,0 +1,7 @@
package main
// Session represents a user session
type Session struct {
ID string
Graph *Graph
}

13
util.go Normal file
View File

@ -0,0 +1,13 @@
package main
import "math/rand"
// generateRandomID generates a random session ID
func generateRandomID() string {
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
b := make([]byte, 10)
for i := range b {
b[i] = charset[rand.Intn(len(charset))]
}
return string(b)
}