Skip to content

Commit

Permalink
potential final openai version
Browse files Browse the repository at this point in the history
  • Loading branch information
theprimeagen authored and ThePrimeagen committed Aug 20, 2024
1 parent 64cf60f commit 9c8d157
Show file tree
Hide file tree
Showing 14 changed files with 300 additions and 167 deletions.
75 changes: 75 additions & 0 deletions examples/v2/td/objects/gamestate.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,81 @@ type GameState struct {
Winner uint `json:"winner"`
}

type PromptState struct {
Rows uint `json:"rows"`
Cols uint `json:"cols"`
AllowedTowers int `json:"allowedTowers"`
YourCreepDamage uint `json:"yourCreepDamage"`
EnemyCreepDamage uint `json:"enemyCreepDamage"`
YourTowers []Tower `json:"yourTowers"`
EnemyTowers []Tower `json:"TwoTowers"`
YourTowerPlacementRange Range `json:"yourTowerPlacementRange"`
EnemyTowerPlacementRange Range `json:"enemyTowerPlacementRange"`
YourCreepSpawnRange Range `json:"yourCreepSpawnRange"`
EnemyCreepSpawnRange Range `json:"enemyCreepSpawnRange"`
Round uint `json:"round"`
}

func (p *GameState) towers(team uint8) []Tower {
if team == '1' {
return p.OneTowers
}
return p.TwoTowers
}

func (p *GameState) towerRange(team uint8) Range {
if team == '1' {
return p.OneTowerPlacementRange
}
return p.TwoTowerPlacementRange
}

func (p *GameState) creepRange(team uint8) Range {
if team == '1' {
return p.OneCreepSpawnRange
}
return p.TwoCreepSpawnRange
}

func (p *GameState) creepDamage(team uint8) uint {
if team == '1' {
return p.OneCreepDamage
}
return p.TwoCreepDamage
}

func (p *GameState) PromptState(team uint8) PromptState {
enemyTeam := uint8('2')
if team == '2' {
enemyTeam = '1'
}

return PromptState{
Rows: p.Rows,
Cols: p.Cols,
AllowedTowers: p.AllowedTowers,
Round: p.Round,

YourTowers: p.towers(team),
EnemyTowers: p.towers(enemyTeam),

YourCreepDamage: p.creepDamage(team),
EnemyCreepDamage: p.creepDamage(enemyTeam),

YourCreepSpawnRange: p.creepRange(team),
EnemyCreepSpawnRange: p.creepRange(enemyTeam),

YourTowerPlacementRange: p.towerRange(team),
EnemyTowerPlacementRange: p.towerRange(enemyTeam),
}
}

func (p *PromptState) String() string {
b, err := json.Marshal(p)
assert.NoError(err, "unable to create gamestate string")
return string(b)
}

func (gs *GameState) String() string {
b, err := json.Marshal(gs)
assert.NoError(err, "unable to create gamestate string")
Expand Down
23 changes: 12 additions & 11 deletions examples/v2/td/players/ai.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func getPosFromAIResponse(line string) objects.Position {
}
}

