-
Notifications
You must be signed in to change notification settings - Fork 0
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
Add new boards to Baduk variant #255
Conversation
} | ||
|
||
override exportState(): BadukState { | ||
return { | ||
board: this.board.to2DArray(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd really like to keep the exports "JSON-compatible". What I mean by that is information should not be lost by converting to JSON:
let grid: Grid<number> = ...;
let arr: number[][] = ...;
grid = JSON.parse(JSON.stringify(grid)); // not actually a Grid
arr = JSON.parse(JSON.stringify(arr)); // a 2D Array, just like the original
Motivation: We need to keep in mind that game state needs to travel over the wire at some point (#48, #174), and we need a way to losslessly encode the state.
In my mind, the way to do that is to return simple types from exportState()
with helper methods like Grid.prototype.to2DArray()
, then use the JSON utils to encode and decode. (If you need a Graph
-compatible way to do this, feel free to alias that method to Grid.prototype.serialize()
).
And let me know if you'd propose another way to pass state over the wire that doesn't simplification inside exportState!
This is so great by the way, I'm looking forward to playing some more graph Go! And I really appreciate the effort you put into de-duplicating implementations - this will help maintainability immensely. |
One thought to keep this PR small and atomic - if you introduce a GridBaduk adapter, you won't need to change all the downstream stuff (vue boards, config forms, etc) at the same time. Something like (I think the types work.. ts playground):
This will also remove the need to assert the type of board at the access-site in variants like Keima and Pyramid ( |
return a.map(copyArray); | ||
} | ||
|
||
export class GraphWrapper<T> implements Fillable<CoordinateLike, T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm envisioning a version without GraphWrapper
at some point. I've thought about passing decodeMove(move: string): TKey
to a Baduk<TKey>
class that has a board: Fillable<TKey, Color>
via the constructor.
But it's not important.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about introducing a new interface that extends fillable? It could be our board interface and have methods like serialize, reduce etc. that maybe don't fit fillable, but make sense for our board interface?
Then this interface could also handle the encoding / decoding of moves.
} | ||
|
||
export type BadukMove = { 0: string } | { 1: string }; | ||
|
||
export declare type BadukBoardType<TColor> = Fillable<CoordinateLike, TColor>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we could just call this BadukBoard
instead of BadukBoardType
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
renamed to BadukBoard
let black_points = 0; | ||
board.forEach( | ||
(intersection) => (black_points += intersection === Color.BLACK ? 1 : 0), | ||
); | ||
|
||
let white_points = 0; | ||
board.forEach( | ||
(intersection) => (white_points += intersection === Color.WHITE ? 1 : 0), | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why stop using reduce()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reduce() is not a method of the Fillable interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we remove it, we should get rid of count_color function below.
OTOH, I have no problem adding reduce
to the Fillable
interface either. (At this point the interface has grown to much more than "something that can be flood filled" 😂)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alternatively, we could also have Fillable
return a one-dimensional array and use reduce
on that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with any of these options, so I'd like to leave the decision to you.
We can also undo the changes here and continue using this type instead of fillable:
export declare type BadukBoard<TColor> = Grid<TColor> | GraphWrapper<TColor>;
... which allows using board.reduce()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh sure if that allows us to use reduce
again, typing as Grid | GraphWrapper
would be nice!
In the end I don't have a strong preference - I do want to keep reduce
so we can re-use the reducer and keep variables like white_points
const
, but otherwise I don't feel strongly about how we do it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done!
); | ||
const white_points: number = | ||
board.reduce(count_color<Color>(Color.WHITE), 0) + this.config.komi; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like komi is gone.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, thank you for catching that! Fixed
export function groupHasLiberties(group: CoordinateLike[], board: Grid<Color>) { | ||
export function groupHasLiberties( | ||
group: CoordinateLike[], | ||
board: Fillable<CoordinateLike, Color>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be BadukBoard<Color>
instead of Fillable<...>
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed type to BadukBoard
|
||
export type GridBadukConfig = { | ||
width: number; | ||
height: number; | ||
komi: number; | ||
board?: GridBoardConfig; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use something like
export type GridBadukConfig = {
width: number;
height: number;
komi: number;
} | {
board: GridBoardConfig;
komi: number;
}
otherwise there's room for trouble:
{
komi: 6.5;
width: 9;
height: 9;
board: {
type: "grid";
width: 19;
height: 19;
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
Color, | ||
groupHasLiberties, | ||
isGridBadukConfig, | ||
} from "./baduk"; | ||
|
||
export interface DriftGoConfig extends BadukConfig { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this extend GridBadukConfig
instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed to type and extend GridBadukConfig
private typedConfig: DriftGoConfig; | ||
|
||
constructor(config?: DriftGoConfig) { | ||
if (config && !isGridBadukConfig(config)) { | ||
throw Error("config for drift must be for board type grid"); | ||
} | ||
super(config); | ||
this.typedConfig = config ?? this.defaultConfig(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can change the type of the board to a Grid here.
See
class Board {
foo() {
return "graph";
}
}
class SpecificBoard extends Board {
foo() { return "grid"; }
bar() { return "asdf"; }
}
class GameParent {
constructor(protected board: Board) {
}
public foo() {
return this.board.foo();
}
}
class GameChild extends GameParent {
constructor(protected board: SpecificBoard) {
super(board);
}
public bar() {
return this.board.bar();
}
}
const game = new GameChild(new SpecificBoard());
console.log(game.foo()); // prints "grid"
console.log(game.bar()); // prints "asdf"
Then we wouldn't need the as Grid
type assertions.
@@ -23,7 +23,7 @@ class BadukHelper { | |||
this.badukGame.playMove(player, "pass"); | |||
} | |||
|
|||
play(player: number, move: string): Coordinate[] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I like the rule "Return the most specific type, accept the most generic type". In other words, I usually accept CoordinateLike
as argument, and return Coordinate
. That way, callers have access to all the utility methods of the Coordinate
class, but only need to pass the bare minimum ({x: 1, y: 2}
) as a parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed the types in quantum.ts thusly
Revert to 2D array board and introduce GridBaduk class
currBoard: BadukBoardType<Color>, | ||
): CoordinateLike[] { | ||
const captures: CoordinateLike[] = []; | ||
prevBoard.forEach((color, coordinate) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice generic refactor!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you
@@ -12,7 +11,7 @@ export class TetrisGo extends Baduk { | |||
} | |||
} | |||
|
|||
function getGroup(pos: CoordinateLike, board: Grid<Color>) { | |||
function getGroup(pos: CoordinateLike, board: BadukBoardType<Color>) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This implementation won't work for graph boards, even with the GraphWrapper. Luckily, I think this is just a grid version of group_utils.getGroup()
and can be replaced altogether.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, thanks for pointing this out! Replaced by group_utils.getGroup()
Ok, I think I'm at a point where we can (hopefully) merge this. Here's an overview of what I did since yesterday:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey looks good, no blocking comments. I haven't tested the UI changes, but I trust you will at least run through the game creation flow with one of the affected variants.
Thanks for doing this!
// This was used before... will need to figure out where it went | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// This was used before... will need to figure out where it went | |
// eslint-disable-next-line @typescript-eslint/no-unused-vars |
I added these comments to suppress the linter. Should be good to remove now that we reverted the reduce(count_color())
code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed comments
@@ -190,19 +216,48 @@ export class Baduk extends AbstractGame<BadukConfig, BadukState> { | |||
this.phase = "gameover"; | |||
} | |||
|
|||
defaultConfig(): BadukConfig { | |||
defaultConfig(): GridBadukConfig { | |||
return { width: 19, height: 19, komi: 6.5 }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If top level width
and height
are now considered legacy, we may want to update this return value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed to return new type structure
for (const pos of group) { | ||
this.badukGame.board.set(pos, Color.EMPTY); | ||
} | ||
} | ||
} | ||
|
||
export class QuantumGo extends AbstractGame<BadukConfig, QuantumGoState> { | ||
export class QuantumGo extends AbstractGame<GridBadukConfig, QuantumGoState> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't have to change in this PR, but I think QuantumGo can be adapted to graph boards with only moderate effort.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's the plan eventually! I believe this will work as soon as I changed the vue-client components for rendering the board for Baduk. But that's for another PR.
@@ -15,7 +15,7 @@ import { positionsGetter } from "./board_utils"; | |||
const props = defineProps<{ | |||
board: (MulticolorStone | null)[][]; | |||
background_color?: string; | |||
config: { height: number; width: number }; | |||
config: { width: number; height: number }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps change this property name from config
to dimensions
since it's no longer representative of the game config.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed props name to board_dimensions
Still needs to be done: