Skip to content

Commit

Permalink
feat: 🎉 Init Goban test
Browse files Browse the repository at this point in the history
Setup the project using TS and NPM
Add goban test with Readme, skeleton and tests
  • Loading branch information
fxalgrain committed Oct 11, 2024
1 parent 5c82ca5 commit 75ee6c7
Show file tree
Hide file tree
Showing 7 changed files with 500 additions and 2 deletions.
59 changes: 59 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
### IDE ###
.vscode
.idea/

### direnv ###
.direnv
.envrc

### macOS ###
.DS_Store
# Thumbnails
._*

### Node ###
# Logs
logs
*.log
npm-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# unit tests code coverage reports
coverage/

# nyc test coverage
.nyc_output

# Dependency directories
node_modules/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# dotenv environment variables file
.env
.env*.local

# Default build output
dist/

# Temporary folders
tmp/
temp/


### Windows ###
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable

# Folder config file
[Dd]esktop.ini
76 changes: 74 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,74 @@
# ts-backend-tech-test
TypeScript Backend technical test.
# Lumapps Goban Technical test

## How to launch the project

To setup and launch tests:

```sh
git clone https://github.com/lumapps/test-goban-ts.git
cd test-goban-ts
npm install
npm test
```

## Technical Test

The theme of this test is the game of go.

The goal is to write a function that determines whether the stone at an x, y position on a goban is taken or not.

Vocabulary:

- Goban: the board on which stones are placed to play
- Shape: a group of one or more adjacent stones of the same color (adjacent: stones that are left, right, top, bottom of each other, diagonals do not count)
- Freedom: empty space adjacent to a shape

Reminder of the rules:

1. The goban has an indefinite size
2. There are two players and everyone plays a stone color: black or white
3. The stones are laid one after the other each turn
4. When a form has no more freedom it is taken

The objective of the test is to write an `isTaken` function which takes in parameter `x`, `y` and which returns true if the stone with the position `x`, `y`, is taken there and false otherwise. To do this function we use a function `getStatus(x, y)` which returns:

- Status.BLACK: when the stone at position `x`, `y` is black
- Status.WHITE: when the stone at the position `x`, `y` is white
- Status.EMPTY: when there is no stone at position `x`, `y`
- Status.OUT: when the position `x`, `y` is out of the goban

Complete the `isTaken` function with your solution. You can add parameters to the method if needed. This one must respect the good practices of TypeScript. You can test your solution at any time with `npm test`. The tests are in the file goban.spec.ts.

Examples:

```text
# = black
o = white
. = empty
. #.
# o # <= o is taken because she has no freedom, she has no adjacent empty space
. #.
...
# o # <= o is not taken because she has a freedom over
. #.
o # <= o is taken because she has no freedom (the top and the left are out of the goban so they are not freedoms)
#.
oo.
## o <= the form # is taken because it has no freedom
o o #
.o.
oo.
##. <= the form # is not taken because it has a freedom in x = 2, y = 1 (0, 0 on the top left)
o o #
.o.
```
39 changes: 39 additions & 0 deletions goban.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { describe, it } from "node:test";
import assert from "node:assert/strict";

import { Goban } from "./goban";

describe("Goban", () => {
it("test_white_is_taken_when_surrounded_by_black", () => {
const goban = new Goban([".#.", "#o#", ".#."]);
assert.ok(goban.isTaken(1, 1));
});

it("test_white_is_not_taken_when_it_has_a_liberty", () => {
const goban = new Goban(["...", "#o#", ".#."]);
assert.equal(goban.isTaken(1, 1), false);
});

it("test_black_shape_is_taken_when_surrounded", () => {
const goban = new Goban(["oo.", "##o", "o#o", ".o."]);
assert.ok(goban.isTaken(0, 1));
assert.ok(goban.isTaken(1, 1));
assert.ok(goban.isTaken(1, 2));
});

it("test_black_shape_is_not_taken_when_it_has_a_liberty", () => {
const goban = new Goban(["oo.", "##.", "o#o", ".o."]);

assert.equal(goban.isTaken(0, 1), false);
assert.equal(goban.isTaken(1, 1), false);
assert.equal(goban.isTaken(1, 2), false);
});

it("test_square_shape_is_taken", () => {
const goban = new Goban(["oo.", "##o", "##o", "oo."]);
assert.ok(goban.isTaken(0, 1));
assert.ok(goban.isTaken(0, 2));
assert.ok(goban.isTaken(1, 1));
assert.ok(goban.isTaken(1, 2));
});
});
41 changes: 41 additions & 0 deletions goban.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
export enum Status {
WHITE = 1,
BLACK = 2,
EMPTY = 3,
OUT = 4,
}

export class Goban {
private board: string[];

constructor(board: string[]) {
this.board = board;
}

public print() {
console.log(this.board.join("\n"));
}

public getStatus(x: number, y: number): Status {
if (
!this.board ||
x < 0 ||
y < 0 ||
y >= this.board.length ||
x >= this.board[0].length
) {
return Status.OUT;
} else if (this.board[y][x] === ".") {
return Status.EMPTY;
} else if (this.board[y][x] === "o") {
return Status.WHITE;
} else if (this.board[y][x] === "#") {
return Status.BLACK;
}
throw new Error(`Unknown goban value ${this.board[y][x]}`);
}

public isTaken(x: number, y: number): boolean {
throw new Error("Not implemented");
}
}
Loading

0 comments on commit 75ee6c7

Please sign in to comment.