Skip to content

Commit

Permalink
checking out robot names
Browse files Browse the repository at this point in the history
  • Loading branch information
willshen8 committed Aug 15, 2021
1 parent c770d7d commit 23724fd
Show file tree
Hide file tree
Showing 10 changed files with 5,553 additions and 0 deletions.
10 changes: 10 additions & 0 deletions typescript/robot-name/.eslintignore
@@ -0,0 +1,10 @@
bin/*
dist/*
docs/*
node_modules/*
production_node_modules/*
test/fixtures/*
tmp/*

babel.config.js
jest.config.js
86 changes: 86 additions & 0 deletions typescript/robot-name/.eslintrc
@@ -0,0 +1,86 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json",
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 2018,
"sourceType": "module"
},
"env": {
"browser": true,
"es6": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
],
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"plugins": [
"@typescript-eslint"
],
"rules": {
// Code style not forced upon the student
"@typescript-eslint/array-type": "off",

// Prevent bugs
"@typescript-eslint/explicit-function-return-type": [
"warn", {
"allowExpressions": false,
"allowTypedFunctionExpressions": true,
"allowHigherOrderFunctions": true
}
],

// Code style not forced upon the student
"@typescript-eslint/explicit-member-accessibility": "off",

// Code style not forced upon the student
"@typescript-eslint/indent": "off",

"@typescript-eslint/no-inferrable-types": [
"error", {
"ignoreParameters": true
}
],

// Code style not forced upon the student
"@typescript-eslint/member-delimiter-style": "off",

// Code style not forced upon the student
"@typescript-eslint/no-non-null-assertion": "off",

// Only disallow readonly without an access modifier
"@typescript-eslint/no-parameter-properties": [
"warn", {
"allows": [
"private", "protected", "public",
"private readonly", "protected readonly", "public readonly"
]
}
],

// Covered by the tsc compiler (noUnusedLocals)
"@typescript-eslint/no-unused-vars": "off",

// Prevent bugs, not styling
"@typescript-eslint/no-use-before-define": [
"error", {
"functions": false,
"typedefs": false
}
],

// Always disable base-rule
"semi": "off",

// Code style not forced upon student
"@typescript-eslint/semi": "off"
}
}
53 changes: 53 additions & 0 deletions typescript/robot-name/README.md
@@ -0,0 +1,53 @@
# Robot Name

Manage robot factory settings.

When robots come off the factory floor, they have no name.

The first time you boot them up, a random name is generated in the format
of two uppercase letters followed by three digits, such as RX837 or BC811.

Every once in a while we need to reset a robot to its factory settings,
which means that their name gets wiped. The next time you ask, it will
respond with a new random name.

The names must be random: they should not follow a predictable sequence.
Random names means a risk of collisions. Your solution must ensure that
every existing robot has a unique name.

## Setup

Go through the setup instructions for TypeScript to install the necessary
dependencies:

[https://exercism.io/tracks/typescript/installation](https://exercism.io/tracks/typescript/installation)

## Requirements

Install assignment dependencies:

```bash
$ yarn install
```

## Making the test suite pass

Execute the tests with:

```bash
$ yarn test
```

In the test suites all tests but the first have been skipped.

Once you get a test passing, you can enable the next one by changing `xit` to
`it`.

## Source

A debugging session with Paul Blackwell at gSchool.

## Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have
completed the exercise.
20 changes: 20 additions & 0 deletions typescript/robot-name/babel.config.js
@@ -0,0 +1,20 @@
module.exports = {
presets: [
[
'@babel/preset-env',
{
targets: {
node: 'current',
},
useBuiltIns: 'entry',
corejs: 3,
},
],
'@babel/preset-typescript',
],
plugins: [
'@babel/proposal-class-properties',
'@babel/proposal-object-rest-spread',
'@babel/plugin-syntax-bigint',
],
}
19 changes: 19 additions & 0 deletions typescript/robot-name/jest.config.js
@@ -0,0 +1,19 @@
module.exports = {
verbose: true,
projects: ['<rootDir>'],
testMatch: [
'**/__tests__/**/*.[jt]s?(x)',
'**/test/**/*.[jt]s?(x)',
'**/?(*.)+(spec|test).[jt]s?(x)',
],
testPathIgnorePatterns: [
'/(?:production_)?node_modules/',
'.d.ts$',
'<rootDir>/test/fixtures',
'<rootDir>/test/helpers',
'__mocks__',
],
transform: {
'^.+\\.[jt]sx?$': 'babel-jest',
},
}
33 changes: 33 additions & 0 deletions typescript/robot-name/package.json
@@ -0,0 +1,33 @@
{
"name": "@exercism/typescript",
"description": "Exercism exercises in Typescript.",
"private": true,
"repository": {
"type": "git",
"url": "https://github.com/exercism/typescript"
},
"devDependencies": {
"@babel/core": "^7.12.10",
"@babel/plugin-proposal-class-properties": "^7.12.1",
"@babel/plugin-proposal-object-rest-spread": "^7.12.1",
"@babel/plugin-syntax-bigint": "^7.8.3",
"@babel/preset-env": "^7.12.11",
"@babel/preset-typescript": "^7.12.7",
"@types/jest": "^26.0.19",
"@types/node": "^14.14.14",
"@typescript-eslint/eslint-plugin": "^4.11.0",
"@typescript-eslint/parser": "^4.11.0",
"babel-jest": "^26.6.3",
"core-js": "^3.8.1",
"eslint": "^7.16.0",
"eslint-plugin-import": "^2.22.1",
"jest": "^26.6.3",
"typescript": "^4.1.3"
},
"scripts": {
"test": "yarn lint:types && jest --no-cache",
"lint": "yarn lint:types && yarn lint:ci",
"lint:types": "yarn tsc --noEmit -p .",
"lint:ci": "eslint . --ext .tsx,.ts"
}
}
106 changes: 106 additions & 0 deletions typescript/robot-name/robot-name.test.ts
@@ -0,0 +1,106 @@
import Robot from './robot-name'