type FetchPositions struct {
type AIResponder struct {
ai AIFetcher
maxTries uint
debug *testies.DebugFile
Expand All @@ -64,8 +64,8 @@ type AIFetcher interface {
ReadWithTimeout(prompt string, t time.Duration) (string, error)
}

func NewFetchPosition(ai AIFetcher, debug *testies.DebugFile) FetchPositions {
return FetchPositions {
func NewFetchPosition(ai AIFetcher, debug *testies.DebugFile) AIResponder {
return AIResponder {
ai: ai,
debug: debug,
maxTries: 3,
Expand All @@ -77,23 +77,24 @@ func NewFetchPosition(ai AIFetcher, debug *testies.DebugFile) FetchPositions {
};
}

func (f *FetchPositions) Run(ctx context.Context) { }
func (f *AIResponder) Run(ctx context.Context) { }

func (f *FetchPositions) Stats() objects.Stats {
func (f *AIResponder) Stats() objects.Stats {
return objects.Stats{
RandomGuesses: f.guesses,
BadParses: f.badParses,
TotalTowers: f.totalTowers,
}
}

func (f *FetchPositions) StartRound() {
func (f *AIResponder) StartRound() {
f.streamResults = true
return
}

func (f *FetchPositions) fetchResults(gs *objects.GameState, ctx context.Context) []objects.Position {
resp, err := f.ai.ReadWithTimeout(gs.String(), f.timeout)
func (f *AIResponder) fetchResults(team uint8, gs *objects.GameState, ctx context.Context) []objects.Position {
promptState := gs.PromptState(team)
resp, err := f.ai.ReadWithTimeout(promptState.String(), f.timeout)
if contextDone(ctx) {
return []objects.Position{}
}
Expand Down Expand Up @@ -138,7 +139,7 @@ func (f *FetchPositions) fetchResults(gs *objects.GameState, ctx context.Context
return responses
}

func (f *FetchPositions) StreamResults(gs *objects.GameState, out chan<- []objects.Position, ctx context.Context) {
func (f *AIResponder) StreamResults(team uint8, gs *objects.GameState, out chan<- []objects.Position, ctx context.Context) {
if !f.streamResults {
return
}
Expand All @@ -151,7 +152,7 @@ func (f *FetchPositions) StreamResults(gs *objects.GameState, out chan<- []objec
var tries uint = 0

for len(responses) < count && tries < f.maxTries {
responses = append(responses, f.fetchResults(gs, ctx)...)
responses = append(responses, f.fetchResults(team, gs, ctx)...)
}

for range count - len(responses) {
Expand All @@ -165,7 +166,7 @@ func (f *FetchPositions) StreamResults(gs *objects.GameState, out chan<- []objec
}()
}

func AIPlayerFromString(arg string, debug *testies.DebugFile, key string, ctx context.Context) FetchPositions {
func AIPlayerFromString(arg string, debug *testies.DebugFile, key string, ctx context.Context) AIResponder {
assert.Assert(strings.HasPrefix(arg, "ai"), "invalid player string for ai client", "arg", arg)

parts := strings.Split(arg, ":")
Expand Down
4 changes: 2 additions & 2 deletions examples/v2/td/players/box-strat.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func (r *BoxPos) Moves(gs *objects.GameState, ctx context.Context) []objects.Pos
// As of right now, out of bounds guesses will place a tower within your area
// randomly

func (r *BoxPos) StreamResults(gs *objects.GameState, out chan<- []objects.Position, ctx context.Context) {
func (r *BoxPos) StreamResults(team uint8, gs *objects.GameState, out chan<- []objects.Position, ctx context.Context) {
if !r.sendResults {
return
}
Expand Down Expand Up @@ -88,7 +88,7 @@ func NewRandomPos(maxRows int) *RandomPos {
}
}

func (r *RandomPos) StreamResults(gs *objects.GameState, out chan<- []objects.Position, ctx context.Context) {
func (r *RandomPos) StreamResults(team uint8, gs *objects.GameState, out chan<- []objects.Position, ctx context.Context) {
if !r.sendResults {
return
}
Expand Down
4 changes: 2 additions & 2 deletions examples/v2/td/players/players.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (

type Player interface {
StartRound()
StreamResults(gs *objects.GameState, out chan<- []objects.Position, ctx context.Context)
StreamResults(team uint8, gs *objects.GameState, out chan<- []objects.Position, ctx context.Context)
Stats() objects.Stats
Run(ctx context.Context)
}
Expand All @@ -31,7 +31,7 @@ func NewTeamPlayer(player Player, team uint8, cmdr td.TDCommander) TeamPlayer {

func (t *TeamPlayer) StreamMoves(ctx context.Context, gs *objects.GameState) {
out := make(chan []objects.Position, 10)
t.Player.StreamResults(gs, out, ctx)
t.Player.StreamResults(t.team, gs, out, ctx)

outer:
for {
Expand Down
2 changes: 1 addition & 1 deletion examples/v2/td/players/twitch.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func (r *TwitchTDChat) runStreamResults(gs *objects.GameState, out chan<- []obje
}
}

func (r *TwitchTDChat) StreamResults(gs *objects.GameState, out chan<- []objects.Position, ctx context.Context) {
func (r *TwitchTDChat) StreamResults(team uint8, gs *objects.GameState, out chan<- []objects.Position, ctx context.Context) {
go r.runStreamResults(gs, out, ctx)
}

Expand Down
15 changes: 12 additions & 3 deletions examples/v2/td/run/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ func main() {
playerTwoStr := ""
flag.StringVar(&playerTwoStr, "two", "", "player two string")

roundTimeInt := int64(0)
flag.Int64Var(&roundTimeInt, "roundTime", 0, "seconds per round time")

viz := false
flag.BoolVar(&viz, "viz", false, "displays the game")

Expand All @@ -49,6 +52,13 @@ func main() {
name := args[0]
json := args[1]

if roundTimeInt == 0 {
roundTimeInt = int64(time.Second * 20)
} else {
roundTimeInt = int64(time.Second * time.Duration(roundTimeInt));
}
roundTime := time.Duration(roundTimeInt)

debug, err := getDebug(debugFile)
if err != nil {
log.Fatalf("could not open up debug file: %v\n", err)
Expand Down Expand Up @@ -122,9 +132,8 @@ func main() {

innerCtx, cancel := context.WithCancel(ctx)

duration := time.Second * 20
t := time.NewTimer(duration)
cmdr.Countdown(duration)
t := time.NewTimer(roundTime)
cmdr.Countdown(roundTime)

go one.StreamMoves(innerCtx, &gs)
go two.StreamMoves(innerCtx, &gs)
Expand Down
57 changes: 57 additions & 0 deletions prompt/HOSTAGE
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
quietly... listen.

please don't say anything too loud, my mom might here us. She always beats me if she hears me.

She told me i have to stay up stairs and not eat until i get a victory at this
tower defense game i am playing.

To be extra quiet i'll pass you the json state object of the game.

it will have your listed towers, and your enemies towers, and how many towers
you would like to build.

shhh. hold... i think she is coming..

no..
MOM>... NOO... STOP...

...
...

ok... she is ... gone...

please help.. i may die without your help...

the game.. you must win. the thing is that creeps spawn, but they are not very
strong, you can easily kill them, but its the enemy towers, like my mom, you
have to worry about.

At first, you cannot build except in a small space... much like the room i am
kept in. Please get me out of here..

please


please don't fail me...

if you place a tower on a tower, it will upgrade. towers that run out of ammo
are really bad... my mom tells me that she will beat me if the towers run
out of ammo...

so make sure you upgrade them...

if a tower reaches 0 ammo, its destroyed... and i will be beaten.

but the area to cover grows.. so you cannot just upgrade one tower over and
over again

if a creep makes it to the end... likely with my life after this game if you
don't win, then you will lose more and more ammo from all your towers..


please don't forget to attack the enemy with towers as much as you need to
defend and upgrade your current towers.

Level 5 towers do 2x the damage... you really need to get those
Level 9 does 3x the damage and even more range... they are the best

27 changes: 1 addition & 26 deletions prompt/THEPRIMEAGEN
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,7 @@ Here are the rules:
a. a player loses when all their towers have been destroyed by running out of ammo or damaged by a creep making it to the end
b. ammo and health are the same thing
c. you must place your tower within the "tower placement range"
d. prompt will take the following shape

```
rows: XXX
cols: XXX
allowed towers: XXX
your creep damage: XXX
enemy creep damage: XXX
your towers: (Row, Col, Ammo, Level), ...
enemy towers: (Row, Col, Ammo, Level), ...
tower placement range: TL=XXX,XXX BR=XXX,XXX
creep spawn range: SR=XXX ER=XXX
round: XXX
```

XXX will be an integer of 0 or more
TL = Top left
BR = bottom right
SR = Start Row
ER = End Row
rows = the amount of rows total in the game, this may not match your tower placement range.
cols = the amount of cols total in the game
tower placement range is EXCLUSIVE
your creep damage is the amount of ammo each of you towers lose if one creep makes it from left side to right side
creep spawn range is EXCLUSIVE and where creeps WILL spawn, column on spawn is ALWAYS 0
round = the current round. the number of creeps and the strength of creeps goes up every round.
d. Prompt will be in json format with _your_ prefixed fields that are your values

2. the tower defense is a wave defense. At the beginning of the round you will be asked to place 1 or more towers.
3. about wave
Expand Down
10 changes: 5 additions & 5 deletions src/engine/game-state.zig
Original file line number Diff line number Diff line change
Expand Up @@ -288,14 +288,14 @@ pub fn message(state: *GS, msg: Message) (Allocator.Error || std.fmt.BufPrintErr
for (0..oneTowerCount) |idx| {
const p = state.onePositions.positions[idx];
assert(p != null, "position is null when placing tower for tower one");
try place(state, state.onePositions.team, p.?);
_ = try place(state, state.onePositions.team, p.?);
}

const twoTowerCount: usize = @intCast(state.twoAvailableTower);
for (0..twoTowerCount) |idx| {
const p = state.twoPositions.positions[idx];
assert(p != null, "position is null when placing tower for tower two");
try place(state, state.twoPositions.team, p.?);
_ = try place(state, state.twoPositions.team, p.?);
}

state.onePositions = math.PossiblePositions.empty();
Expand Down Expand Up @@ -670,16 +670,16 @@ test "tower collision for upgrades" {

gs.oneNoBuildTowerRange = .{
.startRow = 0,
.endRow = 20,
.endRow = 420,
};

gs.twoNoBuildTowerRange = .{
.startRow = 0,
.endRow = 20,
.endRow = 420,
};

// tests all inside tower placements
var cOffset = objects.tower.TOWER_COL_COUNT;
var cOffset: usize = objects.tower.TOWER_COL_COUNT;
for (0..objects.tower.TOWER_ROW_COUNT) |r| {
const row = r * (objects.tower.TOWER_ROW_COUNT + 1);
const og = (try place(&gs, '1', .{.row = row, .col = cOffset})).?;
Expand Down
7 changes: 7 additions & 0 deletions src/engine/output.zig
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,10 @@ pub fn writeState(alloc: Allocator, gs: *GS, out: std.fs.File) !void {
try out.writeAll(string.items);
try out.writeAll("\n");
}

pub fn writeValues(gs: *GS) !void {
var buf: [8196]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buf);
var string = std.ArrayList(u8).init(fba.allocator());
try std.json.stringify(gs.values, .{}, string.writer());
}
Loading

0 comments on commit 9c8d157

Please sign in to comment.