Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README ETUDIANTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Nom Prénom

- Pesant Fantin
- Chlabi Aymen
- Pouget--Péjoan Elfin
- Hoarau Allan
14 changes: 7 additions & 7 deletions src/12_RefactoringGolf/exo5/README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
# Exo 5 to Exo 6


## Refactorings

- PROBLEME: la loi de Demeter n'est pas respectée ("Tell, Don't Ask" ou "principle of least knowledge")
- https://martinfowler.com/bliki/TellDontAsk.html
- https://savoiragile.com/2012/05/04/connaissez-vous-la-loi-de-demeter/
- https://tech-fr.netlify.app/articles/fr512716/index.html
- https://www.arolla.fr/blog/2017/02/principes-solid-vie-de-jours/#Loi_de_Demeter
- <https://martinfowler.com/bliki/TellDontAsk.html>
- <https://savoiragile.com/2012/05/04/connaissez-vous-la-loi-de-demeter/>
- <https://tech-fr.netlify.app/articles/fr512716/index.html>
- <https://www.arolla.fr/blog/2017/02/principes-solid-vie-de-jours/#Loi_de_Demeter>


- REVUE DE CODE: repérez les endroits où, pour obtenir une condition dans un IF, on fait appel (ASK) à des propriétés
- REVUE DE CODE: repérez les endroits où, pour obtenir une condition dans un IF, on fait appel (ASK) à des propriétés
qui ne sont pas dans l'objet courant
Example:

