From 3940de1e5a5322daecc82e0aad2424daeff7dbc0 Mon Sep 17 00:00:00 2001 From: guillaume Date: Mon, 20 Nov 2023 00:53:35 +0100 Subject: [PATCH] hole 3 --- src/12_RefactoringGolf/hole1/README.md | 22 +++++ src/12_RefactoringGolf/hole1/kata.ts | 130 +++++++++++++++---------- src/12_RefactoringGolf/hole1/test.ts | 16 ++- src/README.md | 22 ----- 4 files changed, 111 insertions(+), 79 deletions(-) create mode 100644 src/12_RefactoringGolf/hole1/README.md delete mode 100644 src/README.md diff --git a/src/12_RefactoringGolf/hole1/README.md b/src/12_RefactoringGolf/hole1/README.md new file mode 100644 index 0000000..e5237ca --- /dev/null +++ b/src/12_RefactoringGolf/hole1/README.md @@ -0,0 +1,22 @@ +# Hole 3 to Hole 4 + +Change the code in hole 3 to be identical to the code on hole 4, both implenentation and tests can change. + +## Refactorings + +- Remove magic strings and numbers + - Introduce constant + +## Tips + +- Use a diff tool to identify the code changes you need to perform +- Check the code coverage is enough to detect any unintended behaviour changes + +### While refactoring + +- Stay in the green while refactoring + - Run the tests after each refactor + - Check all tests still pass + - Check code coverage has not dropped +- Commit after each refactor +- In case of persistent test fails, use `git reset` to go back to green diff --git a/src/12_RefactoringGolf/hole1/kata.ts b/src/12_RefactoringGolf/hole1/kata.ts index c750e5e..0fadad1 100644 --- a/src/12_RefactoringGolf/hole1/kata.ts +++ b/src/12_RefactoringGolf/hole1/kata.ts @@ -2,78 +2,105 @@ export class Game { private _lastSymbol = ' '; - private _toto: Board = new Board(); + private _board: Board = new Board(); public Play(symbol: string, x: number, y: number): void { - //if first move + this.validateFirstMove(symbol); + this.validatePlayer(symbol); + this.validatePositionIsEmpty(x, y); + + this.updateLastPlayer(symbol); + this.updateBoard(symbol, x, y); + } + + private validateFirstMove(player: string) { if (this._lastSymbol == ' ') { - //if player is X - if (symbol == 'O') { + if (player == 'O') { throw new Error('Invalid first player'); } } - //if not first move but player repeated - else if (symbol == this._lastSymbol) { + } + + private validatePlayer(player: string) { + if (player == this._lastSymbol) { throw new Error('Invalid next player'); } - //if not first move but play on an already played tile - else if (this._toto.TileAt(x, y).Symbol != ' ') { + } + + private validatePositionIsEmpty(x: number, y: number) { + if (this._board.TileAt(x, y).Symbol != ' ') { throw new Error('Invalid position'); } + } + + private updateLastPlayer(player: string) { + this._lastSymbol = player; + } - // update game state - this._lastSymbol = symbol; - this._toto.AddTileAt(symbol, x, y); + private updateBoard(player: string, x: number, y: number) { + this._board.AddTileAt(player, x, y); } public Winner(): string { - //if the positions in first row are taken - if ( - this._toto.TileAt(0, 0)!.Symbol != ' ' && - this._toto.TileAt(0, 1)!.Symbol != ' ' && - this._toto.TileAt(0, 2)!.Symbol != ' ' - ) { - //if first row is full with same symbol - if ( - this._toto.TileAt(0, 0)!.Symbol == this._toto.TileAt(0, 1)!.Symbol && - this._toto.TileAt(0, 2)!.Symbol == this._toto.TileAt(0, 1)!.Symbol - ) { - return this._toto.TileAt(0, 0)!.Symbol; - } + if (this.isFirstRowFull() && this.isFirstRowFullWithSameSymbol()) { + return this._board.TileAt(0, 0)!.Symbol; } - //if the positions in first row are taken - if ( - this._toto.TileAt(1, 0)!.Symbol != ' ' && - this._toto.TileAt(1, 1)!.Symbol != ' ' && - this._toto.TileAt(1, 2)!.Symbol != ' ' - ) { - //if middle row is full with same symbol - if ( - this._toto.TileAt(1, 0)!.Symbol == this._toto.TileAt(1, 1)!.Symbol && - this._toto.TileAt(1, 2)!.Symbol == this._toto.TileAt(1, 1)!.Symbol - ) { - return this._toto.TileAt(1, 0)!.Symbol; - } + if (this.isSecondRowFull() && this.isSecondRowFullWithSameSymbol()) { + return this._board.TileAt(1, 0)!.Symbol; } - //if the positions in first row are taken - if ( - this._toto.TileAt(2, 0)!.Symbol != ' ' && - this._toto.TileAt(2, 1)!.Symbol != ' ' && - this._toto.TileAt(2, 2)!.Symbol != ' ' - ) { - //if middle row is full with same symbol - if ( - this._toto.TileAt(2, 0)!.Symbol == this._toto.TileAt(2, 1)!.Symbol && - this._toto.TileAt(2, 2)!.Symbol == this._toto.TileAt(2, 1)!.Symbol - ) { - return this._toto.TileAt(2, 0)!.Symbol; - } + if (this.isThirdRowFull() && this.isThirdRowFullWithSameSymbol()) { + return this._board.TileAt(2, 0)!.Symbol; } return ' '; } + + private isFirstRowFull() { + return ( + this._board.TileAt(0, 0)!.Symbol != ' ' && + this._board.TileAt(0, 1)!.Symbol != ' ' && + this._board.TileAt(0, 2)!.Symbol != ' ' + ); + } + + private isFirstRowFullWithSameSymbol() { + return ( + this._board.TileAt(0, 0)!.Symbol == this._board.TileAt(0, 1)!.Symbol && + this._board.TileAt(0, 2)!.Symbol == this._board.TileAt(0, 1)!.Symbol + ); + } + + private isSecondRowFull() { + return ( + this._board.TileAt(1, 0)!.Symbol != ' ' && + this._board.TileAt(1, 1)!.Symbol != ' ' && + this._board.TileAt(1, 2)!.Symbol != ' ' + ); + } + + private isSecondRowFullWithSameSymbol() { + return ( + this._board.TileAt(1, 0)!.Symbol == this._board.TileAt(1, 1)!.Symbol && + this._board.TileAt(1, 2)!.Symbol == this._board.TileAt(1, 1)!.Symbol + ); + } + + private isThirdRowFull() { + return ( + this._board.TileAt(2, 0)!.Symbol != ' ' && + this._board.TileAt(2, 1)!.Symbol != ' ' && + this._board.TileAt(2, 2)!.Symbol != ' ' + ); + } + + private isThirdRowFullWithSameSymbol() { + return ( + this._board.TileAt(2, 0)!.Symbol == this._board.TileAt(2, 1)!.Symbol && + this._board.TileAt(2, 2)!.Symbol == this._board.TileAt(2, 1)!.Symbol + ); + } } interface Tile { @@ -99,9 +126,6 @@ class Board { } public AddTileAt(symbol: string, x: number, y: number): void { - //@ts-ignore - const tile: Tile = { X: x, Y: y, Symbol: symbol }; - this._plays.find((t: Tile) => t.X == x && t.Y == y)!.Symbol = symbol; } } diff --git a/src/12_RefactoringGolf/hole1/test.ts b/src/12_RefactoringGolf/hole1/test.ts index 44d6c2a..9aa2e2e 100644 --- a/src/12_RefactoringGolf/hole1/test.ts +++ b/src/12_RefactoringGolf/hole1/test.ts @@ -8,23 +8,31 @@ describe('TicTacToe game', () => { }); test('should not allow player O to play first', () => { - expect(() => game.Play('O', 0, 0)).toThrow(); + expect(() => { + game.Play('O', 0, 0); + }).toThrow(); }); it('should not allow player x to play twice in a row', () => { game.Play('X', 0, 0); - expect(() => game.Play('X', 1, 0)).toThrow(); + expect(() => { + game.Play('X', 1, 0); + }).toThrow(); }); it('should not allow a player to play in last played position', () => { game.Play('X', 0, 0); - expect(() => game.Play('O', 0, 0)).toThrow(); + expect(() => { + game.Play('O', 0, 0); + }).toThrow(); }); it('should not allow a player to play in any played position', () => { game.Play('X', 0, 0); game.Play('O', 1, 0); - expect(() => game.Play('X', 0, 0)).toThrow(); + expect(() => { + game.Play('X', 0, 0); + }).toThrow(); }); it('should declare player X as winner if it plays three in top row', () => { diff --git a/src/README.md b/src/README.md deleted file mode 100644 index 4cfc9a0..0000000 --- a/src/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# Hole 1 to Hole 2 - -Change the code in hole 1 to be identical to the code in hole 2; implementation and tests can change. - -## Refactorings - -- Tackle code comments, long method and large class - - Extract method - -## Tips - -- Use a diff tool to identify the code changes you need to perform -- Check the code coverage is enough to detect any unintended behaviour changes - -### While refactoring - -- Stay in the green while refactoring; no failing tests - - Run the tests after each refactor - - Check all tests still pass - - Check code coverage has not dropped -- Commit after each refactor -- In case of persistent compilation errors or test fails, use `git reset` to go back to green