<commit_before>package main

import (
	"fmt"
	"github.com/nsf/termbox-go"
	"github.com/nsf/tulib"
	"image"
	"log"
	"runtime"
	"time"
	"unicode"
)

const (
	NumFPSSamples = 64
	FPSLimit      = 60
)

var (
	fpsSamples    [64]float64
	currentSample = 0
	stats         runtime.MemStats
)

type Game struct {
	P *Player

	Terminal
	CloseChan chan bool

	// unexported
	fps float64
	Objects []Object
	Map *MapChunk
}

func NewGame() *Game {
	g := Game{}

	g.CloseChan = make(chan bool, 1)

	g.Map = NewMapChunk()
	g.Map.Locations[1][4] = GlyphToTerrain('#')
	g.Map.Locations[2][4] = GlyphToTerrain('#')
	g.Map.Locations[3][4] = GlyphToTerrain('#')
	g.Map.Locations[4][4] = GlyphToTerrain('#')
	g.Map.Locations[4][3] = GlyphToTerrain('#')
	g.Map.Locations[4][2] = GlyphToTerrain('#')
	g.Map.Locations[4][1] = GlyphToTerrain('#')

	g.P = NewPlayer(&g)
	g.P.Pos = image.Pt(2, 2)

	g.Objects = append(g.Objects, g.P)

	u := NewUnit(&g)
	u.Ch.Ch = '@'
	u.Pos = image.Pt(7, 7)

	g.Objects = append(g.Objects, &u)

	return &g
}

func (g *Game) Run() {

	g.Start()

	timer := NewDeltaTimer()
	ticker := time.NewTicker(time.Second / FPSLimit)

	run := true

	for run {
		select {
		case <-ticker.C:
			// frame tick
			delta := timer.DeltaTime()

			if delta.Seconds() > 0.25 {
				delta = time.Duration(250 * time.Millisecond)
			}

			g.Update(delta)
			g.Draw()

			g.Flush()

		case <-g.CloseChan:
			run = false
		}
	}

	g.End()

}

func (g *Game) Start() {
	log.Print("Game starting")

	g.Terminal.Start()

	g.HandleKey(termbox.KeyEsc, func(ev termbox.Event) { g.CloseChan <- false })

	scale := PLAYER_RUN_SPEED

	// convert to func SetupDirections()
	for k, v := range CARDINALS {
		func(c rune, d Direction) {
			g.HandleRune(c, func(_ termbox.Event) {
				g.P.Move(d)
			})

			upperc := unicode.ToUpper(c)
			g.HandleRune(upperc, func(_ termbox.Event) {
				for i := 0; i < scale; i++ {
					g.P.Move(d)
				}
			})
		}(k, v)
	}
}

func (g *Game) End() {
	log.Print("Game ending")
	g.Terminal.End()
}

func (g *Game) Update(delta time.Duration) {
	// update fps
	g.fps = g.calcFPS(delta)
	runtime.ReadMemStats(&stats)

	g.RunInputHandlers()

	for _, o := range g.Objects {
		o.Update(delta)
	}

}

