-
Notifications
You must be signed in to change notification settings - Fork 715
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
Fix for null last move if the move changed the stage #701
Fix for null last move if the move changed the stage #701
Conversation
Thanks for catching this! Do you think you could a test to the reducer test suite for undo-ing with stages so we can avoid regressions in the future? |
I'll try my best to recreate this situation in a small sample. |
@JGrzybowski Thanks — happy to help with any questions you might have. I think you can add a new but similar test to the current |
I've got the test butit fails as test('undo / redo with state', () => {
const game = {
seed: 0,
setup: ctx => {
ctx.events.setStage('StartingStage');
return { A: false, B: false, C: false };
},
turn: {
stages: {
StartingStage: {
moves: {
moveA: {
move: (G, ctx, moveAisReversible) => {
ctx.events.setStage('Stage_a');
return { ...G, moveAisReversible, A: true };
},
undoable: G => G.moveAisReversible > 0,
},
},
},
Stage_a: {
moves: {
moveB: {
move: (G, ctx) => {
ctx.events.setStage('Stage_b');
return { ...G, B: true };
},
undoable: false,
},
},
},
Stage_b: {
moves: {
moveC: {
move: (G, ctx) => {
ctx.events.setStage('Stage_c');
return { ...G, C: true };
},
undoable: true,
},
},
},
Stage_c: {
moves: {},
},
},
},
};
const reducer = CreateGameReducer({ game, numPlayers: 2 });
let state = InitializeGame({ game });
state = reducer(state, makeMove('moveA', true));
expect(state.G).toMatchObject({
moveAisReversible: true,
A: true,
B: false,
C: false,
});
expect(state.ctx.activePlayers['0']).toBe('Stage_a');
state = reducer(state, undo());
expect(state.G).toMatchObject({
A: false,
B: false,
C: false,
});
expect(state.ctx.activePlayers['0']).toBe('StartingStage');
state = reducer(state, redo());
expect(state.G).toMatchObject({
moveAisReversible: true,
A: true,
B: false,
C: false,
});
expect(state.ctx.activePlayers['0']).toBe('Stage_a');
state = reducer(state, undo());
expect(state.G).toMatchObject({
A: false,
B: false,
C: false,
});
expect(state.ctx.activePlayers['0']).toBe('StartingStage');
state = reducer(state, makeMove('moveA', false));
expect(state.G).toMatchObject({
moveAisReversible: false,
A: true,
B: false,
C: false,
});
expect(state.ctx.activePlayers['0']).toBe('Stage_a');
state = reducer(state, makeMove('moveB'));
expect(state.G).toMatchObject({
moveAisReversible: false,
A: true,
B: true,
C: false,
});
expect(state.ctx.activePlayers['0']).toBe('Stage_b');
state = reducer(state, undo());
expect(state.G).toMatchObject({
moveAisReversible: false,
A: true,
B: true,
C: false,
});
expect(state.ctx.activePlayers['0']).toBe('Stage_b');
state = reducer(state, makeMove('moveC'));
expect(state.G).toMatchObject({
moveAisReversible: false,
A: true,
B: true,
C: true,
});
expect(state.ctx.activePlayers['0']).toBe('Stage_c');
state = reducer(state, undo());
expect(state.G).toMatchObject({
moveAisReversible: false,
A: true,
B: true,
C: false,
});
expect(state.ctx.activePlayers['0']).toBe('Stage_b');
state = reducer(state, redo());
expect(state.G).toMatchObject({
moveAisReversible: false,
A: true,
B: true,
C: true,
});
expect(state.ctx.activePlayers['0']).toBe('Stage_c');
state = reducer(state, undo());
expect(state.G).toMatchObject({
moveAisReversible: false,
A: true,
B: true,
C: false,
});
expect(state.ctx.activePlayers['0']).toBe('Stage_b');
state = reducer(state, undo());
expect(state.G).toMatchObject({
moveAisReversible: false,
A: true,
B: true,
C: false,
});
expect(state.ctx.activePlayers['0']).toBe('Stage_b');
});
EDIT: The test fails at the very begging on the first assertion as it does not make the first move. |
Managed bo by pass the git push limit and to fix playerID issue but now the test looks fine to me but it looks linethe wrong stage is stored in undo redo array. It might be that the issue is not where I did my fix but rather in saving the |
@delucis can you confirm that the test checks expected behaviour of the stages events? |
@JGrzybowski Sorry, haven’t had time to go through this yet — will get to it soon! |
Thanks again for looking into this. The tests look correct to me, so I think there must be a bug somewhere. I’ve broken up the tests you added to make it clearer where they are failing and it seems that the problem is with the redo state: the Edit: If the redo stack has bad state, it comes from the undo stack, so now looking for how the undo is set — this is exactly what you suggested above: “saving the |
I would wrap those tests in I cannot verify it now, but I remember that the events like I think that if we would do the adding to the |
@JGrzybowski More or less got it! But I still need to fix some subtle bugs. The events code also needs to be able to reset the |
That's awesome! I'll see the solution in the afternoon. So, is it ready to
merge? Or do we wait for someone else to review it?
|
I think it should be ready to merge — just pushed a fix for the bug I’d found before. There is still some work to be done around undo/redo. For example, #565. So even after merging this, undo/redo with stages probably won’t work. Also, we don’t currently store the ID of the player who made a move in the undo state. That means we can’t check if the player undo-ing is the same player as made the move. This used to be obvious, because only |
During work on my project I've fount that if the move changed the stage undo throws an error.
After some debugging I've found that the last move is calculated using present context instead of previous one.
I'm not so familliar with this codebase (yet!) to be sure this fix is really needed but from logical point of view it would make sense.
I'm glad to hear any critique and questions.