```javascript
if (
this._board.TileAt(row, firstColumn)!.Symbol ==
Expand Down
177 changes: 98 additions & 79 deletions src/12_RefactoringGolf/exo5/kata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,106 +10,125 @@ const thirdColumn = 2;
const playerO = 'O';
const emptyPlay = ' ';

export class Game {
private _lastSymbol = emptyPlay;
private _board: Board = new Board();
interface TileInterface {
X: number;
Y: number;
Symbol: string;
}

public Play(symbol: string, x: number, y: number): void {
this.validateFirstMove(symbol);
this.validatePlayer(symbol);
this.validatePositionIsEmpty(x, y);
class Tile implements TileInterface {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Création d'une classe Tile pour remplacer l'interface et ajouter des fonctionnalités

X: number;
Y: number;
Symbol: string;

this.updateLastPlayer(symbol);
this.updateBoard(symbol, x, y);
}
constructor(x: number, y: number, symbol: string) {
this.X = x;
this.Y = y;
this.Symbol = symbol;
}

private validateFirstMove(player: string) {
if (this._lastSymbol == emptyPlay) {
if (player == playerO) {
throw new Error('Invalid first player');
isEmpty(): boolean {
return this.Symbol === emptyPlay;
}
}
}

private validatePlayer(player: string) {
if (player == this._lastSymbol) {
throw new Error('Invalid next player');
}
hasSameSymbolAs(other: Tile): boolean {
return this.Symbol === other.Symbol;
}
}

private validatePositionIsEmpty(x: number, y: number) {
if (this._board.TileAt(x, y).Symbol != emptyPlay) {
throw new Error('Invalid position');
}
}
export class Game {
private _lastSymbol = emptyPlay;
private _board: Board = new Board();

private updateLastPlayer(player: string) {
this._lastSymbol = player;
}
public Play(symbol: string, x: number, y: number): void {
this.validateFirstMove(symbol);
this.validatePlayer(symbol);
this.validatePositionIsEmpty(x, y);

private updateBoard(player: string, x: number, y: number) {
this._board.AddTileAt(player, x, y);
}
this.updateLastPlayer(symbol);
this.updateBoard(symbol, x, y);
}

public Winner(): string {
return this._board.findRowFullWithSamePlayer();
}
}
private validateFirstMove(player: string) {
if (this._lastSymbol == emptyPlay) {
if (player == playerO) {
throw new Error('Invalid first player');
}
}
}

interface Tile {
X: number;
Y: number;
Symbol: string;
}
private validatePlayer(player: string) {
if (player == this._lastSymbol) {
throw new Error('Invalid next player');
}
}

class Board {
private _plays: Tile[] = [];
private validatePositionIsEmpty(x: number, y: number) {
if (!this._board.TileAt(x, y).isEmpty()) {
throw new Error('Invalid position');
}
}

constructor() {
for (let i = firstRow; i <= thirdRow; i++) {
for (let j = firstColumn; j <= thirdColumn; j++) {
const tile: Tile = { X: i, Y: j, Symbol: emptyPlay };
this._plays.push(tile);
private updateLastPlayer(player: string) {
this._lastSymbol = player;
}
}
}

public TileAt(x: number, y: number): Tile {
return this._plays.find((t: Tile) => t.X == x && t.Y == y)!;
}
private updateBoard(player: string, x: number, y: number) {
this._board.AddTileAt(player, x, y);
}

public AddTileAt(symbol: string, x: number, y: number): void {
this._plays.find((t: Tile) => t.X == x && t.Y == y)!.Symbol = symbol;
public Winner(): string {
return this._board.findRowFullWithSamePlayer();
}
}

public findRowFullWithSamePlayer(): string {
if (this.isRowFull(firstRow) && this.isRowFullWithSameSymbol(firstRow)) {
return this.TileAt(firstRow, firstColumn)!.Symbol;
}
class Board {
private _plays: Tile[] = [];

constructor() {
for (let i = firstRow; i <= thirdRow; i++) {
for (let j = firstColumn; j <= thirdColumn; j++) {
this._plays.push(new Tile(i, j, emptyPlay));
}
}
}

if (this.isRowFull(secondRow) && this.isRowFullWithSameSymbol(secondRow)) {
return this.TileAt(secondRow, firstColumn)!.Symbol;
}
public TileAt(x: number, y: number): Tile {
return this._plays.find((t: Tile) => t.X == x && t.Y == y)!;
}

if (this.isRowFull(thirdRow) && this.isRowFullWithSameSymbol(thirdRow)) {
return this.TileAt(thirdRow, firstColumn)!.Symbol;
}
public AddTileAt(symbol: string, x: number, y: number): void {
this.TileAt(x, y).Symbol = symbol;
}

return emptyPlay;
}
public findRowFullWithSamePlayer(): string {
if (this.isRowFull(firstRow) && this.isRowFullWithSameSymbol(firstRow)) {
return this.TileAt(firstRow, firstColumn)!.Symbol;
}

private isRowFull(row: number) {
return (
this.TileAt(row, firstColumn)!.Symbol != emptyPlay &&
this.TileAt(row, secondColumn)!.Symbol != emptyPlay &&
this.TileAt(row, thirdColumn)!.Symbol != emptyPlay
);
}
if (this.isRowFull(secondRow) && this.isRowFullWithSameSymbol(secondRow)) {
return this.TileAt(secondRow, firstColumn)!.Symbol;
}

private isRowFullWithSameSymbol(row: number) {
return (
this.TileAt(row, firstColumn)!.Symbol == this.TileAt(row, secondColumn)!.Symbol &&
this.TileAt(row, thirdColumn)!.Symbol == this.TileAt(row, secondColumn)!.Symbol
);
}
if (this.isRowFull(thirdRow) && this.isRowFullWithSameSymbol(thirdRow)) {
return this.TileAt(thirdRow, firstColumn)!.Symbol;
}

return emptyPlay;
}

private isRowFull(row: number) {
return (
!this.TileAt(row, firstColumn).isEmpty() &&
!this.TileAt(row, secondColumn).isEmpty() &&
!this.TileAt(row, thirdColumn).isEmpty()
);
}

private isRowFullWithSameSymbol(row: number) {
return (
this.TileAt(row, firstColumn).hasSameSymbolAs(this.TileAt(row, secondColumn)) &&
this.TileAt(row, thirdColumn).hasSameSymbolAs(this.TileAt(row, secondColumn))
);
}
}
6 changes: 6 additions & 0 deletions src/12_RefactoringGolf/exo5/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,10 @@ describe('TicTacToe game', () => {

expect(winner).toBe('O');
});

it('should declare empty string as winner if nothing is played', () => {
const winner = game.Winner();

expect(winner).toBe(' ');
});
});