From 3940de1e5a5322daecc82e0aad2424daeff7dbc0 Mon Sep 17 00:00:00 2001 From: guillaume Date: Mon, 20 Nov 2023 00:53:35 +0100 Subject: [PATCH 1/5] 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 From e32a3ea105bfde43287b26c3453fcdac628b652d Mon Sep 17 00:00:00 2001 From: guillaume Date: Mon, 20 Nov 2023 16:54:21 +0100 Subject: [PATCH 2/5] enable linter --- src/12_RefactoringGolf/hole1/kata.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/12_RefactoringGolf/hole1/kata.ts b/src/12_RefactoringGolf/hole1/kata.ts index 0fadad1..050dc06 100644 --- a/src/12_RefactoringGolf/hole1/kata.ts +++ b/src/12_RefactoringGolf/hole1/kata.ts @@ -1,7 +1,7 @@ -/* eslint-disable */ +const leBonNom = ' '; export class Game { - private _lastSymbol = ' '; + private _lastSymbol = leBonNom; private _board: Board = new Board(); public Play(symbol: string, x: number, y: number): void { From 31e1f20ab50dc2d1185b1b940f3399ec831e704a Mon Sep 17 00:00:00 2001 From: guillaume iter Date: Mon, 27 Nov 2023 13:12:34 +0100 Subject: [PATCH 3/5] Tackle scope of constants and variables --- src/12_RefactoringGolf/hole1/README.md | 16 +++++-- src/12_RefactoringGolf/hole1/kata.ts | 64 ++++++++++++++++---------- 2 files changed, 52 insertions(+), 28 deletions(-) diff --git a/src/12_RefactoringGolf/hole1/README.md b/src/12_RefactoringGolf/hole1/README.md index e5237ca..99989af 100644 --- a/src/12_RefactoringGolf/hole1/README.md +++ b/src/12_RefactoringGolf/hole1/README.md @@ -1,15 +1,23 @@ -# Hole 3 to Hole 4 +# Hole 4 to Hole 5 -Change the code in hole 3 to be identical to the code on hole 4, both implenentation and tests can change. +Change the code in hole 4 to be identical to the code on hole 5, both implenentation and tests can change. ## Refactorings -- Remove magic strings and numbers - - Introduce constant +- Tackle scope of constants and variables + - Move constants and variables to proper scope + - les constantes et les variable ne sont pas au bon endroit, dans le bon scope + - Déplacez les pour qu'elles ne soient pas globales mais utilisées aux seuls endroits où on en a besoin + - +- Tackle duplication + - Introduce more generic methods to replace duplicted methods + - il y a des méthodes qui font la meme chose, trouvez les, et en les rendant à peine plus générique, réduisez le code dupliqué au strict nécessaire. ## Tips - Use a diff tool to identify the code changes you need to perform +- https://devconnected.com/how-to-compare-two-git-branches/ +- $ git diff branch1..branch2 - Check the code coverage is enough to detect any unintended behaviour changes ### While refactoring diff --git a/src/12_RefactoringGolf/hole1/kata.ts b/src/12_RefactoringGolf/hole1/kata.ts index 050dc06..4e9ba71 100644 --- a/src/12_RefactoringGolf/hole1/kata.ts +++ b/src/12_RefactoringGolf/hole1/kata.ts @@ -1,9 +1,19 @@ +/* eslint-disable */ -const leBonNom = ' '; export class Game { - private _lastSymbol = leBonNom; + private _lastSymbol = ' '; private _board: Board = new Board(); + private readonly playerO = 'O'; + private readonly emptyPlay = ' '; + + private readonly firstRow = 0; + private readonly secondRow = 1; + private readonly thirdRow = 2; + private readonly firstColumn = 0; + private readonly secondColumn = 1; + private readonly thirdColumn = 2; + public Play(symbol: string, x: number, y: number): void { this.validateFirstMove(symbol); this.validatePlayer(symbol); @@ -14,8 +24,8 @@ export class Game { } private validateFirstMove(player: string) { - if (this._lastSymbol == ' ') { - if (player == 'O') { + if (this._lastSymbol == this.emptyPlay) { + if (player == this.playerO) { throw new Error('Invalid first player'); } } @@ -28,7 +38,7 @@ export class Game { } private validatePositionIsEmpty(x: number, y: number) { - if (this._board.TileAt(x, y).Symbol != ' ') { + if (this._board.TileAt(x, y).Symbol != this.emptyPlay) { throw new Error('Invalid position'); } } @@ -43,62 +53,68 @@ export class Game { public Winner(): string { if (this.isFirstRowFull() && this.isFirstRowFullWithSameSymbol()) { - return this._board.TileAt(0, 0)!.Symbol; + return this._board.TileAt(this.firstRow, this.firstColumn)!.Symbol; } if (this.isSecondRowFull() && this.isSecondRowFullWithSameSymbol()) { - return this._board.TileAt(1, 0)!.Symbol; + return this._board.TileAt(this.secondRow, this.firstColumn)!.Symbol; } if (this.isThirdRowFull() && this.isThirdRowFullWithSameSymbol()) { - return this._board.TileAt(2, 0)!.Symbol; + return this._board.TileAt(this.thirdRow, this.firstColumn)!.Symbol; } - return ' '; + return this.emptyPlay; } private isFirstRowFull() { return ( - this._board.TileAt(0, 0)!.Symbol != ' ' && - this._board.TileAt(0, 1)!.Symbol != ' ' && - this._board.TileAt(0, 2)!.Symbol != ' ' + this._board.TileAt(this.firstRow, this.firstColumn)!.Symbol != this.emptyPlay && + this._board.TileAt(this.firstRow, this.secondColumn)!.Symbol != this.emptyPlay && + this._board.TileAt(this.firstRow, this.thirdColumn)!.Symbol != this.emptyPlay ); } 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 + this._board.TileAt(this.firstRow, this.firstColumn)!.Symbol == + this._board.TileAt(this.firstRow, this.secondColumn)!.Symbol && + this._board.TileAt(this.firstRow, this.thirdColumn)!.Symbol == + this._board.TileAt(this.firstRow, this.secondColumn)!.Symbol ); } private isSecondRowFull() { return ( - this._board.TileAt(1, 0)!.Symbol != ' ' && - this._board.TileAt(1, 1)!.Symbol != ' ' && - this._board.TileAt(1, 2)!.Symbol != ' ' + this._board.TileAt(this.secondRow, this.firstColumn)!.Symbol != this.emptyPlay && + this._board.TileAt(this.secondRow, this.secondColumn)!.Symbol != this.emptyPlay && + this._board.TileAt(this.secondRow, this.thirdColumn)!.Symbol != this.emptyPlay ); } 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 + this._board.TileAt(this.secondRow, this.firstColumn)!.Symbol == + this._board.TileAt(this.secondRow, this.secondColumn)!.Symbol && + this._board.TileAt(this.secondRow, this.thirdColumn)!.Symbol == + this._board.TileAt(this.secondRow, this.secondColumn)!.Symbol ); } private isThirdRowFull() { return ( - this._board.TileAt(2, 0)!.Symbol != ' ' && - this._board.TileAt(2, 1)!.Symbol != ' ' && - this._board.TileAt(2, 2)!.Symbol != ' ' + this._board.TileAt(this.thirdRow, this.firstColumn)!.Symbol != this.emptyPlay && + this._board.TileAt(this.thirdRow, this.secondColumn)!.Symbol != this.emptyPlay && + this._board.TileAt(this.thirdRow, this.thirdColumn)!.Symbol != this.emptyPlay ); } 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 + this._board.TileAt(this.thirdRow, this.firstColumn)!.Symbol == + this._board.TileAt(this.thirdRow, this.secondColumn)!.Symbol && + this._board.TileAt(this.thirdRow, this.thirdColumn)!.Symbol == + this._board.TileAt(this.thirdRow, this.secondColumn)!.Symbol ); } } From 7f77c87fdf74d5fa3657decfa565a564b2038ab3 Mon Sep 17 00:00:00 2001 From: Jules Cayrol Date: Mon, 27 Nov 2023 16:06:54 +0100 Subject: [PATCH 4/5] test commit --- src/12_RefactoringGolf/hole1/kata.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/12_RefactoringGolf/hole1/kata.ts b/src/12_RefactoringGolf/hole1/kata.ts index 4e9ba71..73c5a5c 100644 --- a/src/12_RefactoringGolf/hole1/kata.ts +++ b/src/12_RefactoringGolf/hole1/kata.ts @@ -1,5 +1,6 @@ /* eslint-disable */ +//salut export class Game { private _lastSymbol = ' '; private _board: Board = new Board(); From 12a761a4d8937cd16b451584fbfe3c2ce4859da8 Mon Sep 17 00:00:00 2001 From: Jules Cayrol Date: Mon, 27 Nov 2023 16:42:05 +0100 Subject: [PATCH 5/5] =?UTF-8?q?refactoring=20-=20D=C3=A9placement=20des=20?= =?UTF-8?q?constantes=20au=20dessus=20de=20la=20classe=20Game=20et=20passa?= =?UTF-8?q?ge=20de=20"private=20readonly"=20a=20"const"=20-=20=5FlastSymbo?= =?UTF-8?q?l=20:=20passage=20de=20la=20valeur=20de=20la=20constante=20empt?= =?UTF-8?q?yPlay=20-suppression=20des=20"this."=20pour=20les=20constantes?= =?UTF-8?q?=20-refactoring=20des=20fonctions=20isRowFirst=20et=20isRowFull?= =?UTF-8?q?WithSameSymbol?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/12_RefactoringGolf/hole1/kata.ts | 94 +++++++++------------------- 1 file changed, 29 insertions(+), 65 deletions(-) diff --git a/src/12_RefactoringGolf/hole1/kata.ts b/src/12_RefactoringGolf/hole1/kata.ts index 73c5a5c..5f28c95 100644 --- a/src/12_RefactoringGolf/hole1/kata.ts +++ b/src/12_RefactoringGolf/hole1/kata.ts @@ -1,19 +1,18 @@ /* eslint-disable */ -//salut -export class Game { - private _lastSymbol = ' '; - private _board: Board = new Board(); +const playerO = 'O'; +const emptyPlay = ' '; - private readonly playerO = 'O'; - private readonly emptyPlay = ' '; +const firstRow = 0; +const secondRow = 1; +const thirdRow = 2; +const firstColumn = 0; +const secondColumn = 1; +const thirdColumn = 2; - private readonly firstRow = 0; - private readonly secondRow = 1; - private readonly thirdRow = 2; - private readonly firstColumn = 0; - private readonly secondColumn = 1; - private readonly thirdColumn = 2; +export class Game { + private _lastSymbol = emptyPlay; + private _board: Board = new Board(); public Play(symbol: string, x: number, y: number): void { this.validateFirstMove(symbol); @@ -25,8 +24,8 @@ export class Game { } private validateFirstMove(player: string) { - if (this._lastSymbol == this.emptyPlay) { - if (player == this.playerO) { + if (this._lastSymbol == emptyPlay) { + if (player == playerO) { throw new Error('Invalid first player'); } } @@ -39,7 +38,7 @@ export class Game { } private validatePositionIsEmpty(x: number, y: number) { - if (this._board.TileAt(x, y).Symbol != this.emptyPlay) { + if (this._board.TileAt(x, y).Symbol != emptyPlay) { throw new Error('Invalid position'); } } @@ -53,69 +52,34 @@ export class Game { } public Winner(): string { - if (this.isFirstRowFull() && this.isFirstRowFullWithSameSymbol()) { - return this._board.TileAt(this.firstRow, this.firstColumn)!.Symbol; + if (this.isRowFull(firstRow) && this.isRowFullWithSameSymbol(firstRow)) { + return this._board.TileAt(firstRow, firstColumn)!.Symbol; } - if (this.isSecondRowFull() && this.isSecondRowFullWithSameSymbol()) { - return this._board.TileAt(this.secondRow, this.firstColumn)!.Symbol; + if (this.isRowFull(secondRow) && this.isRowFullWithSameSymbol(secondRow)) { + return this._board.TileAt(secondRow, firstColumn)!.Symbol; } - if (this.isThirdRowFull() && this.isThirdRowFullWithSameSymbol()) { - return this._board.TileAt(this.thirdRow, this.firstColumn)!.Symbol; + if (this.isRowFull(thirdRow) && this.isRowFullWithSameSymbol(thirdRow)) { + return this._board.TileAt(thirdRow, firstColumn)!.Symbol; } - return this.emptyPlay; - } - - private isFirstRowFull() { - return ( - this._board.TileAt(this.firstRow, this.firstColumn)!.Symbol != this.emptyPlay && - this._board.TileAt(this.firstRow, this.secondColumn)!.Symbol != this.emptyPlay && - this._board.TileAt(this.firstRow, this.thirdColumn)!.Symbol != this.emptyPlay - ); - } - - private isFirstRowFullWithSameSymbol() { - return ( - this._board.TileAt(this.firstRow, this.firstColumn)!.Symbol == - this._board.TileAt(this.firstRow, this.secondColumn)!.Symbol && - this._board.TileAt(this.firstRow, this.thirdColumn)!.Symbol == - this._board.TileAt(this.firstRow, this.secondColumn)!.Symbol - ); - } - - private isSecondRowFull() { - return ( - this._board.TileAt(this.secondRow, this.firstColumn)!.Symbol != this.emptyPlay && - this._board.TileAt(this.secondRow, this.secondColumn)!.Symbol != this.emptyPlay && - this._board.TileAt(this.secondRow, this.thirdColumn)!.Symbol != this.emptyPlay - ); - } - - private isSecondRowFullWithSameSymbol() { - return ( - this._board.TileAt(this.secondRow, this.firstColumn)!.Symbol == - this._board.TileAt(this.secondRow, this.secondColumn)!.Symbol && - this._board.TileAt(this.secondRow, this.thirdColumn)!.Symbol == - this._board.TileAt(this.secondRow, this.secondColumn)!.Symbol - ); + return emptyPlay; } - private isThirdRowFull() { + private isRowFull(row: number) { return ( - this._board.TileAt(this.thirdRow, this.firstColumn)!.Symbol != this.emptyPlay && - this._board.TileAt(this.thirdRow, this.secondColumn)!.Symbol != this.emptyPlay && - this._board.TileAt(this.thirdRow, this.thirdColumn)!.Symbol != this.emptyPlay + this._board.TileAt(row, firstColumn)!.Symbol != emptyPlay && + this._board.TileAt(row, secondColumn)!.Symbol != emptyPlay && + this._board.TileAt(row, thirdColumn)!.Symbol != emptyPlay ); } - private isThirdRowFullWithSameSymbol() { + private isRowFullWithSameSymbol(row: number) { return ( - this._board.TileAt(this.thirdRow, this.firstColumn)!.Symbol == - this._board.TileAt(this.thirdRow, this.secondColumn)!.Symbol && - this._board.TileAt(this.thirdRow, this.thirdColumn)!.Symbol == - this._board.TileAt(this.thirdRow, this.secondColumn)!.Symbol + this._board.TileAt(row, firstColumn)!.Symbol == + this._board.TileAt(row, secondColumn)!.Symbol && + this._board.TileAt(row, thirdColumn)!.Symbol == this._board.TileAt(row, secondColumn)!.Symbol ); } }