I don’t have much experience as a programmer, I started working as a junior software engineer in July last year. Plust I didn’t study informatics but mathematics, so I don’t feel qualified to answer questions such as “what programming language / sdk’s should we use?” etc.
I think that is useful, plus I believe that we need to be able to communicate between client and server in both directions.
In general I like the idea of making variants combineable, like variant go server does. And for this purpose it would be nice to extend VGS. But I can see some drawbacks.
Probably the more variants we support, the more difficult will it be to implement them in a compatible way (I think it might be helpful to categorise them by what parts of the rules they change, e.g. the board layout, the move sequence, the objective etc.). And the bigger the project, the more work to change some integral parts.
Plus I believe that combining many variants is maybe not as exciting as trying out one new variant. For example if we have four variants that can be combined freely, that makes 16 possibilities. Trying everything might be a bit overwhelming.
For those reasons I don’t mind starting a new project. But I’m also down to try to extend VGS (or one of the others)
trigo (two moves per player on a hex board, except Black plays one stone on the first move)
Blooms (hex board, but two colors per player, and the objective is N captures. Place one or two stones each turn but of different colors. First player places only one stone)
Keil (hex board, but connections are not just being adjacent, it’s about having mutually adjacent points that don’t contain the other player color)
Redstone (normal grid but captures are redstones, no passing, capture all opponents stones to win)
If I understand it correctly, Keil is an example for a variant that cannot (feasibly) be played on any grid. If you were to apply Keil’s definition of connectivity and liberties to a rectangular board, then any stone would immediately be captured due to having no liberty … then all moves are illegal. Just goes to show that combining variants can be tricky.
I have a suggestion: We discuss which basic elements we need and then we decide whether it is easier to change an existing project or start something from scratch.
Currently we know that:
There will be different variants which define the rules of the game
The game will be played on a board. A board consists of intersections (nodes) which are connected to other intersections. Boards are mostly represented in 2D, but might also be represented in 3D or something else.
At certain times certain players are allowed to place stones on (empty) board intersections (or if chess, move stones/pieces from one intersection to another)
If multiple players are allowed to make moves at the same time, rules for collision handling are needed.
Stones have different attributes (e.g. colors, visiblity, display colors)
Stones (may) form groups with other stones, normally by being adjacent to each other.
Stones/groups can be removed, e.g. when all adjacent intersections are occupied by stones of a different color.
Players can be eliminated i.e. lose the possibility to place stones/make moves.
Win conditions define the result of a game and may vary between variants.
Currently I’m tending towards building something new, because of Variant Go Server’s biases towards chinese scoring, alternating moves, intersections with x-y-coordinates, but we could probably use a lot of the existing code, so I still think changing Variant Go Server might be a viable option too.
Go and Go variants have a scoring phase where players need to agree on dead stones (even it they arent fully surrounded).
That’s a difficult UX topic even without variants!
Variant Go Server
One question: has anyone managed to get the server running? I tried and failed, but that’s says more about my (lack of) docker experience than anything else…
One way to bypass the UX problem that is the scoring phase is to use area scoring with the exception that dead stones have to be captured (i.e. Tromp Taylor Scoring)
AFAIK that is how dipgo does it (or at least used to do it), and maybe VGS too …? I’m not entirely sure.
I’ve been thinking how to model a game in an abstract (mathematical) way that doesn’t restrict ourselves too much, but still helps by providing some structure. (Just to be sure, I’m not proposing we use these as part of our data structure.) Here’s the ideas I came up with:
A game has a list of players.
At all times a game has a game-state. (contains all informations needed for rule considerations, might e.g. include information that defines …
the board position
previous game-states
which player has which informations
etc.)
A game has rounds. (discrete time units where players make decisions. I find this a sensible assumption unless we want to include “real-time” variants.)
During each round, all players have options. (can depend on the game-state, and a player can have zero options)
A game has a transition function, which takes the game-state and all options chosen by players this round as input, and replaces the current game-state by a new one whenever we proceed to the next round.
The game ends when reaching a game-state where all players have zero options.
I believe these assumptions facilitate all variants that we listed so far. (although I’m not 100% confident ) There are still unanswered questions such as
under what circumstances do we proceed to the next round? (e.g. when all players made a choice, or after a fixed time etc.)
are there mechanics working outside the turn-based system? (e.g. resignation)
Not sure if any of this helps though, sorry if I’m being too abstract here.
I think it’s good to think about it like that. And that’s a perspective I haven’t discovered in the code of VGS, it seems that its code evolved variant by variant (“if this variant, do this” pops up a lot in the code) and it’s lacking some sort of abstraction layer.
To propose a simpler alternative, what if the server only handled keeping track of a sequence of board positions, allowing various combinations of colors but making no attempt to enforce any particular rules? Like Vsotvep MulticolorGo but with a recorded game history and a chat window. If we got that much done, maybe additional modules later could implement some rules.
I think we’re on the same page as far as abstract representation goes!
Confession: I’ve actually been working on something, just to kind of see if I could crank out a prototype. Turns out it’s hard to try to build a backend, frontend and middle end from scratch at the same time
Anyway, here's what I've got so far for an abstract base class
/**
* An abstract class that can represent any game on the server
*/
export abstract class AbstractGame<
GameConfig = object,
GameState = object,
DeadStones = string
> {
private phase_: GamePhase = "play";
private result_: string = "";
constructor(protected readonly config: GameConfig) {}
/**
* Play one move by the specified player.
*
* May throw if the move was invalid and we should return that information
* to the user
*/
abstract playMove(move: MovesType): void;
/** Returns complete representation of the game. */
abstract exportState(): GameState;
/**
* Returns the list of players that need to play a move the next round.
*/
abstract nextToPlay(): number[];
/**
* Total number of players required for this game. The players will be
* referenced by number (zero-indexed).
*/
abstract numPlayers(): number;
get phase(): GamePhase {
return this.phase_;
}
protected set phase(p: GamePhase) {
this.phase_ = p;
}
// Scoring
/** Sets the dead stones on the board */
setDeadStones(_dead_stones: DeadStones): void {
// Subclasses may reimplement this function if there is a scoring phase.
}
/** Ends the scoring phase and finalizes the result.
*
* This should likely be reimplemented if setDeadStones has been reimplemented.
*/
finalizeScore() {
this.phase_ = "gameover";
}
/** Get result. Will only be called when phase() is "gameover" */
get result(): string {
return this.result_;
}
/** Sets the result of the game. */
protected set result(res: string) {
this.result_ = res;
}
canResign(player_: number): boolean {
return this.numPlayers() === 2;
}
resign(player: number) {
this.phase_ = "gameover";
const opponent = 1 - player;
this.result_ = `Player ${opponent} + R`;
}
}
export interface MovesType {
[player: number]: string;
}
export type GamePhase = "play" | "scoring" | "gameover";
The only thing that doesn’t feel abstract is the scoring, but as you mentioned, this can be avoided by using Tromp-Taylor scoring. Still, I think at some point, we might want to implement more mainstream score agreement.
I wasn’t going to share the codebase before I had some running game, but if either of you has interest in checking it out/getting it running, I’m happy to make the repo public.
Interesting idea. In the end I’d want a server that does enforce the rules, but building on what you’ve proposed could be a way to go.
Nice work. And yes, keeping track of so many things at the same time can be hard, focusing on what is important for whatever -end one is working on should help.
Some variants don’t even have scoring, like Go Battle Royale (and chess).
What programming languages does everybody know? Recently I gained a bit experience with Typescript (with Angular) and some more with C#.
(long time ago C++ and even longer ago Delphi)
Me too. Although deno might be a modern alternative for node. And I’d like to try more TypeScript to get more experience, but I’d be okay with plain JS or something else too.
I don’t know anything about deno, but if it’s well supported (good package manager, support for the web frameworks we want to use), it sounds like a cool technology!
What do you all think of that? In terms of @martin3141’s abstraction that would mean the transition function can be carried out by users*, which would allow for a lot of flexibility. When starting a new game users could decide to pick an existing transition function (handled automatically by the server) or to do the transitioning on their own.
Should we start with that?
*Actually that’s not totally true, because the rules also define which options players have. So those have to be considered too.