Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

greatly simplify tictactoe now that we have for loops #99

Merged
merged 3 commits into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# grol-discord-bot
Discord bot offering grol

![screenshot](screenshot.png)
![screenshot](https://github.com/user-attachments/assets/91687f8a-6023-4a8c-8564-865f054b2941)

## Invite link
Invite link (add grol bot to your server):
Expand Down
174 changes: 82 additions & 92 deletions discord.gr
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,55 @@
Library in grol for discord bot.
*/

// --- General library functions ---

// Note: some of these could be moved from recursive to iterative now that we have `for` loops.

// f argument takes the element and the index
func walk(f, a) {
(f,a,i) => {
if (len(a)==0) {
[]
} else {
[f(first(a),i)]+self(f,rest(a),i+1)
}
}(f,a,0)
}

// Convert to string
func str(x) {sprintf("%v", x)}

// Apply a function to each element of an array.
func apply(f, a) {
if (len(a)==0) {
[]
} else {
[f(first(a))]+apply(f,rest(a))
}
}

// Reverse an array or map or string
func reverse(a) {
if len(a) == 0 {
return []
}
self(rest(a)) + first(a)
}

// Filter an array
func filter(predicate, arr) {
if len(arr) == 0 {
[]
} else if predicate(first(arr)) {
[first(arr)] + filter(predicate, rest(arr))
} else {
filter(predicate, rest(arr))
}
}


// ---- discord specific ----

discord = {
"actionRow": elems => {
{
Expand Down Expand Up @@ -74,6 +123,8 @@ discord = {
state.end = tictactoe.endGame(board)
if state.end != nil{
clicked = clicked + ": " + state.end + " wins!"
} else if state.turn >= 9 {
clicked = clicked + ": draw."
}
InteractionRespond({
"type": discord.interaction.update_message,
Expand All @@ -85,16 +136,8 @@ discord = {

state = {}

// f argument takes the element and the index
func walk(f, a) {
(f,a,i) => {
if (len(a)==0) {
[]
} else {
[f(first(a),i)]+self(f,rest(a),i+1)
}
}(f,a,0)
}
// ---- tic tac toe ----


tictactoe = {
"empty_board": [["","",""],["","",""],["","",""]],
Expand All @@ -121,20 +164,14 @@ tictactoe = {
},
"endGame": board => {
// check for win
r = for(3, (i,r) => {
if r!=nil {
r
} else if board[i][0] != "" && board[i][0] == board[i][1] && board[i][1] == board[i][2] {
board[i][0]
for i=0:3 {
if board[i][0] != "" && board[i][0] == board[i][1] && board[i][1] == board[i][2] {
return board[i][0]
} else if board[0][i] != "" && board[0][i] == board[1][i] && board[1][i] == board[2][i] {
board[0][i]
} else {
nil
return board[0][i]
}
}, nil)
if r!=nil {
r
} else if board[0][0] != "" && board[0][0] == board[1][1] && board[1][1] == board[2][2] {
}
if board[0][0] != "" && board[0][0] == board[1][1] && board[1][1] == board[2][2] {
board[0][0]
} else if board[0][2] != "" && board[0][2] == board[1][1] && board[1][1] == board[2][0] {
board[0][2]
Expand All @@ -150,8 +187,15 @@ tictactoe = {
}
},
"play": (board, next) => {
wmove = max(walk((row,i) => max(walk((cell,j) => {
if cell == "" {
for i = 0:3 {
freeList = []
row = board[i]
for j = 0:3 {
cell = row[j]
if cell != "" {
continue
}
freeList = freeList + [[i,j]]
row[j] = next
board[i] = row
if tictactoe.endGame(board) != nil {
Expand All @@ -164,34 +208,21 @@ tictactoe = {
log("Loss by", next, "at", i, j)
return [i,j]
}
// restore board
row[j]=""
board[i]=row
}
nil
}, row)), board))
if wmove != nil {
wmove
} else {
// try middle move
if board[1][1] == "" {
[1,1]
} else if board[0][0] == "" {
[0,0]
} else if board[0][2] == "" {
[0,2]
} else if board[2][0] == "" {
[2,0]
} else if board[2][2] == "" {
[2,2]
} else if board[0][1] == "" {
[0,1]
} else if board[1][0] == "" {
[1,0]
} else if board[1][2] == "" {
[1,2]
} else {
[2,1]
}
}
}
}
if len(freeList) == 1 { // only one move left
return freeList[0]
}
// try middle move
if board[1][1] == "" {
return [1,1]
}
// random move
freeList[rand(len(freeList))]
},
}

func TicTacToe() {
Expand All @@ -204,47 +235,6 @@ func layout(){
println("Simple project layout [github.com/go-standard/project-layout](<https://github.com/go-standard/project-layout#project-layout>) - simple is good!")
}

func str(x) {sprintf("%v", x)}

// Iterate n times with first argument i=0 to n-1 and passing the intermediate result as second argument.
func for(n, f, start) {
(i,f,x) => { // internal lambda with the index param and intermediate result
if (i>=n) {
return x
}
r = f(i,x)
self(i+1, f,r)
}(0,f,start)
}

// Apply a function to each element of an array.
func apply(f, a) {
if (len(a)==0) {
[]
} else {
[f(first(a))]+apply(f,rest(a))
}
}

// Reverse an array
func reverse(a) {
if len(a) == 0 {
return []
}
self(rest(a)) + first(a)
}

// Filter an array
func filter(predicate, arr) {
if len(arr) == 0 {
[]
} else if predicate(first(arr)) {
[first(arr)] + filter(predicate, rest(arr))
} else {
filter(predicate, rest(arr))
}
}


// Result of eval of this file is logged by bot.go Run(). confirm we reached the end without error.
print("Imported discord grol library ok")
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
fortio.org/scli v1.15.2
fortio.org/version v1.0.4
github.com/bwmarrin/discordgo v0.28.1
grol.io/grol v0.60.0
grol.io/grol v0.62.0
)

// replace grol.io/grol => ../grol
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,5 @@ golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
grol.io/grol v0.60.0 h1:pg724EX6rHk+vAP3UzNs8Z+rYt4vcBZKyDUxRwczaLo=
grol.io/grol v0.60.0/go.mod h1:auvyNPGD+C1jMFsu+EkAVmXCjweP9qRLoTIYtdfrWiI=
grol.io/grol v0.62.0 h1:frHwkLiL22mNxlMidSltOwrGN3eLYW+wXkQYy2uX+sg=
grol.io/grol v0.62.0/go.mod h1:auvyNPGD+C1jMFsu+EkAVmXCjweP9qRLoTIYtdfrWiI=
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
var (
//go:embed discord.gr
libraryCode string
depth = flag.Int("max-depth", 10000, "Maximum depth of recursion")
depth = flag.Int("max-depth", 2500, "Maximum depth of recursion")
maxLen = flag.Int("max-save-len", 2000, "Maximum len of saved identifiers, use 0 for unlimited")
panicF = flag.Bool("panic", false, "Don't catch panic (DEV only)")
)
Expand Down