Skip to content

Commit

Permalink
Add README/CONTRIBUTING. Remove logging.
Browse files Browse the repository at this point in the history
  • Loading branch information
marianogappa committed Aug 10, 2024
1 parent 0fe4326 commit 61579ad
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 11 deletions.
58 changes: 58 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Contributing

If you're a little lost on how to contribute and these notes are not helpful, reach me online and I'm happy to chat about it. I'm not hard to find.

## Making your own bot

### Getting started

The bot interface is very straightforward; you only need to implement a single function:

```go
type Bot interface {
ChooseAction(ClientGameState) Action
}
```

Upon a given `ClientGameState`, choose an action. `ClientGameState` provides a `PossibleActions` property, and these are the only possible actions, so you just need to pick one. Use `truco.DeserializeAction` to be able to return it.

The `ClientGameState` struct is a "view" of the main `GameState` struct from the point of view of the bot. This prevents the bot from seeing the opponent's cards, but also simplifies the state.

There are subtleties to implementing this function, such as:
- There could be no possible actions. You must return `nil` in this case.
- There could be only one possible action. You must return this action in this case.
- Review the existing bot for inspiration. You'll have to figure out how to calculate envido/flor scores, the results of the card faceoffs, etc. I would clone the existing bot as a starting point.

### My bot is ready, how do I test it?

You should be able to instantiate your own bot instead of the existing one in this one line:

https://github.com/marianogappa/truco/blob/main/main.go#L51

### I don't know Go, can I still make a Bot?

The server implementation allows any client that understands it's WebSocket message implementation to play a game.

Here's the server code: https://github.com/marianogappa/truco/blob/main/server/websocket_server.go#L36

And here's an example bot client that implements the client WebSocket message implementation:

https://github.com/marianogappa/truco/blob/main/botclient/main.go

The implementation is quite straightforward, so I encourage you to implement yours in whichever language you want. As long as your code can address the server, you can make it work. If you're stuck, let me know.

## Making your own frontend

Writing a frontend is a more involved task, but in terms of the communication with the Truco engine, it's essentially exactly the same as making your own bot.

You will have to implement the same Websocket message implementation, you get the same state struct (`ClientGameState`), and you must send the actions that the user selects in the same fashion that you did for the bot, the only difference is that the user is picking them, rather than an algorithm.

The `ClientGameState` struct is designed to be straightforward for making a frontend implementation. Even the cards information is presented in a way that you're able to know how to animate the card from source to destination (as an example).

Please use the existing implementations to guide your own; let me know if you get stuck.

## Contributing guidelines

Feel free to contribute informally; please add tests if possible. Reach out if you need help.

## Basic Flow Diagram
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# Truco

Truco argentino implementation, using websocket-based client/server architecture and example terminal-based frontend.
Truco argentino implementation, featuring:

- websocket-based client/server architecture
- example terminal-based frontend
- example React-based frontend
- a simple, documented interface for making your own frontend
- example bot, and a simple, documented interface for making your own

<img width="1512" alt="Screenshot 2024-06-23 at 19 26 11" src="https://github.com/marianogappa/truco/assets/1078546/881e7204-f1a6-4de2-a0b5-60faa43b4fac">

Expand Down Expand Up @@ -66,10 +72,6 @@ $ truco player 1 retail-curves-bernard-affairs.trycloudflare.com
$ truco player 2 retail-curves-bernard-affairs.trycloudflare.com
```

### Project status

It mostly works well, but it's not bug-free yet. Needs a little more battle-test. Help?

### Reconnect after issue

If the server dies, state is gone. If client dies, you can simply reconnect to the same server and game goes on.
Expand All @@ -78,6 +80,10 @@ If the server dies, state is gone. If client dies, you can simply reconnect to t

It's just an example UI. I encourage you to implement a web-based UI (that's you @devblac). You may browse the documentation and the existing UI to guide your implementation.

### I don't like your Bot

It's just an example bot, which beats me. I encourage you to implement your own bot. You may browse the documentation and the existing bot to guide your implementation.

### Known issues / limitations

- Don't resize your terminal. This is a go-termbox issue. Also, have a terminal with a decent viewport. That is on me mostly.
Expand Down
5 changes: 2 additions & 3 deletions main_wasm.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func trucoNew(this js.Value, p []js.Value) interface{} {
}
state = truco.New(opts...)

bot = (newbot.New(newbot.WithDefaultLogger))
bot = (newbot.New())

nbs, err := json.Marshal(state.ToClientGameState(0))
if err != nil {
Expand All @@ -71,7 +71,7 @@ func trucoRunAction(this js.Value, p []js.Value) interface{} {
func trucoBotRunAction(this js.Value, p []js.Value) interface{} {
if !state.IsGameEnded {
action := bot.ChooseAction(state.ToClientGameState(1))
fmt.Println("Action chosen by bot:", action)
// fmt.Println("Action chosen by bot:", action)

err := state.RunAction(action)
if err != nil {
Expand All @@ -98,7 +98,6 @@ func _runAction(bs []byte) []byte {
if err != nil {
panic(err)
}
fmt.Println("Ran action:", string(bs))
nbs, err := json.Marshal(state.ToClientGameState(0))
if err != nil {
panic(err)
Expand Down
5 changes: 2 additions & 3 deletions truco/truco.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"encoding/json"
"errors"
"fmt"
"log"
)

// DefaultMaxPoints is the points a player must reach to win the game.
Expand Down Expand Up @@ -241,7 +240,7 @@ func (g *GameState) RunAction(action Action) error {

// Start new round if current round is finished
if !g.IsGameEnded && g.IsRoundFinished && len(g.RoundFinishedConfirmedPlayerIDs) == 2 {
fmt.Println("Starting new round...")
// fmt.Println("Starting new round...")
g.startNewRound()
return nil
}
Expand Down Expand Up @@ -275,7 +274,7 @@ func (g *GameState) RunAction(action Action) error {

g.PossibleActions = _serializeActions(possibleActions)

log.Printf("Possible actions: %v\n", possibleActions)
// log.Printf("Possible actions: %v\n", possibleActions)

return nil
}
Expand Down

0 comments on commit 61579ad

Please sign in to comment.