const areSequential = (name1: string, name2: string): boolean => {
const alpha1 = name1.substr(0, 2)
const alpha2 = name2.substr(0, 2)
const num1 = +name1.substr(2, 3)
const num2 = +name2.substr(2, 3)

const numDiff = num2 - num1
const alphaDiff =
(alpha2.charCodeAt(0) - alpha1.charCodeAt(0)) * 26 +
(alpha2.charCodeAt(1) - alpha1.charCodeAt(1))

const totalDiff = alphaDiff * 1000 + numDiff

return Math.abs(totalDiff) <= 1
}

const NAME_RE = /^[A-Z]{2}\d{3}$/
const TOTAL_NUMBER_OF_NAMES =
26 * // A-Z
26 * // A-Z
10 * // 0-9
10 * // 0-9
10 // 0-9

describe('Robot', () => {
let robot: Robot

beforeEach(() => {
robot = new Robot()
})

afterEach(() => {
Robot.releaseNames()
})

it('has a name', () => {
expect(robot.name).toMatch(NAME_RE)
})

xit('name is the same each time', () => {
expect(robot.name).toEqual(robot.name)
})

xit('different robots have different names', () => {
const differentRobot = new Robot()
expect(differentRobot.name).not.toEqual(robot.name)
})

xit('is able to reset the name', () => {
const originalName = robot.name

robot.resetName()
const newName = robot.name

expect(newName).toMatch(NAME_RE)
expect(originalName).not.toEqual(newName)
})

xit('should set a unique name after reset', () => {
const NUMBER_OF_ROBOTS = 10000
const usedNames = new Set()

usedNames.add(robot.name)
for (let i = 0; i < NUMBER_OF_ROBOTS; i++) {
robot.resetName()
usedNames.add(robot.name)
}

expect(usedNames.size).toEqual(NUMBER_OF_ROBOTS + 1)
})

xit('new names should not be sequential', () => {
const name1 = robot.name
const name2 = new Robot().name
const name3 = new Robot().name
expect(areSequential(name1, name1)).toBe(true)
expect(areSequential(name1, name2)).toBe(false)
expect(areSequential(name2, name3)).toBe(false)
})

xit('names from reset should not be sequential', () => {
const name1 = robot.name
robot.resetName()
const name2 = robot.name
robot.resetName()
const name3 = robot.name
expect(areSequential(name1, name2)).toBe(false)
expect(areSequential(name2, name3)).toBe(false)
expect(areSequential(name3, name3)).toBe(true)
})

// This test is optional.
xit('all the names can be generated', () => {
const usedNames = new Set()
usedNames.add(robot.name)

for (let i = 0; i < TOTAL_NUMBER_OF_NAMES - 1; i += 1) {
const newRobot = new Robot()
usedNames.add(newRobot.name)
}

expect(usedNames.size).toEqual(TOTAL_NUMBER_OF_NAMES)
})
})
15 changes: 15 additions & 0 deletions typescript/robot-name/robot-name.ts
@@ -0,0 +1,15 @@
export default class Robot {
constructor() {}

public get name(): string {
throw new Error('Implement Robot#name')
}

public resetName(): void {
throw new Error('Implement Robot#resetName')
}

public static releaseNames(): void {
throw new Error('Implement Robot.releaseNames')
}
}

0 comments on commit 23724fd

Please sign in to comment.