func (g *Game) Draw() {

	// construct a current view of the 2d world and blit it
	viewwidth := g.Terminal.Rect.Width - VIEW_START_X - VIEW_PAD_X
	viewheight := g.Terminal.Rect.Height - VIEW_START_Y - VIEW_PAD_Y
	viewrect := tulib.Rect{VIEW_START_X, VIEW_START_Y, viewwidth, viewheight}
	viewbuf := tulib.NewBuffer(viewwidth, viewheight)
	viewbuf.Fill(viewrect, termbox.Cell{Ch: ' ', Fg: termbox.ColorDefault, Bg: termbox.ColorDefault})

	cam := NewCamera(viewbuf)
	cam.SetCenter(g.P.GetPos())

	// draw terrain
	for y, row := range g.Map.Locations {
		for x, terr := range row {
			pos := image.Pt(x, y)
			if cam.ContainsWorldPoint(pos) {
				cam.Draw(terr, pos)
			}
		}
	}

	// draw other crap<commit_msg>fix map orientation<commit_after>package main

import (
	"fmt"
	"github.com/nsf/termbox-go"
	"github.com/nsf/tulib"
	"image"
	"log"
	"runtime"
	"time"
	"unicode"
)

const (
	NumFPSSamples = 64
	FPSLimit      = 60
)

var (
	fpsSamples    [64]float64
	currentSample = 0
	stats         runtime.MemStats
)

type Game struct {
	P *Player

	Terminal
	CloseChan chan bool

	// unexported
	fps float64
	Objects []Object
	Map *MapChunk
}

func NewGame() *Game {
	g := Game{}

	g.CloseChan = make(chan bool, 1)

	g.Map = NewMapChunk()
	g.Map.Locations[1][4] = GlyphToTerrain('#')
	g.Map.Locations[2][4] = GlyphToTerrain('#')
	g.Map.Locations[3][4] = GlyphToTerrain('#')
	g.Map.Locations[4][4] = GlyphToTerrain('#')
	g.Map.Locations[4][3] = GlyphToTerrain('#')
	g.Map.Locations[4][2] = GlyphToTerrain('#')
	g.Map.Locations[4][1] = GlyphToTerrain('#')

	g.P = NewPlayer(&g)
	g.P.Pos = image.Pt(2, 2)

	g.Objects = append(g.Objects, g.P)

	u := NewUnit(&g)
	u.Ch.Ch = '@'
	u.Pos = image.Pt(7, 7)

	g.Objects = append(g.Objects, &u)

	return &g
}

func (g *Game) Run() {

	g.Start()

	timer := NewDeltaTimer()
	ticker := time.NewTicker(time.Second / FPSLimit)

	run := true

	for run {
		select {
		case <-ticker.C:
			// frame tick
			delta := timer.DeltaTime()

			if delta.Seconds() > 0.25 {
				delta = time.Duration(250 * time.Millisecond)
			}

			g.Update(delta)
			g.Draw()

			g.Flush()

		case <-g.CloseChan:
			run = false
		}
	}

	g.End()

}

func (g *Game) Start() {
	log.Print("Game starting")

	g.Terminal.Start()

	g.HandleKey(termbox.KeyEsc, func(ev termbox.Event) { g.CloseChan <- false })

	scale := PLAYER_RUN_SPEED

	// convert to func SetupDirections()
	for k, v := range CARDINALS {
		func(c rune, d Direction) {
			g.HandleRune(c, func(_ termbox.Event) {
				g.P.Move(d)
			})

			upperc := unicode.ToUpper(c)
			g.HandleRune(upperc, func(_ termbox.Event) {
				for i := 0; i < scale; i++ {
					g.P.Move(d)
				}
			})
		}(k, v)
	}
}

func (g *Game) End() {
	log.Print("Game ending")
	g.Terminal.End()
}

func (g *Game) Update(delta time.Duration) {
	// update fps
	g.fps = g.calcFPS(delta)
	runtime.ReadMemStats(&stats)

	g.RunInputHandlers()

	for _, o := range g.Objects {
		o.Update(delta)
	}

}

func (g *Game) Draw() {

	// construct a current view of the 2d world and blit it
	viewwidth := g.Terminal.Rect.Width - VIEW_START_X - VIEW_PAD_X
	viewheight := g.Terminal.Rect.Height - VIEW_START_Y - VIEW_PAD_Y
	viewrect := tulib.Rect{VIEW_START_X, VIEW_START_Y, viewwidth, viewheight}
	viewbuf := tulib.NewBuffer(viewwidth, viewheight)
	viewbuf.Fill(viewrect, termbox.Cell{Ch: ' ', Fg: termbox.ColorDefault, Bg: termbox.ColorDefault})

	cam := NewCamera(viewbuf)
	cam.SetCenter(g.P.GetPos())

	// draw terrain
	for x, row := range g.Map.Locations {
		for y, terr := range row {
			pos := image.Pt(x, y)
			if cam.ContainsWorldPoint(pos) {
				cam.Draw(terr, pos)
			}
		}
	}

	// draw other crap
{'fraction_non_alphanumeric': 0.16827253957329663, 'fraction_numerical': 0.01307639366827254, 'mean_word_length': 3.2031814895155457, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3467970', 'n_tokens_mistral': 2685, 'n_tokens_neox': 2422, 'n_words': 497}