From d9bee028735e78838eb2a32bbc16c72696d14fd0 Mon Sep 17 00:00:00 2001 From: jihwooon Date: Mon, 11 Dec 2023 22:18:49 +0900 Subject: [PATCH 01/21] Initial commit --- .eslintrc.js | 105 +++++++++++++++++++++++++-------------------------- 1 file changed, 51 insertions(+), 54 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 473d001..05d4847 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -3,69 +3,66 @@ module.exports = { node: true, jest: true, }, - parser: '@typescript-eslint/parser', + parser: "@typescript-eslint/parser", parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', + ecmaVersion: "latest", + sourceType: "module", }, - plugins: [ - '@typescript-eslint', - 'jest', - ], - extends: [ - 'airbnb', - 'plugin:@typescript-eslint/recommended', - 'plugin:jest/recommended', - ], + plugins: ["@typescript-eslint", "jest"], + extends: ["airbnb", "plugin:@typescript-eslint/recommended", "plugin:jest/recommended"], root: true, settings: { - 'import/resolver': { + "import/resolver": { node: { - extensions: ['.js', '.ts'], + extensions: [".js", ".ts"], }, }, }, rules: { - indent: ['error', 2], - 'no-trailing-spaces': 'error', - curly: 'error', - 'brace-style': 'error', - 'no-multi-spaces': 'error', - 'space-infix-ops': 'error', - 'space-unary-ops': 'error', - 'no-whitespace-before-property': 'error', - 'func-call-spacing': 'error', - 'space-before-blocks': 'error', - 'keyword-spacing': ['error', { before: true, after: true }], - 'comma-spacing': ['error', { before: false, after: true }], - 'comma-style': ['error', 'last'], - 'comma-dangle': ['error', 'always-multiline'], - 'space-in-parens': ['error', 'never'], - 'block-spacing': 'error', - 'array-bracket-spacing': ['error', 'never'], - 'object-curly-spacing': ['error', 'always'], - 'key-spacing': ['error', { mode: 'strict' }], - 'arrow-spacing': ['error', { before: true, after: true }], - 'class-methods-use-this': 'off', - 'no-shadow': 'off', - 'no-plusplus': 'off', - 'no-useless-constructor': 'off', - 'import/prefer-default-export': 'off', - 'consistent-return': 'off', - 'no-unreachable-loop': 'off', - 'no-empty-function': 'off', - 'max-classes-per-file': 'off', - 'no-cond-assign': 'off', - 'import/extensions': ['error', 'ignorePackages', { - js: 'never', - ts: 'never', - }], - '@typescript-eslint/no-unused-vars': 'off', - '@typescript-eslint/interface-name-prefix': 'off', - '@typescript-eslint/explicit-function-return-type': 'off', - '@typescript-eslint/explicit-module-boundary-types': 'off', - '@typescript-eslint/no-explicit-any': 'off', - 'no-param-reassign': 'off', + indent: ["error", 2], + "no-trailing-spaces": "error", + curly: "error", + "brace-style": "error", + "no-multi-spaces": "error", + "space-infix-ops": "error", + "space-unary-ops": "error", + "no-whitespace-before-property": "error", + "func-call-spacing": "error", + "space-before-blocks": "error", + "keyword-spacing": ["error", { before: true, after: true }], + "comma-spacing": ["error", { before: false, after: true }], + "comma-style": ["error", "last"], + "comma-dangle": ["error", "always-multiline"], + "space-in-parens": ["error", "never"], + "block-spacing": "error", + "array-bracket-spacing": ["error", "never"], + "object-curly-spacing": ["error", "always"], + "key-spacing": ["error", { mode: "strict" }], + "arrow-spacing": ["error", { before: true, after: true }], + "class-methods-use-this": "off", + "no-shadow": "off", + "no-plusplus": "off", + "no-useless-constructor": "off", + "import/prefer-default-export": "off", + "consistent-return": "off", + "no-unreachable-loop": "off", + "no-empty-function": "off", + "max-classes-per-file": "off", + "no-cond-assign": "off", + "import/extensions": [ + "error", + "ignorePackages", + { + js: "never", + ts: "never", + }, + ], + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/no-explicit-any": "off", + "no-param-reassign": "off", }, }; From bd6746ef120054f9257234ffa32519a2d3e2ae9f Mon Sep 17 00:00:00 2001 From: leehoosgg Date: Tue, 19 Dec 2023 15:25:02 +0900 Subject: [PATCH 02/21] =?UTF-8?q?update,=20draw=20=ED=95=A8=EC=88=98=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=84=B0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 메소드 추출을 통해 한 메소드가 한가지 일만 하도록 크기를 줄였음 추상화 수준을 맞춤으로써 가독성 향상 --- index.ts | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/index.ts b/index.ts index fb5294d..c1c3001 100644 --- a/index.ts +++ b/index.ts @@ -80,19 +80,30 @@ function moveVertical(dy: number) { } function update() { + handleInputs(); + updateMap(); +} + +function handleInputs() { while (inputs.length > 0) { const current = inputs.pop(); - if (current === Input.LEFT) { - moveHorizontal(-1); - } else if (current === Input.RIGHT) { - moveHorizontal(1); - } else if (current === Input.UP) { - moveVertical(-1); - } else if (current === Input.DOWN) { - moveVertical(1); - } + handleInput(current); + } +} + +function handleInput(input:Input) { + if (input === Input.LEFT) { + moveHorizontal(-1); + } else if (input === Input.RIGHT) { + moveHorizontal(1); + } else if (input === Input.UP) { + moveVertical(-1); + } else if (input === Input.DOWN) { + moveVertical(1); } +} +function updateMap() { for (let y = map.length - 1; y >= 0; y--) { for (let x = 0; x < map[y].length; x++) { if ((map[y][x] === Tile.STONE || map[y][x] === Tile.FALLING_STONE) @@ -113,12 +124,19 @@ function update() { } function draw() { - const canvas = document.getElementById('GameCanvas') as HTMLCanvasElement; - const g = canvas.getContext('2d'); + let g = createGraphics(); + drawMap(g); + drawPlayer(g); +} +function createGraphics() { + const canvas = document.getElementById('GameCanvas') as HTMLCanvasElement; + let g = canvas.getContext('2d'); g.clearRect(0, 0, canvas.width, canvas.height); + return g; +} - // Draw map +function drawMap(g:CanvasRenderingContext2D) { for (let y = 0; y < map.length; y++) { for (let x = 0; x < map[y].length; x++) { if (map[y][x] === Tile.FLUX) { @@ -140,8 +158,9 @@ function draw() { } } } +} - // Draw player +function drawPlayer(g:CanvasRenderingContext2D) { g.fillStyle = '#ff0000'; g.fillRect(playerx * TILE_SIZE, playery * TILE_SIZE, TILE_SIZE, TILE_SIZE); } From f964ca5989611fb34a0c3ef6eae2c2898a9b2d21 Mon Sep 17 00:00:00 2001 From: leehoosgg Date: Tue, 19 Dec 2023 18:01:20 +0900 Subject: [PATCH 03/21] =?UTF-8?q?ch01=20=EC=98=88=EC=A0=9C=20=EC=84=B8?= =?UTF-8?q?=EA=B0=80=EC=A7=80=20=ED=92=80=EC=9D=B4=EC=99=80=20eslint=20?= =?UTF-8?q?=EB=94=B0=EC=98=B4=ED=91=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ch01 sum 예제는 풀이하지 않음 --- .eslintrc.js | 96 +++++++++++++++++------------------ src/ch01/average.test.ts | 14 +++-- src/ch01/minimum.test.ts | 10 ++-- src/ch01/reportPrimes.test.ts | 8 +-- 4 files changed, 70 insertions(+), 58 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 05d4847..cbe4f1b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -3,66 +3,66 @@ module.exports = { node: true, jest: true, }, - parser: "@typescript-eslint/parser", + parser: '@typescript-eslint/parser', parserOptions: { - ecmaVersion: "latest", - sourceType: "module", + ecmaVersion: 'latest', + sourceType: 'module', }, - plugins: ["@typescript-eslint", "jest"], - extends: ["airbnb", "plugin:@typescript-eslint/recommended", "plugin:jest/recommended"], + plugins: ['@typescript-eslint', 'jest'], + extends: ['airbnb', 'plugin:@typescript-eslint/recommended', 'plugin:jest/recommended'], root: true, settings: { - "import/resolver": { + 'import/resolver': { node: { - extensions: [".js", ".ts"], + extensions: ['.js', '.ts'], }, }, }, rules: { - indent: ["error", 2], - "no-trailing-spaces": "error", - curly: "error", - "brace-style": "error", - "no-multi-spaces": "error", - "space-infix-ops": "error", - "space-unary-ops": "error", - "no-whitespace-before-property": "error", - "func-call-spacing": "error", - "space-before-blocks": "error", - "keyword-spacing": ["error", { before: true, after: true }], - "comma-spacing": ["error", { before: false, after: true }], - "comma-style": ["error", "last"], - "comma-dangle": ["error", "always-multiline"], - "space-in-parens": ["error", "never"], - "block-spacing": "error", - "array-bracket-spacing": ["error", "never"], - "object-curly-spacing": ["error", "always"], - "key-spacing": ["error", { mode: "strict" }], - "arrow-spacing": ["error", { before: true, after: true }], - "class-methods-use-this": "off", - "no-shadow": "off", - "no-plusplus": "off", - "no-useless-constructor": "off", - "import/prefer-default-export": "off", - "consistent-return": "off", - "no-unreachable-loop": "off", - "no-empty-function": "off", - "max-classes-per-file": "off", - "no-cond-assign": "off", - "import/extensions": [ - "error", - "ignorePackages", + indent: ['error', 2], + 'no-trailing-spaces': 'error', + curly: 'error', + 'brace-style': 'error', + 'no-multi-spaces': 'error', + 'space-infix-ops': 'error', + 'space-unary-ops': 'error', + 'no-whitespace-before-property': 'error', + 'func-call-spacing': 'error', + 'space-before-blocks': 'error', + 'keyword-spacing': ['error', { before: true, after: true }], + 'comma-spacing': ['error', { before: false, after: true }], + 'comma-style': ['error', 'last'], + 'comma-dangle': ['error', 'always-multiline'], + 'space-in-parens': ['error', 'never'], + 'block-spacing': 'error', + 'array-bracket-spacing': ['error', 'never'], + 'object-curly-spacing': ['error', 'always'], + 'key-spacing': ['error', { mode: 'strict' }], + 'arrow-spacing': ['error', { before: true, after: true }], + 'class-methods-use-this': 'off', + 'no-shadow': 'off', + 'no-plusplus': 'off', + 'no-useless-constructor': 'off', + 'import/prefer-default-export': 'off', + 'consistent-return': 'off', + 'no-unreachable-loop': 'off', + 'no-empty-function': 'off', + 'max-classes-per-file': 'off', + 'no-cond-assign': 'off', + 'import/extensions': [ + 'error', + 'ignorePackages', { - js: "never", - ts: "never", + js: 'never', + ts: 'never', }, ], - "@typescript-eslint/no-unused-vars": "off", - "@typescript-eslint/interface-name-prefix": "off", - "@typescript-eslint/explicit-function-return-type": "off", - "@typescript-eslint/explicit-module-boundary-types": "off", - "@typescript-eslint/no-explicit-any": "off", - "no-param-reassign": "off", + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/interface-name-prefix': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-explicit-any': 'off', + 'no-param-reassign': 'off', }, }; diff --git a/src/ch01/average.test.ts b/src/ch01/average.test.ts index 395dd8f..54a1b49 100644 --- a/src/ch01/average.test.ts +++ b/src/ch01/average.test.ts @@ -1,11 +1,17 @@ const average = (arr: number[]) => { - let answer = 0; + return sum(arr) / size(arr); +}; +const sum = (arr: number[]) => { + let accumulator = 0; for (let i = 0; i < arr.length; i++) { - answer += arr[i]; + accumulator += arr[i]; } + return accumulator; +} - return answer / arr.length; -}; +const size = (arr: number[]) => { + return arr.length; +} console.log(average([1, 2, 3, 4, 5])); // 결과값 : 3 diff --git a/src/ch01/minimum.test.ts b/src/ch01/minimum.test.ts index e64ab5f..a001845 100644 --- a/src/ch01/minimum.test.ts +++ b/src/ch01/minimum.test.ts @@ -2,13 +2,17 @@ const minimum = (arr: number[][]) => { let result = Number.POSITIVE_INFINITY; for (let x = 0; x < arr.length; x++) { for (let y = 0; y < arr[x].length; y++) { - if (result > arr[x][y]) { - result = arr[x][y]; - } + min(result, arr, x, y); } return result; } }; +const min = (result: number, arr: number[][], x: number, y: number) => { + if (result > arr[x][y]) { + result = arr[x][y]; + } +} + console.log(minimum([[1, 2, 4], [1, 2, 3]])); // 결과값 : 1 diff --git a/src/ch01/reportPrimes.test.ts b/src/ch01/reportPrimes.test.ts index f15a12a..28e3795 100644 --- a/src/ch01/reportPrimes.test.ts +++ b/src/ch01/reportPrimes.test.ts @@ -14,10 +14,12 @@ const isPrime = (num: number) => { const reportPrimes = (n: number) => { for (let i = 2; i < n; i++) { - if (isPrime(i)) { - console.log(`${i} is prime`); - } + if (isPrime(i)) reportIfPrime(i); } }; +const reportIfPrime = (i: number) => { + console.log(`${i} is prime`); +} + console.log(reportPrimes(5)); // 결과값 : 2,3 From d6e7cb128be52e214d96e71fc296ee697efecbc5 Mon Sep 17 00:00:00 2001 From: leehoosgg Date: Wed, 20 Dec 2023 17:09:02 +0900 Subject: [PATCH 04/21] =?UTF-8?q?sum.test.ts=20=ED=92=80=EC=9D=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit describe, context, it, expect, tobe 구조 적용 --- src/ch01/sum.test.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/ch01/sum.test.ts b/src/ch01/sum.test.ts index a1d041a..01f7db0 100644 --- a/src/ch01/sum.test.ts +++ b/src/ch01/sum.test.ts @@ -1,5 +1,12 @@ +const calculate = (a: number, b: number) => { + return a + b; +} + describe('sum', () => { - it('두 수가 주어지면 합의 결괏값을 리턴해야 한다.', () => { - expect(1 + 2).toBe(3); + context("두 수가 주어지면", () => { + it('합한 값을 리턴해야 한다.', () => { + expect(calculate(1, 2)).toBe(3); + expect(calculate(-3, 5)).toBe(2); + }); }); }); From 87b12624f3b030931861da379af6ba84ba58dbf0 Mon Sep 17 00:00:00 2001 From: leehoosgg Date: Thu, 21 Dec 2023 19:41:29 +0900 Subject: [PATCH 05/21] =?UTF-8?q?Input=20=EC=9D=B8=ED=84=B0=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4,=20=ED=81=B4=EB=9E=98=EC=8A=A4=EB=A1=9C?= =?UTF-8?q?=EC=9D=98=20=EC=BD=94=EB=93=9C=20=EC=9D=B4=EA=B4=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 간단한 if 문의 리팩토링을 수행 --- index.ts | 67 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/index.ts b/index.ts index c1c3001..27aaa4a 100644 --- a/index.ts +++ b/index.ts @@ -13,10 +13,51 @@ enum Tile { KEY2, LOCK2 } -enum Input { +enum RawInput { UP, DOWN, LEFT, RIGHT } +// Input Interface & Class +interface Input { + isRight(): boolean; + isLeft(): boolean; + isUp(): boolean; + isDown(): boolean; + handle(): void; +} + +class Right implements Input { + isRight() { return true; } + isLeft() { return false; } + isUp() { return false; } + isDown() { return false; } + handle() { moveHorizontal(1); } +} + +class Left implements Input { + isRight() { return false; } + isLeft() { return true; } + isUp() { return false; } + isDown() { return false; } + handle() { moveHorizontal(-1); } +} + +class Up implements Input { + isRight() { return false; } + isLeft() { return false; } + isUp() { return true; } + isDown() { return false; } + handle() { moveVertical(-1); } +} + +class Down implements Input { + isRight() { return false; } + isLeft() { return false; } + isUp() { return false; } + isDown() { return true; } + handle() { moveVertical(1); } +} + let playerx = 1; let playery = 1; const map: Tile[][] = [ @@ -86,20 +127,8 @@ function update() { function handleInputs() { while (inputs.length > 0) { - const current = inputs.pop(); - handleInput(current); - } -} - -function handleInput(input:Input) { - if (input === Input.LEFT) { - moveHorizontal(-1); - } else if (input === Input.RIGHT) { - moveHorizontal(1); - } else if (input === Input.UP) { - moveVertical(-1); - } else if (input === Input.DOWN) { - moveVertical(1); + const input = inputs.pop(); + input.handle(); } } @@ -184,8 +213,8 @@ const UP_KEY = 'ArrowUp'; const RIGHT_KEY = 'ArrowRight'; const DOWN_KEY = 'ArrowDown'; window.addEventListener('keydown', (e) => { - if (e.key === LEFT_KEY || e.key === 'a') inputs.push(Input.LEFT); - else if (e.key === UP_KEY || e.key === 'w') inputs.push(Input.UP); - else if (e.key === RIGHT_KEY || e.key === 'd') inputs.push(Input.RIGHT); - else if (e.key === DOWN_KEY || e.key === 's') inputs.push(Input.DOWN); + if (e.key === LEFT_KEY || e.key === 'a') inputs.push(new Left()); + else if (e.key === UP_KEY || e.key === 'w') inputs.push(new Up()); + else if (e.key === RIGHT_KEY || e.key === 'd') inputs.push(new Right()); + else if (e.key === DOWN_KEY || e.key === 's') inputs.push(new Down()); }); From f268a653f76eb2cf0cca9617e5b30abc3c4d000c Mon Sep 17 00:00:00 2001 From: leehoosgg Date: Thu, 21 Dec 2023 19:50:36 +0900 Subject: [PATCH 06/21] =?UTF-8?q?=EC=8B=A0=ED=98=B8=EB=93=B1=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20interface,=20class=20=EB=A1=9C=EC=9D=98=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=9D=B4=EA=B4=80=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 테스트를 위하여 원래 void 였던 updateCar() 함수를 임시로 boolean 으로 변경 --- src/ch02/trafficLight.test.ts | 53 ++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/src/ch02/trafficLight.test.ts b/src/ch02/trafficLight.test.ts index 0081e81..8aabab4 100644 --- a/src/ch02/trafficLight.test.ts +++ b/src/ch02/trafficLight.test.ts @@ -1,4 +1,8 @@ -import { TrafficLight } from './TrafficLight.enum'; +export enum RawTrafficLight { + RED, + YELLOW, + GREEN +} class Car { stop(): boolean { @@ -10,28 +14,49 @@ class Car { } } -const CYCLE = [TrafficLight.RED, TrafficLight.YELLOW, TrafficLight.GREEN]; +interface TrafficLight { + isRed(): boolean; + isYellow(): boolean; + isGreen(): boolean; + updateCar(): boolean; +} -const updateCarForLight = (current: TrafficLight) => { - const car = new Car(); +class Red implements TrafficLight { + isRed() { return true; } + isYellow() { return false; } + isGreen() { return false; } + updateCar() { return car.stop(); } +} - if (current === TrafficLight.RED) { - return car.stop(); - } - return car.drive(); -}; +class Yellow implements TrafficLight { + isRed() { return false; } + isYellow() { return true; } + isGreen() { return false; } + updateCar() { return car.drive(); } +} + +class Green implements TrafficLight { + isRed() { return false; } + isYellow() { return false; } + isGreen() { return true; } + updateCar() { return car.drive(); } +} + +const car = new Car(); +const CYCLE = [new Red(), new Green(), new Yellow()]; +const updateCar = (car: TrafficLight) => car.updateCar(); describe('trafficLight', () => { - context('updateCarForLight에 RED가 주어지면', () => { + context('updateCar() 에 Red 가 주어지면', () => { it('false를 리턴해야 한다.', () => { - expect(updateCarForLight(CYCLE[0])).toBe(false); + expect(updateCar(new Red())).toBe(false); }); }); - context('updateCarForLight에 YELLOW or GREEN가 주어지면', () => { + context('updateCar() 에 Yellow or Green 이 주어지면', () => { it('true를 리턴해야 한다.', () => { - expect(updateCarForLight(CYCLE[1])).toBe(true); - expect(updateCarForLight(CYCLE[2])).toBe(true); + expect(updateCar(new Green())).toBe(true); + expect(updateCar(new Yellow())).toBe(true); }); }); }); From 78ab05a2624dc7763ca473ca881ea6e4f9890e4f Mon Sep 17 00:00:00 2001 From: leehoosgg Date: Thu, 21 Dec 2023 20:34:02 +0900 Subject: [PATCH 07/21] =?UTF-8?q?=ED=83=80=EC=9D=BC=20Interface,=20Class?= =?UTF-8?q?=20=EB=A1=9C=EC=9D=98=20=EC=BD=94=EB=93=9C=20=EC=9D=B4=EA=B4=80?= =?UTF-8?q?=20=EB=B0=8F=20=EC=97=90=EB=9F=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit if 문 리팩토링시 map[y][x] 에서 메서드 인식 불가 map 생성 함수를 고쳐서 map[y][x] 가 클래스로 받아들여지도록 해야할듯 싶음 --- index.ts | 250 +++++++++++++++++++++++++++------- src/ch02/TrafficLight.enum.ts | 5 - 2 files changed, 199 insertions(+), 56 deletions(-) delete mode 100644 src/ch02/TrafficLight.enum.ts diff --git a/index.ts b/index.ts index 27aaa4a..e188893 100644 --- a/index.ts +++ b/index.ts @@ -2,7 +2,7 @@ const TILE_SIZE = 30; const FPS = 30; const SLEEP = 1000 / FPS; -enum Tile { +enum RawTile { AIR, FLUX, UNBREAKABLE, @@ -13,6 +13,150 @@ enum Tile { KEY2, LOCK2 } +// Tile Interface & Class +interface Tile { + isFlux(): boolean; + isUnbreakable(): boolean; + isStone(): boolean; + isFallingStone(): boolean; + isBox(): boolean; + isFallingBox(): boolean; + isKey1(): boolean; + isLock1(): boolean; + isKey2(): boolean; + isLock2(): boolean; +} + +class Flux implements Tile { + isFlux() { return true; } + isUnbreakable() { return false; } + isStone() { return false; } + isFallingStone() { return false; } + isBox() { return false; } + isFallingBox() { return false; } + isKey1() { return false; } + isLock1() { return false; } + isKey2() { return false; } + isLock2() { return false; } +} + +class Unbreakable implements Tile { + isFlux() { return false; } + isUnbreakable() { return true; } + isStone() { return false; } + isFallingStone() { return false; } + isBox() { return false; } + isFallingBox() { return false; } + isKey1() { return false; } + isLock1() { return false; } + isKey2() { return false; } + isLock2() { return false; } +} + +class Stone implements Tile { + isFlux() { return false; } + isUnbreakable() { return false; } + isStone() { return true; } + isFallingStone() { return false; } + isBox() { return false; } + isFallingBox() { return false; } + isKey1() { return false; } + isLock1() { return false; } + isKey2() { return false; } + isLock2() { return false; } +} + +class FallingStone implements Tile { + isFlux() { return false; } + isUnbreakable() { return false; } + isStone() { return false; } + isFallingStone() { return true; } + isBox() { return false; } + isFallingBox() { return false; } + isKey1() { return false; } + isLock1() { return false; } + isKey2() { return false; } + isLock2() { return false; } +} + +class Box implements Tile { + isFlux() { return false; } + isUnbreakable() { return false; } + isStone() { return false; } + isFallingStone() { return false; } + isBox() { return true; } + isFallingBox() { return false; } + isKey1() { return false; } + isLock1() { return false; } + isKey2() { return false; } + isLock2() { return false; } +} + +class FallingBox implements Tile { + isFlux() { return false; } + isUnbreakable() { return false; } + isStone() { return false; } + isFallingStone() { return false; } + isBox() { return false; } + isFallingBox() { return true; } + isKey1() { return false; } + isLock1() { return false; } + isKey2() { return false; } + isLock2() { return false; } +} + +class Key1 implements Tile { + isFlux() { return false; } + isUnbreakable() { return false; } + isStone() { return false; } + isFallingStone() { return false; } + isBox() { return false; } + isFallingBox() { return false; } + isKey1() { return true; } + isLock1() { return false; } + isKey2() { return false; } + isLock2() { return false; } +} + +class Lock1 implements Tile { + isFlux() { return false; } + isUnbreakable() { return false; } + isStone() { return false; } + isFallingStone() { return false; } + isBox() { return false; } + isFallingBox() { return false; } + isKey1() { return false; } + isLock1() { return true; } + isKey2() { return false; } + isLock2() { return false; } +} + +class Key2 implements Tile { + isFlux() { return false; } + isUnbreakable() { return false; } + isStone() { return false; } + isFallingStone() { return false; } + isBox() { return false; } + isFallingBox() { return false; } + isKey1() { return false; } + isLock1() { return false; } + isKey2() { return true; } + isLock2() { return false; } +} + +class Lock2 implements Tile { + isFlux() { return false; } + isUnbreakable() { return false; } + isStone() { return false; } + isFallingStone() { return false; } + isBox() { return false; } + isFallingBox() { return false; } + isKey1() { return false; } + isLock1() { return false; } + isKey2() { return false; } + isLock2() { return true; } +} + enum RawInput { UP, DOWN, LEFT, RIGHT } @@ -60,7 +204,7 @@ class Down implements Input { let playerx = 1; let playery = 1; -const map: Tile[][] = [ +const map: RawTile[][] = [ [2, 2, 2, 2, 2, 2, 2, 2], [2, 3, 0, 1, 1, 2, 0, 2], [2, 4, 2, 6, 1, 2, 0, 2], @@ -71,51 +215,51 @@ const map: Tile[][] = [ const inputs: Input[] = []; -function remove(tile: Tile) { +function remove(tile: RawTile) { for (let y = 0; y < map.length; y++) { for (let x = 0; x < map[y].length; x++) { if (map[y][x] === tile) { - map[y][x] = Tile.AIR; + map[y][x] = RawTile.AIR; } } } } function moveToTile(newx: number, newy: number) { - map[playery][playerx] = Tile.AIR; - map[newy][newx] = Tile.PLAYER; + map[playery][playerx] = RawTile.AIR; + map[newy][newx] = RawTile.PLAYER; playerx = newx; playery = newy; } function moveHorizontal(dx: number) { - if (map[playery][playerx + dx] === Tile.FLUX - || map[playery][playerx + dx] === Tile.AIR) { + if (map[playery][playerx + dx] === RawTile.FLUX + || map[playery][playerx + dx] === RawTile.AIR) { moveToTile(playerx + dx, playery); - } else if ((map[playery][playerx + dx] === Tile.STONE - || map[playery][playerx + dx] === Tile.BOX) - && map[playery][playerx + dx + dx] === Tile.AIR - && map[playery + 1][playerx + dx] !== Tile.AIR) { + } else if ((map[playery][playerx + dx] === RawTile.STONE + || map[playery][playerx + dx] === RawTile.BOX) + && map[playery][playerx + dx + dx] === RawTile.AIR + && map[playery + 1][playerx + dx] !== RawTile.AIR) { map[playery][playerx + dx + dx] = map[playery][playerx + dx]; moveToTile(playerx + dx, playery); - } else if (map[playery][playerx + dx] === Tile.KEY1) { - remove(Tile.LOCK1); + } else if (map[playery][playerx + dx] === RawTile.KEY1) { + remove(RawTile.LOCK1); moveToTile(playerx + dx, playery); - } else if (map[playery][playerx + dx] === Tile.KEY2) { - remove(Tile.LOCK2); + } else if (map[playery][playerx + dx] === RawTile.KEY2) { + remove(RawTile.LOCK2); moveToTile(playerx + dx, playery); } } function moveVertical(dy: number) { - if (map[playery + dy][playerx] === Tile.FLUX - || map[playery + dy][playerx] === Tile.AIR) { + if (map[playery + dy][playerx] === RawTile.FLUX + || map[playery + dy][playerx] === RawTile.AIR) { moveToTile(playerx, playery + dy); - } else if (map[playery + dy][playerx] === Tile.KEY1) { - remove(Tile.LOCK1); + } else if (map[playery + dy][playerx] === RawTile.KEY1) { + remove(RawTile.LOCK1); moveToTile(playerx, playery + dy); - } else if (map[playery + dy][playerx] === Tile.KEY2) { - remove(Tile.LOCK2); + } else if (map[playery + dy][playerx] === RawTile.KEY2) { + remove(RawTile.LOCK2); moveToTile(playerx, playery + dy); } } @@ -135,18 +279,18 @@ function handleInputs() { function updateMap() { for (let y = map.length - 1; y >= 0; y--) { for (let x = 0; x < map[y].length; x++) { - if ((map[y][x] === Tile.STONE || map[y][x] === Tile.FALLING_STONE) - && map[y + 1][x] === Tile.AIR) { - map[y + 1][x] = Tile.FALLING_STONE; - map[y][x] = Tile.AIR; - } else if ((map[y][x] === Tile.BOX || map[y][x] === Tile.FALLING_BOX) - && map[y + 1][x] === Tile.AIR) { - map[y + 1][x] = Tile.FALLING_BOX; - map[y][x] = Tile.AIR; - } else if (map[y][x] === Tile.FALLING_STONE) { - map[y][x] = Tile.STONE; - } else if (map[y][x] === Tile.FALLING_BOX) { - map[y][x] = Tile.BOX; + if ((map[y][x] === RawTile.STONE || map[y][x] === RawTile.FALLING_STONE) + && map[y + 1][x] === RawTile.AIR) { + map[y + 1][x] = RawTile.FALLING_STONE; + map[y][x] = RawTile.AIR; + } else if ((map[y][x] === RawTile.BOX || map[y][x] === RawTile.FALLING_BOX) + && map[y + 1][x] === RawTile.AIR) { + map[y + 1][x] = RawTile.FALLING_BOX; + map[y][x] = RawTile.AIR; + } else if (map[y][x] === RawTile.FALLING_STONE) { + map[y][x] = RawTile.STONE; + } else if (map[y][x] === RawTile.FALLING_BOX) { + map[y][x] = RawTile.BOX; } } } @@ -168,27 +312,31 @@ function createGraphics() { function drawMap(g:CanvasRenderingContext2D) { for (let y = 0; y < map.length; y++) { for (let x = 0; x < map[y].length; x++) { - if (map[y][x] === Tile.FLUX) { - g.fillStyle = '#ccffcc'; - } else if (map[y][x] === Tile.UNBREAKABLE) { - g.fillStyle = '#999999'; - } else if (map[y][x] === Tile.STONE || map[y][x] === Tile.FALLING_STONE) { - g.fillStyle = '#0000cc'; - } else if (map[y][x] === Tile.BOX || map[y][x] === Tile.FALLING_BOX) { - g.fillStyle = '#8b4513'; - } else if (map[y][x] === Tile.KEY1 || map[y][x] === Tile.LOCK1) { - g.fillStyle = '#ffcc00'; - } else if (map[y][x] === Tile.KEY2 || map[y][x] === Tile.LOCK2) { - g.fillStyle = '#00ccff'; - } - - if (map[y][x] !== Tile.AIR && map[y][x] !== Tile.PLAYER) { - g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); - } + colorOfTile(g, x, y); } } } +function colorOfTile(g: CanvasRenderingContext2D, x: number, y: number) { + if (map[y][x]) { + g.fillStyle = '#ccffcc'; + } else if (map[y][x] === RawTile.UNBREAKABLE) { + g.fillStyle = '#999999'; + } else if (map[y][x] === RawTile.STONE || map[y][x] === RawTile.FALLING_STONE) { + g.fillStyle = '#0000cc'; + } else if (map[y][x] === RawTile.BOX || map[y][x] === RawTile.FALLING_BOX) { + g.fillStyle = '#8b4513'; + } else if (map[y][x] === RawTile.KEY1 || map[y][x] === RawTile.LOCK1) { + g.fillStyle = '#ffcc00'; + } else if (map[y][x] === RawTile.KEY2 || map[y][x] === RawTile.LOCK2) { + g.fillStyle = '#00ccff'; + } + + if (map[y][x] !== RawTile.AIR && map[y][x] !== RawTile.PLAYER) { + g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); + } +} + function drawPlayer(g:CanvasRenderingContext2D) { g.fillStyle = '#ff0000'; g.fillRect(playerx * TILE_SIZE, playery * TILE_SIZE, TILE_SIZE, TILE_SIZE); diff --git a/src/ch02/TrafficLight.enum.ts b/src/ch02/TrafficLight.enum.ts deleted file mode 100644 index 240d46c..0000000 --- a/src/ch02/TrafficLight.enum.ts +++ /dev/null @@ -1,5 +0,0 @@ -export enum TrafficLight { - RED, - YELLOW, - GREEN -} From 21c83cb6768ba8cfc45c4944b0569b7bf48b4ec2 Mon Sep 17 00:00:00 2001 From: leehoosgg Date: Thu, 21 Dec 2023 21:29:47 +0900 Subject: [PATCH 08/21] =?UTF-8?q?Map=20=EB=B3=80=EC=88=98,=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=ED=95=A8=EC=88=98=EB=A1=9C=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0=20=EB=B0=8F=20PR=20=EC=A0=9C=EC=96=B8=20?= =?UTF-8?q?=ED=86=A0=EB=8C=80=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit remove 함수 수정 전까지의 작업 완료 --- .eslintrc.js | 23 ++-- index.ts | 221 +++++++++++++++++++++++----------- src/ch01/reportPrimes.test.ts | 4 +- src/ch02/trafficLight.test.ts | 10 +- 4 files changed, 175 insertions(+), 83 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index cbe4f1b..473d001 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -8,8 +8,15 @@ module.exports = { ecmaVersion: 'latest', sourceType: 'module', }, - plugins: ['@typescript-eslint', 'jest'], - extends: ['airbnb', 'plugin:@typescript-eslint/recommended', 'plugin:jest/recommended'], + plugins: [ + '@typescript-eslint', + 'jest', + ], + extends: [ + 'airbnb', + 'plugin:@typescript-eslint/recommended', + 'plugin:jest/recommended', + ], root: true, settings: { @@ -50,14 +57,10 @@ module.exports = { 'no-empty-function': 'off', 'max-classes-per-file': 'off', 'no-cond-assign': 'off', - 'import/extensions': [ - 'error', - 'ignorePackages', - { - js: 'never', - ts: 'never', - }, - ], + 'import/extensions': ['error', 'ignorePackages', { + js: 'never', + ts: 'never', + }], '@typescript-eslint/no-unused-vars': 'off', '@typescript-eslint/interface-name-prefix': 'off', '@typescript-eslint/explicit-function-return-type': 'off', diff --git a/index.ts b/index.ts index e188893..97dd00e 100644 --- a/index.ts +++ b/index.ts @@ -2,6 +2,34 @@ const TILE_SIZE = 30; const FPS = 30; const SLEEP = 1000 / FPS; +window.onload = () => { + transformMap(); + gameLoop(); +}; + +function gameLoop() { + const before = Date.now(); + update(); + draw(); + const after = Date.now(); + const frameTime = after - before; + const sleep = SLEEP - frameTime; + setTimeout(() => gameLoop(), sleep); +} + +const LEFT_KEY = 'ArrowLeft'; +const UP_KEY = 'ArrowUp'; +const RIGHT_KEY = 'ArrowRight'; +const DOWN_KEY = 'ArrowDown'; + +window.addEventListener('keydown', (e) => { + if (e.key === LEFT_KEY || e.key === 'a') inputs.push(new Left()); + else if (e.key === UP_KEY || e.key === 'w') inputs.push(new Up()); + else if (e.key === RIGHT_KEY || e.key === 'd') inputs.push(new Right()); + else if (e.key === DOWN_KEY || e.key === 's') inputs.push(new Down()); +}); + +// Tile Enum & Interface & Class enum RawTile { AIR, FLUX, @@ -13,10 +41,11 @@ enum RawTile { KEY2, LOCK2 } -// Tile Interface & Class interface Tile { + isAir(): boolean; isFlux(): boolean; isUnbreakable(): boolean; + isPlayer(): boolean; isStone(): boolean; isFallingStone(): boolean; isBox(): boolean; @@ -27,9 +56,26 @@ interface Tile { isLock2(): boolean; } +class Air implements Tile { + isAir() { return true; } + isFlux() { return false; } + isUnbreakable() { return false; } + isPlayer() { return false; } + isStone() { return false; } + isFallingStone() { return false; } + isBox() { return false; } + isFallingBox() { return false; } + isKey1() { return false; } + isLock1() { return false; } + isKey2() { return false; } + isLock2() { return false; } +} + class Flux implements Tile { + isAir() { return false; } isFlux() { return true; } isUnbreakable() { return false; } + isPlayer() { return false; } isStone() { return false; } isFallingStone() { return false; } isBox() { return false; } @@ -41,8 +87,25 @@ class Flux implements Tile { } class Unbreakable implements Tile { + isAir() { return false; } isFlux() { return false; } isUnbreakable() { return true; } + isPlayer() { return false; } + isStone() { return false; } + isFallingStone() { return false; } + isBox() { return false; } + isFallingBox() { return false; } + isKey1() { return false; } + isLock1() { return false; } + isKey2() { return false; } + isLock2() { return false; } +} + +class Player implements Tile { + isAir() { return false; } + isFlux() { return false; } + isUnbreakable() { return false; } + isPlayer() { return true; } isStone() { return false; } isFallingStone() { return false; } isBox() { return false; } @@ -54,8 +117,10 @@ class Unbreakable implements Tile { } class Stone implements Tile { + isAir() { return false; } isFlux() { return false; } isUnbreakable() { return false; } + isPlayer() { return false; } isStone() { return true; } isFallingStone() { return false; } isBox() { return false; } @@ -67,8 +132,10 @@ class Stone implements Tile { } class FallingStone implements Tile { + isAir() { return false; } isFlux() { return false; } isUnbreakable() { return false; } + isPlayer() { return false; } isStone() { return false; } isFallingStone() { return true; } isBox() { return false; } @@ -80,8 +147,10 @@ class FallingStone implements Tile { } class Box implements Tile { + isAir() { return false; } isFlux() { return false; } isUnbreakable() { return false; } + isPlayer() { return false; } isStone() { return false; } isFallingStone() { return false; } isBox() { return true; } @@ -93,8 +162,10 @@ class Box implements Tile { } class FallingBox implements Tile { + isAir() { return false; } isFlux() { return false; } isUnbreakable() { return false; } + isPlayer() { return false; } isStone() { return false; } isFallingStone() { return false; } isBox() { return false; } @@ -106,8 +177,10 @@ class FallingBox implements Tile { } class Key1 implements Tile { + isAir() { return false; } isFlux() { return false; } isUnbreakable() { return false; } + isPlayer() { return false; } isStone() { return false; } isFallingStone() { return false; } isBox() { return false; } @@ -119,8 +192,10 @@ class Key1 implements Tile { } class Lock1 implements Tile { + isAir() { return false; } isFlux() { return false; } isUnbreakable() { return false; } + isPlayer() { return false; } isStone() { return false; } isFallingStone() { return false; } isBox() { return false; } @@ -132,8 +207,10 @@ class Lock1 implements Tile { } class Key2 implements Tile { + isAir() { return false; } isFlux() { return false; } isUnbreakable() { return false; } + isPlayer() { return false; } isStone() { return false; } isFallingStone() { return false; } isBox() { return false; } @@ -145,8 +222,10 @@ class Key2 implements Tile { } class Lock2 implements Tile { + isAir() { return false; } isFlux() { return false; } isUnbreakable() { return false; } + isPlayer() { return false; } isStone() { return false; } isFallingStone() { return false; } isBox() { return false; } @@ -157,11 +236,11 @@ class Lock2 implements Tile { isLock2() { return true; } } +// Input Enum & Interface & Class enum RawInput { UP, DOWN, LEFT, RIGHT } -// Input Interface & Class interface Input { isRight(): boolean; isLeft(): boolean; @@ -204,7 +283,7 @@ class Down implements Input { let playerx = 1; let playery = 1; -const map: RawTile[][] = [ +const rawMap: RawTile[][] = [ [2, 2, 2, 2, 2, 2, 2, 2], [2, 3, 0, 1, 1, 2, 0, 2], [2, 4, 2, 6, 1, 2, 0, 2], @@ -212,53 +291,86 @@ const map: RawTile[][] = [ [2, 4, 1, 1, 1, 9, 0, 2], [2, 2, 2, 2, 2, 2, 2, 2], ]; +let map: Tile[][]; + +function transformMap() { + map = new Array(rawMap.length); + for (let y = 0; y < rawMap.length; y++) { + map[y] = new Array(rawMap[y].length); + for (let x = 0; x < rawMap[y].length; x++) { + map[y][x] = transformTile(rawMap[y][x]); + } + } +} + +function assertExhausted(x: never): never { + throw new Error("Unexpected Object: " + x); +} + +function transformTile(tile: RawTile) { + switch(tile) { + case RawTile.AIR: return new Air(); + case RawTile.BOX: return new Box(); + case RawTile.FALLING_BOX: return new FallingBox(); + case RawTile.FALLING_STONE: return new FallingStone(); + case RawTile.FLUX: return new Flux(); + case RawTile.KEY1: return new Key1(); + case RawTile.KEY2: return new Key2(); + case RawTile.LOCK1: return new Lock1(); + case RawTile.LOCK2: return new Lock2(); + case RawTile.PLAYER: return new Player(); + case RawTile.STONE: return new Stone(); + case RawTile.UNBREAKABLE: return new Unbreakable(); + default: assertExhausted(tile); + } +} const inputs: Input[] = []; function remove(tile: RawTile) { for (let y = 0; y < map.length; y++) { for (let x = 0; x < map[y].length; x++) { - if (map[y][x] === tile) { - map[y][x] = RawTile.AIR; - } + // if (map[y][x] === tile) { + // map[y][x] = new Air(); + // } } } } function moveToTile(newx: number, newy: number) { - map[playery][playerx] = RawTile.AIR; - map[newy][newx] = RawTile.PLAYER; + map[playery][playerx] = new Air(); + map[newy][newx] = new Player(); playerx = newx; playery = newy; } function moveHorizontal(dx: number) { - if (map[playery][playerx + dx] === RawTile.FLUX - || map[playery][playerx + dx] === RawTile.AIR) { + if (map[playery][playerx + dx].isFlux() + || map[playery][playerx + dx].isAir()) { moveToTile(playerx + dx, playery); - } else if ((map[playery][playerx + dx] === RawTile.STONE - || map[playery][playerx + dx] === RawTile.BOX) - && map[playery][playerx + dx + dx] === RawTile.AIR - && map[playery + 1][playerx + dx] !== RawTile.AIR) { + } else if ((map[playery][playerx + dx].isStone() + || map[playery][playerx + dx].isBox()) + && map[playery][playerx + dx + dx].isAir() + && !map[playery + 1][playerx + dx].isAir()) { map[playery][playerx + dx + dx] = map[playery][playerx + dx]; moveToTile(playerx + dx, playery); - } else if (map[playery][playerx + dx] === RawTile.KEY1) { + } else if (map[playery][playerx + dx].isKey1()) { remove(RawTile.LOCK1); moveToTile(playerx + dx, playery); - } else if (map[playery][playerx + dx] === RawTile.KEY2) { + } else if (map[playery][playerx + dx].isKey2()) { remove(RawTile.LOCK2); moveToTile(playerx + dx, playery); } } function moveVertical(dy: number) { - if (map[playery + dy][playerx] === RawTile.FLUX - || map[playery + dy][playerx] === RawTile.AIR) { + if (map[playery + dy][playerx].isFlux() + || map[playery + dy][playerx].isAir()) { moveToTile(playerx, playery + dy); - } else if (map[playery + dy][playerx] === RawTile.KEY1) { + } else if (map[playery + dy][playerx].isKey1()) { remove(RawTile.LOCK1); moveToTile(playerx, playery + dy); - } else if (map[playery + dy][playerx] === RawTile.KEY2) { + } else if (map[playery + dy][playerx].isKey2()) { remove(RawTile.LOCK2); moveToTile(playerx, playery + dy); } @@ -279,18 +391,18 @@ function handleInputs() { function updateMap() { for (let y = map.length - 1; y >= 0; y--) { for (let x = 0; x < map[y].length; x++) { - if ((map[y][x] === RawTile.STONE || map[y][x] === RawTile.FALLING_STONE) - && map[y + 1][x] === RawTile.AIR) { - map[y + 1][x] = RawTile.FALLING_STONE; - map[y][x] = RawTile.AIR; - } else if ((map[y][x] === RawTile.BOX || map[y][x] === RawTile.FALLING_BOX) - && map[y + 1][x] === RawTile.AIR) { - map[y + 1][x] = RawTile.FALLING_BOX; - map[y][x] = RawTile.AIR; - } else if (map[y][x] === RawTile.FALLING_STONE) { - map[y][x] = RawTile.STONE; - } else if (map[y][x] === RawTile.FALLING_BOX) { - map[y][x] = RawTile.BOX; + if ((map[y][x].isStone() || map[y][x].isFallingStone()) + && map[y + 1][x].isAir()) { + map[y + 1][x] = new FallingStone(); + map[y][x] = new Air(); + } else if ((map[y][x].isBox() || map[y][x].isFallingBox()) + && map[y + 1][x].isAir()) { + map[y + 1][x] = new FallingBox(); + map[y][x] = new Air(); + } else if (map[y][x].isFallingStone()) { + map[y][x] = new Stone(); + } else if (map[y][x].isFallingBox()) { + map[y][x] = new Box(); } } } @@ -313,56 +425,31 @@ function drawMap(g:CanvasRenderingContext2D) { for (let y = 0; y < map.length; y++) { for (let x = 0; x < map[y].length; x++) { colorOfTile(g, x, y); + + if (!map[y][x].isAir() && !map[y][x].isPlayer()) { + g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); + } } } } function colorOfTile(g: CanvasRenderingContext2D, x: number, y: number) { - if (map[y][x]) { + if (map[y][x].isFlux()) { g.fillStyle = '#ccffcc'; - } else if (map[y][x] === RawTile.UNBREAKABLE) { + } else if (map[y][x].isUnbreakable()) { g.fillStyle = '#999999'; - } else if (map[y][x] === RawTile.STONE || map[y][x] === RawTile.FALLING_STONE) { + } else if (map[y][x].isStone() || map[y][x].isFallingStone()) { g.fillStyle = '#0000cc'; - } else if (map[y][x] === RawTile.BOX || map[y][x] === RawTile.FALLING_BOX) { + } else if (map[y][x].isBox() || map[y][x].isFallingBox()) { g.fillStyle = '#8b4513'; - } else if (map[y][x] === RawTile.KEY1 || map[y][x] === RawTile.LOCK1) { + } else if (map[y][x].isKey1() || map[y][x].isLock1()) { g.fillStyle = '#ffcc00'; - } else if (map[y][x] === RawTile.KEY2 || map[y][x] === RawTile.LOCK2) { + } else if (map[y][x].isKey2() || map[y][x].isLock2()) { g.fillStyle = '#00ccff'; } - - if (map[y][x] !== RawTile.AIR && map[y][x] !== RawTile.PLAYER) { - g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); - } } function drawPlayer(g:CanvasRenderingContext2D) { g.fillStyle = '#ff0000'; g.fillRect(playerx * TILE_SIZE, playery * TILE_SIZE, TILE_SIZE, TILE_SIZE); } - -function gameLoop() { - const before = Date.now(); - update(); - draw(); - const after = Date.now(); - const frameTime = after - before; - const sleep = SLEEP - frameTime; - setTimeout(() => gameLoop(), sleep); -} - -window.onload = () => { - gameLoop(); -}; - -const LEFT_KEY = 'ArrowLeft'; -const UP_KEY = 'ArrowUp'; -const RIGHT_KEY = 'ArrowRight'; -const DOWN_KEY = 'ArrowDown'; -window.addEventListener('keydown', (e) => { - if (e.key === LEFT_KEY || e.key === 'a') inputs.push(new Left()); - else if (e.key === UP_KEY || e.key === 'w') inputs.push(new Up()); - else if (e.key === RIGHT_KEY || e.key === 'd') inputs.push(new Right()); - else if (e.key === DOWN_KEY || e.key === 's') inputs.push(new Down()); -}); diff --git a/src/ch01/reportPrimes.test.ts b/src/ch01/reportPrimes.test.ts index 28e3795..9d5abd6 100644 --- a/src/ch01/reportPrimes.test.ts +++ b/src/ch01/reportPrimes.test.ts @@ -18,8 +18,6 @@ const reportPrimes = (n: number) => { } }; -const reportIfPrime = (i: number) => { - console.log(`${i} is prime`); -} +const reportIfPrime = (i: number) => console.log(`${i} is prime`); console.log(reportPrimes(5)); // 결과값 : 2,3 diff --git a/src/ch02/trafficLight.test.ts b/src/ch02/trafficLight.test.ts index 8aabab4..4b7f7a4 100644 --- a/src/ch02/trafficLight.test.ts +++ b/src/ch02/trafficLight.test.ts @@ -14,10 +14,14 @@ class Car { } } +// interface TrafficLight { +// isRed(): boolean; +// isYellow(): boolean; +// isGreen(): boolean; +// updateCar(): boolean; +// } + interface TrafficLight { - isRed(): boolean; - isYellow(): boolean; - isGreen(): boolean; updateCar(): boolean; } From 207897b00d0e7b77ca0d543dc97cdd4de869e513 Mon Sep 17 00:00:00 2001 From: leehoosgg Date: Fri, 22 Dec 2023 12:28:00 +0900 Subject: [PATCH 09/21] =?UTF-8?q?Remove=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=A0=84=EB=AC=B8=ED=99=94,=20colorOfTile=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=EB=A1=9C=20=EC=BD=94=EB=93=9C=20=EC=9D=B4=EA=B4=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - --- index.ts | 53 ++++++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/index.ts b/index.ts index 97dd00e..cc1ee21 100644 --- a/index.ts +++ b/index.ts @@ -54,6 +54,7 @@ interface Tile { isLock1(): boolean; isKey2(): boolean; isLock2(): boolean; + color(g: CanvasRenderingContext2D): void; } class Air implements Tile { @@ -69,6 +70,7 @@ class Air implements Tile { isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } + color(g: CanvasRenderingContext2D) { } } class Flux implements Tile { @@ -84,6 +86,7 @@ class Flux implements Tile { isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } + color(g: CanvasRenderingContext2D) { g.fillStyle = '#999999'; } } class Unbreakable implements Tile { @@ -99,6 +102,7 @@ class Unbreakable implements Tile { isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } + color(g: CanvasRenderingContext2D) { g.fillStyle = '#ccffcc'; } } class Player implements Tile { @@ -114,6 +118,7 @@ class Player implements Tile { isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } + color(g: CanvasRenderingContext2D) { } } class Stone implements Tile { @@ -129,6 +134,7 @@ class Stone implements Tile { isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } + color(g: CanvasRenderingContext2D) { g.fillStyle = '#0000cc'; } } class FallingStone implements Tile { @@ -144,6 +150,7 @@ class FallingStone implements Tile { isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } + color(g: CanvasRenderingContext2D) { g.fillStyle = '#0000cc'; } } class Box implements Tile { @@ -159,6 +166,7 @@ class Box implements Tile { isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } + color(g: CanvasRenderingContext2D) { g.fillStyle = '#8b4513'; } } class FallingBox implements Tile { @@ -174,6 +182,7 @@ class FallingBox implements Tile { isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } + color(g: CanvasRenderingContext2D) { g.fillStyle = '#8b4513'; } } class Key1 implements Tile { @@ -189,6 +198,7 @@ class Key1 implements Tile { isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } + color(g: CanvasRenderingContext2D) { g.fillStyle = '#ffcc00'; } } class Lock1 implements Tile { @@ -204,6 +214,7 @@ class Lock1 implements Tile { isLock1() { return true; } isKey2() { return false; } isLock2() { return false; } + color(g: CanvasRenderingContext2D) { g.fillStyle = '#ffcc00'; } } class Key2 implements Tile { @@ -219,6 +230,7 @@ class Key2 implements Tile { isLock1() { return false; } isKey2() { return true; } isLock2() { return false; } + color(g: CanvasRenderingContext2D) { g.fillStyle = '#00ccff'; } } class Lock2 implements Tile { @@ -234,6 +246,7 @@ class Lock2 implements Tile { isLock1() { return false; } isKey2() { return false; } isLock2() { return true; } + color(g: CanvasRenderingContext2D) { g.fillStyle = '#00ccff'; } } // Input Enum & Interface & Class @@ -327,12 +340,18 @@ function transformTile(tile: RawTile) { const inputs: Input[] = []; -function remove(tile: RawTile) { +function removeLock1(tile: RawTile.LOCK1) { for (let y = 0; y < map.length; y++) { for (let x = 0; x < map[y].length; x++) { - // if (map[y][x] === tile) { - // map[y][x] = new Air(); - // } + if (map[y][x].isLock1) map[y][x] = new Air(); + } + } +} + +function removeLock2(tile: RawTile.LOCK2) { + for (let y = 0; y < map.length; y++) { + for (let x = 0; x < map[y].length; x++) { + if (map[y][x].isLock2) map[y][x] = new Air(); } } } @@ -355,10 +374,10 @@ function moveHorizontal(dx: number) { map[playery][playerx + dx + dx] = map[playery][playerx + dx]; moveToTile(playerx + dx, playery); } else if (map[playery][playerx + dx].isKey1()) { - remove(RawTile.LOCK1); + removeLock1(RawTile.LOCK1); moveToTile(playerx + dx, playery); } else if (map[playery][playerx + dx].isKey2()) { - remove(RawTile.LOCK2); + removeLock2(RawTile.LOCK2); moveToTile(playerx + dx, playery); } } @@ -368,10 +387,10 @@ function moveVertical(dy: number) { || map[playery + dy][playerx].isAir()) { moveToTile(playerx, playery + dy); } else if (map[playery + dy][playerx].isKey1()) { - remove(RawTile.LOCK1); + removeLock1(RawTile.LOCK1); moveToTile(playerx, playery + dy); } else if (map[playery + dy][playerx].isKey2()) { - remove(RawTile.LOCK2); + removeLock2(RawTile.LOCK2); moveToTile(playerx, playery + dy); } } @@ -424,7 +443,7 @@ function createGraphics() { function drawMap(g:CanvasRenderingContext2D) { for (let y = 0; y < map.length; y++) { for (let x = 0; x < map[y].length; x++) { - colorOfTile(g, x, y); + map[y][x].color(g) if (!map[y][x].isAir() && !map[y][x].isPlayer()) { g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); @@ -433,22 +452,6 @@ function drawMap(g:CanvasRenderingContext2D) { } } -function colorOfTile(g: CanvasRenderingContext2D, x: number, y: number) { - if (map[y][x].isFlux()) { - g.fillStyle = '#ccffcc'; - } else if (map[y][x].isUnbreakable()) { - g.fillStyle = '#999999'; - } else if (map[y][x].isStone() || map[y][x].isFallingStone()) { - g.fillStyle = '#0000cc'; - } else if (map[y][x].isBox() || map[y][x].isFallingBox()) { - g.fillStyle = '#8b4513'; - } else if (map[y][x].isKey1() || map[y][x].isLock1()) { - g.fillStyle = '#ffcc00'; - } else if (map[y][x].isKey2() || map[y][x].isLock2()) { - g.fillStyle = '#00ccff'; - } -} - function drawPlayer(g:CanvasRenderingContext2D) { g.fillStyle = '#ff0000'; g.fillRect(playerx * TILE_SIZE, playery * TILE_SIZE, TILE_SIZE, TILE_SIZE); From ab5ae4c905a3010314e54d3a911dfe18615f71be Mon Sep 17 00:00:00 2001 From: leehoosgg Date: Fri, 22 Dec 2023 12:38:41 +0900 Subject: [PATCH 10/21] =?UTF-8?q?if=20=EB=AC=B8=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EC=9D=B4=EA=B4=80=EC=9D=84=20=ED=86=B5=ED=95=B4=20color=20?= =?UTF-8?q?=EB=A5=BC=20draw=20=ED=95=A8=EC=88=98=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - --- index.ts | 62 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/index.ts b/index.ts index cc1ee21..2a38e67 100644 --- a/index.ts +++ b/index.ts @@ -54,7 +54,7 @@ interface Tile { isLock1(): boolean; isKey2(): boolean; isLock2(): boolean; - color(g: CanvasRenderingContext2D): void; + draw(g: CanvasRenderingContext2D, x: number, y: number): void; } class Air implements Tile { @@ -70,7 +70,7 @@ class Air implements Tile { isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } - color(g: CanvasRenderingContext2D) { } + draw(g: CanvasRenderingContext2D, x:number, y: number) { } } class Flux implements Tile { @@ -86,7 +86,10 @@ class Flux implements Tile { isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } - color(g: CanvasRenderingContext2D) { g.fillStyle = '#999999'; } + draw(g: CanvasRenderingContext2D, x: number, y: number) { + g.fillStyle = '#999999'; + g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); + } } class Unbreakable implements Tile { @@ -102,7 +105,10 @@ class Unbreakable implements Tile { isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } - color(g: CanvasRenderingContext2D) { g.fillStyle = '#ccffcc'; } + draw(g: CanvasRenderingContext2D, x: number, y: number) { + g.fillStyle = '#ccffcc'; + g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); + } } class Player implements Tile { @@ -118,7 +124,7 @@ class Player implements Tile { isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } - color(g: CanvasRenderingContext2D) { } + draw(g: CanvasRenderingContext2D, x: number, y: number) { } } class Stone implements Tile { @@ -134,7 +140,10 @@ class Stone implements Tile { isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } - color(g: CanvasRenderingContext2D) { g.fillStyle = '#0000cc'; } + draw(g: CanvasRenderingContext2D, x: number, y: number) { + g.fillStyle = '#0000cc'; + g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); + } } class FallingStone implements Tile { @@ -150,7 +159,10 @@ class FallingStone implements Tile { isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } - color(g: CanvasRenderingContext2D) { g.fillStyle = '#0000cc'; } + draw(g: CanvasRenderingContext2D, x: number, y: number) { + g.fillStyle = '#0000cc'; + g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); + } } class Box implements Tile { @@ -166,7 +178,10 @@ class Box implements Tile { isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } - color(g: CanvasRenderingContext2D) { g.fillStyle = '#8b4513'; } + draw(g: CanvasRenderingContext2D, x: number, y: number) { + g.fillStyle = '#8b4513'; + g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); + } } class FallingBox implements Tile { @@ -182,7 +197,10 @@ class FallingBox implements Tile { isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } - color(g: CanvasRenderingContext2D) { g.fillStyle = '#8b4513'; } + draw(g: CanvasRenderingContext2D, x: number, y: number) { + g.fillStyle = '#8b4513'; + g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); + } } class Key1 implements Tile { @@ -198,7 +216,10 @@ class Key1 implements Tile { isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } - color(g: CanvasRenderingContext2D) { g.fillStyle = '#ffcc00'; } + draw(g: CanvasRenderingContext2D, x: number, y: number) { + g.fillStyle = '#ffcc00'; + g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); + } } class Lock1 implements Tile { @@ -214,7 +235,10 @@ class Lock1 implements Tile { isLock1() { return true; } isKey2() { return false; } isLock2() { return false; } - color(g: CanvasRenderingContext2D) { g.fillStyle = '#ffcc00'; } + draw(g: CanvasRenderingContext2D, x: number, y: number) { + g.fillStyle = '#ffcc00'; + g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); + } } class Key2 implements Tile { @@ -230,7 +254,10 @@ class Key2 implements Tile { isLock1() { return false; } isKey2() { return true; } isLock2() { return false; } - color(g: CanvasRenderingContext2D) { g.fillStyle = '#00ccff'; } + draw(g: CanvasRenderingContext2D, x: number, y: number) { + g.fillStyle = '#00ccff'; + g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); + } } class Lock2 implements Tile { @@ -246,7 +273,10 @@ class Lock2 implements Tile { isLock1() { return false; } isKey2() { return false; } isLock2() { return true; } - color(g: CanvasRenderingContext2D) { g.fillStyle = '#00ccff'; } + draw(g: CanvasRenderingContext2D, x: number, y: number) { + g.fillStyle = '#00ccff'; + g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); + } } // Input Enum & Interface & Class @@ -443,11 +473,7 @@ function createGraphics() { function drawMap(g:CanvasRenderingContext2D) { for (let y = 0; y < map.length; y++) { for (let x = 0; x < map[y].length; x++) { - map[y][x].color(g) - - if (!map[y][x].isAir() && !map[y][x].isPlayer()) { - g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); - } + map[y][x].draw(g, x, y); } } } From f223e7b6abcacffe7d24e885185f52be25cbd609 Mon Sep 17 00:00:00 2001 From: leehoosgg Date: Fri, 22 Dec 2023 13:03:46 +0900 Subject: [PATCH 11/21] =?UTF-8?q?moveHorizontal,=20Vertical=20=EC=9D=B8?= =?UTF-8?q?=EB=9D=BC=EC=9D=B8=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 클래스로의 코드 이관을 통한 if 문, 함수 리팩터링 --- index.ts | 108 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 76 insertions(+), 32 deletions(-) diff --git a/index.ts b/index.ts index 2a38e67..c28221c 100644 --- a/index.ts +++ b/index.ts @@ -55,6 +55,10 @@ interface Tile { isKey2(): boolean; isLock2(): boolean; draw(g: CanvasRenderingContext2D, x: number, y: number): void; + isEdible(): boolean; + isPushable(): boolean; + moveHorizontal(dx: number): void; + moveVertical(dx: number): void; } class Air implements Tile { @@ -71,6 +75,10 @@ class Air implements Tile { isKey2() { return false; } isLock2() { return false; } draw(g: CanvasRenderingContext2D, x:number, y: number) { } + isEdible() { return true; } + isPushable() { return false; } + moveHorizontal(dx: number) { moveToTile(playerx + dx, playery); } + moveVertical(dx: number) { moveToTile(playerx, playery + dy); } } class Flux implements Tile { @@ -90,6 +98,10 @@ class Flux implements Tile { g.fillStyle = '#999999'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } + isEdible() { return true; } + isPushable() { return false; } + moveHorizontal(dx: number) { moveToTile(playerx + dx, playery); } + moveVertical(dx: number) { moveToTile(playerx, playery + dy); } } class Unbreakable implements Tile { @@ -109,6 +121,10 @@ class Unbreakable implements Tile { g.fillStyle = '#ccffcc'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } + isEdible() { return false; } + isPushable() { return false; } + moveHorizontal(dx: number) { } + moveVertical(dx: number) { } } class Player implements Tile { @@ -125,6 +141,10 @@ class Player implements Tile { isKey2() { return false; } isLock2() { return false; } draw(g: CanvasRenderingContext2D, x: number, y: number) { } + isEdible() { return false; } + isPushable() { return false; } + moveHorizontal(dx: number) { } + moveVertical(dx: number) { } } class Stone implements Tile { @@ -144,6 +164,16 @@ class Stone implements Tile { g.fillStyle = '#0000cc'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } + isEdible() { return false; } + isPushable() { return true; } + moveHorizontal(dx: number) { + if (map[playery][playerx + dx + dx].isAir() + && !map[playery + 1][playerx + dx].isAir()) { + map[playery][playerx + dx + dx] = map[playery][playerx + dx]; + moveToTile(playerx + dx, playery); + } + } + moveVertical(dx: number) { } } class FallingStone implements Tile { @@ -163,6 +193,10 @@ class FallingStone implements Tile { g.fillStyle = '#0000cc'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } + isEdible() { return false; } + isPushable() { return false; } + moveHorizontal(dx: number) { } + moveVertical(dx: number) { } } class Box implements Tile { @@ -182,6 +216,16 @@ class Box implements Tile { g.fillStyle = '#8b4513'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } + isEdible() { return false; } + isPushable() { return true; } + moveHorizontal(dx: number) { + if (map[playery][playerx + dx + dx].isAir() + && !map[playery + 1][playerx + dx].isAir()) { + map[playery][playerx + dx + dx] = map[playery][playerx + dx]; + moveToTile(playerx + dx, playery); + } + } + moveVertical(dx: number) { } } class FallingBox implements Tile { @@ -201,6 +245,10 @@ class FallingBox implements Tile { g.fillStyle = '#8b4513'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } + isEdible() { return false; } + isPushable() { return false; } + moveHorizontal(dx: number) { } + moveVertical(dx: number) { } } class Key1 implements Tile { @@ -220,6 +268,16 @@ class Key1 implements Tile { g.fillStyle = '#ffcc00'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } + isEdible() { return false; } + isPushable() { return false; } + moveHorizontal(dx: number) { + removeLock1(RawTile.LOCK1); + moveToTile(playerx + dx, playery); + } + moveVertical(dx: number) { + removeLock1(RawTile.LOCK1); + moveToTile(playerx, playery + dy); + } } class Lock1 implements Tile { @@ -239,6 +297,10 @@ class Lock1 implements Tile { g.fillStyle = '#ffcc00'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } + isEdible() { return false; } + isPushable() { return false; } + moveHorizontal(dx: number) { } + moveVertical(dx: number) { } } class Key2 implements Tile { @@ -258,6 +320,16 @@ class Key2 implements Tile { g.fillStyle = '#00ccff'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } + isEdible() { return false; } + isPushable() { return false; } + moveHorizontal(dx: number) { + removeLock2(RawTile.LOCK2); + moveToTile(playerx + dx, playery); + } + moveVertical(dx: number) { + removeLock2(RawTile.LOCK2); + moveToTile(playerx, playery + dy); + } } class Lock2 implements Tile { @@ -277,6 +349,10 @@ class Lock2 implements Tile { g.fillStyle = '#00ccff'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } + isEdible() { return false; } + isPushable() { return false; } + moveHorizontal(dx: number) { } + moveVertical(dx: number) { } } // Input Enum & Interface & Class @@ -393,38 +469,6 @@ function moveToTile(newx: number, newy: number) { playery = newy; } -function moveHorizontal(dx: number) { - if (map[playery][playerx + dx].isFlux() - || map[playery][playerx + dx].isAir()) { - moveToTile(playerx + dx, playery); - } else if ((map[playery][playerx + dx].isStone() - || map[playery][playerx + dx].isBox()) - && map[playery][playerx + dx + dx].isAir() - && !map[playery + 1][playerx + dx].isAir()) { - map[playery][playerx + dx + dx] = map[playery][playerx + dx]; - moveToTile(playerx + dx, playery); - } else if (map[playery][playerx + dx].isKey1()) { - removeLock1(RawTile.LOCK1); - moveToTile(playerx + dx, playery); - } else if (map[playery][playerx + dx].isKey2()) { - removeLock2(RawTile.LOCK2); - moveToTile(playerx + dx, playery); - } -} - -function moveVertical(dy: number) { - if (map[playery + dy][playerx].isFlux() - || map[playery + dy][playerx].isAir()) { - moveToTile(playerx, playery + dy); - } else if (map[playery + dy][playerx].isKey1()) { - removeLock1(RawTile.LOCK1); - moveToTile(playerx, playery + dy); - } else if (map[playery + dy][playerx].isKey2()) { - removeLock2(RawTile.LOCK2); - moveToTile(playerx, playery + dy); - } -} - function update() { handleInputs(); updateMap(); From 6733d98e090a5a0a12241cf3cab7e3cd3eeaabf7 Mon Sep 17 00:00:00 2001 From: leehoosgg Date: Wed, 27 Dec 2023 14:22:11 +0900 Subject: [PATCH 12/21] =?UTF-8?q?stony,=20boxy=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20stone,=20box=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EB=A6=AC=ED=8C=A9=ED=84=B0?= =?UTF-8?q?=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 생성자와 추가 인터페이스 도입으로 if문 간소화 --- index.ts | 201 +++++++++++++++++----------------- src/ch02/trafficLight.test.ts | 7 -- 2 files changed, 102 insertions(+), 106 deletions(-) diff --git a/index.ts b/index.ts index c28221c..b0dd28e 100644 --- a/index.ts +++ b/index.ts @@ -47,9 +47,8 @@ interface Tile { isUnbreakable(): boolean; isPlayer(): boolean; isStone(): boolean; - isFallingStone(): boolean; isBox(): boolean; - isFallingBox(): boolean; + isFalling(): boolean; isKey1(): boolean; isLock1(): boolean; isKey2(): boolean; @@ -57,8 +56,12 @@ interface Tile { draw(g: CanvasRenderingContext2D, x: number, y: number): void; isEdible(): boolean; isPushable(): boolean; + isStony(): boolean; + isBoxy(): boolean; moveHorizontal(dx: number): void; moveVertical(dx: number): void; + drop(): void; + rest(): void; } class Air implements Tile { @@ -67,9 +70,8 @@ class Air implements Tile { isUnbreakable() { return false; } isPlayer() { return false; } isStone() { return false; } - isFallingStone() { return false; } isBox() { return false; } - isFallingBox() { return false; } + isFalling() { return false; } isKey1() { return false; } isLock1() { return false; } isKey2() { return false; } @@ -77,8 +79,12 @@ class Air implements Tile { draw(g: CanvasRenderingContext2D, x:number, y: number) { } isEdible() { return true; } isPushable() { return false; } + isStony() { return false; } + isBoxy() { return false; } moveHorizontal(dx: number) { moveToTile(playerx + dx, playery); } - moveVertical(dx: number) { moveToTile(playerx, playery + dy); } + moveVertical(dx: number) { moveToTile(playerx, playery + dx); } + drop() { } + rest() { } } class Flux implements Tile { @@ -87,13 +93,14 @@ class Flux implements Tile { isUnbreakable() { return false; } isPlayer() { return false; } isStone() { return false; } - isFallingStone() { return false; } isBox() { return false; } - isFallingBox() { return false; } + isFalling() { return false; } isKey1() { return false; } isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } + isStony() { return false; } + isBoxy() { return false; } draw(g: CanvasRenderingContext2D, x: number, y: number) { g.fillStyle = '#999999'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); @@ -101,7 +108,9 @@ class Flux implements Tile { isEdible() { return true; } isPushable() { return false; } moveHorizontal(dx: number) { moveToTile(playerx + dx, playery); } - moveVertical(dx: number) { moveToTile(playerx, playery + dy); } + moveVertical(dx: number) { moveToTile(playerx, playery + dx); } + drop() { } + rest() { } } class Unbreakable implements Tile { @@ -110,13 +119,14 @@ class Unbreakable implements Tile { isUnbreakable() { return true; } isPlayer() { return false; } isStone() { return false; } - isFallingStone() { return false; } isBox() { return false; } - isFallingBox() { return false; } + isFalling() { return false; } isKey1() { return false; } isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } + isStony() { return false; } + isBoxy() { return false; } draw(g: CanvasRenderingContext2D, x: number, y: number) { g.fillStyle = '#ccffcc'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); @@ -125,6 +135,8 @@ class Unbreakable implements Tile { isPushable() { return false; } moveHorizontal(dx: number) { } moveVertical(dx: number) { } + drop() { } + rest() { } } class Player implements Tile { @@ -133,85 +145,91 @@ class Player implements Tile { isUnbreakable() { return false; } isPlayer() { return true; } isStone() { return false; } - isFallingStone() { return false; } isBox() { return false; } - isFallingBox() { return false; } + isFalling() { return false; } isKey1() { return false; } isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } + isStony() { return false; } + isBoxy() { return false; } draw(g: CanvasRenderingContext2D, x: number, y: number) { } isEdible() { return false; } isPushable() { return false; } moveHorizontal(dx: number) { } moveVertical(dx: number) { } + drop() { } + rest() { } } -class Stone implements Tile { - isAir() { return false; } - isFlux() { return false; } - isUnbreakable() { return false; } - isPlayer() { return false; } - isStone() { return true; } - isFallingStone() { return false; } - isBox() { return false; } - isFallingBox() { return false; } - isKey1() { return false; } - isLock1() { return false; } - isKey2() { return false; } - isLock2() { return false; } - draw(g: CanvasRenderingContext2D, x: number, y: number) { - g.fillStyle = '#0000cc'; - g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); - } - isEdible() { return false; } - isPushable() { return true; } - moveHorizontal(dx: number) { +interface FallingState { + isFalling(): boolean; + isResting(): boolean; + moveHorizontal(tile: Tile, dx: number): void; +} + +class Falling implements FallingState { + isFalling() { return true; } + isResting() { return false; } + moveHorizontal(tile: Tile, dx: number) { } +} + +class Resting implements FallingState { + isFalling() { return false; } + isResting() { return true; } + moveHorizontal(tile: Tile, dx: number) { if (map[playery][playerx + dx + dx].isAir() - && !map[playery + 1][playerx + dx].isAir()) { - map[playery][playerx + dx + dx] = map[playery][playerx + dx]; + && !map[playery + 1][playerx + dx].isAir()) { + map[playery][playerx + dx + dx] = tile; moveToTile(playerx + dx, playery); } } - moveVertical(dx: number) { } } -class FallingStone implements Tile { +class Stone implements Tile { + constructor(private falling: FallingState) {} isAir() { return false; } isFlux() { return false; } isUnbreakable() { return false; } isPlayer() { return false; } - isStone() { return false; } - isFallingStone() { return true; } + isStone() { return true; } isBox() { return false; } - isFallingBox() { return false; } + isFalling() { return this.falling.isFalling(); } isKey1() { return false; } isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } + isStony() { return true; } + isBoxy() { return false; } draw(g: CanvasRenderingContext2D, x: number, y: number) { g.fillStyle = '#0000cc'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } isEdible() { return false; } - isPushable() { return false; } - moveHorizontal(dx: number) { } + isPushable() { return true; } + moveHorizontal(dx: number) { + this.falling.moveHorizontal(this, dx); + } moveVertical(dx: number) { } + drop() { this.falling = new Falling(); } + rest() { this.falling = new Resting(); } } class Box implements Tile { + constructor(private falling: FallingState) {} isAir() { return false; } isFlux() { return false; } isUnbreakable() { return false; } isPlayer() { return false; } isStone() { return false; } - isFallingStone() { return false; } isBox() { return true; } - isFallingBox() { return false; } + isFalling() { return this.falling.isFalling(); } isKey1() { return false; } isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } + isStony() { return false; } + isBoxy() { return true; } draw(g: CanvasRenderingContext2D, x: number, y: number) { g.fillStyle = '#8b4513'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); @@ -219,36 +237,11 @@ class Box implements Tile { isEdible() { return false; } isPushable() { return true; } moveHorizontal(dx: number) { - if (map[playery][playerx + dx + dx].isAir() - && !map[playery + 1][playerx + dx].isAir()) { - map[playery][playerx + dx + dx] = map[playery][playerx + dx]; - moveToTile(playerx + dx, playery); - } + this.falling.moveHorizontal(this, dx); } moveVertical(dx: number) { } -} - -class FallingBox implements Tile { - isAir() { return false; } - isFlux() { return false; } - isUnbreakable() { return false; } - isPlayer() { return false; } - isStone() { return false; } - isFallingStone() { return false; } - isBox() { return false; } - isFallingBox() { return true; } - isKey1() { return false; } - isLock1() { return false; } - isKey2() { return false; } - isLock2() { return false; } - draw(g: CanvasRenderingContext2D, x: number, y: number) { - g.fillStyle = '#8b4513'; - g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); - } - isEdible() { return false; } - isPushable() { return false; } - moveHorizontal(dx: number) { } - moveVertical(dx: number) { } + drop() { this.falling = new Falling(); } + rest() { this.falling = new Resting(); } } class Key1 implements Tile { @@ -257,13 +250,14 @@ class Key1 implements Tile { isUnbreakable() { return false; } isPlayer() { return false; } isStone() { return false; } - isFallingStone() { return false; } isBox() { return false; } - isFallingBox() { return false; } + isFalling() { return false; } isKey1() { return true; } isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } + isStony() { return false; } + isBoxy() { return false; } draw(g: CanvasRenderingContext2D, x: number, y: number) { g.fillStyle = '#ffcc00'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); @@ -276,8 +270,10 @@ class Key1 implements Tile { } moveVertical(dx: number) { removeLock1(RawTile.LOCK1); - moveToTile(playerx, playery + dy); + moveToTile(playerx, playery + dx); } + drop() { } + rest() { } } class Lock1 implements Tile { @@ -286,13 +282,14 @@ class Lock1 implements Tile { isUnbreakable() { return false; } isPlayer() { return false; } isStone() { return false; } - isFallingStone() { return false; } isBox() { return false; } - isFallingBox() { return false; } + isFalling() { return false; } isKey1() { return false; } isLock1() { return true; } isKey2() { return false; } isLock2() { return false; } + isStony() { return false; } + isBoxy() { return false; } draw(g: CanvasRenderingContext2D, x: number, y: number) { g.fillStyle = '#ffcc00'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); @@ -301,6 +298,8 @@ class Lock1 implements Tile { isPushable() { return false; } moveHorizontal(dx: number) { } moveVertical(dx: number) { } + drop() { } + rest() { } } class Key2 implements Tile { @@ -309,13 +308,14 @@ class Key2 implements Tile { isUnbreakable() { return false; } isPlayer() { return false; } isStone() { return false; } - isFallingStone() { return false; } isBox() { return false; } - isFallingBox() { return false; } + isFalling() { return false; } isKey1() { return false; } isLock1() { return false; } isKey2() { return true; } isLock2() { return false; } + isStony() { return false; } + isBoxy() { return false; } draw(g: CanvasRenderingContext2D, x: number, y: number) { g.fillStyle = '#00ccff'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); @@ -328,8 +328,10 @@ class Key2 implements Tile { } moveVertical(dx: number) { removeLock2(RawTile.LOCK2); - moveToTile(playerx, playery + dy); + moveToTile(playerx, playery + dx); } + drop() { } + rest() { } } class Lock2 implements Tile { @@ -338,13 +340,14 @@ class Lock2 implements Tile { isUnbreakable() { return false; } isPlayer() { return false; } isStone() { return false; } - isFallingStone() { return false; } isBox() { return false; } - isFallingBox() { return false; } + isFalling() { return false; } isKey1() { return false; } isLock1() { return false; } isKey2() { return false; } isLock2() { return true; } + isStony() { return false; } + isBoxy() { return false; } draw(g: CanvasRenderingContext2D, x: number, y: number) { g.fillStyle = '#00ccff'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); @@ -353,6 +356,8 @@ class Lock2 implements Tile { isPushable() { return false; } moveHorizontal(dx: number) { } moveVertical(dx: number) { } + drop() { } + rest() { } } // Input Enum & Interface & Class @@ -373,7 +378,7 @@ class Right implements Input { isLeft() { return false; } isUp() { return false; } isDown() { return false; } - handle() { moveHorizontal(1); } + handle() { moveToTile(playerx + 1, playery); } } class Left implements Input { @@ -381,7 +386,7 @@ class Left implements Input { isLeft() { return true; } isUp() { return false; } isDown() { return false; } - handle() { moveHorizontal(-1); } + handle() { moveToTile(playerx - 1, playery); } } class Up implements Input { @@ -389,7 +394,7 @@ class Up implements Input { isLeft() { return false; } isUp() { return true; } isDown() { return false; } - handle() { moveVertical(-1); } + handle() { moveToTile(playerx, playery - 1); } } class Down implements Input { @@ -397,7 +402,7 @@ class Down implements Input { isLeft() { return false; } isUp() { return false; } isDown() { return true; } - handle() { moveVertical(1); } + handle() { moveToTile(playerx, playery + 1); } } let playerx = 1; @@ -429,16 +434,16 @@ function assertExhausted(x: never): never { function transformTile(tile: RawTile) { switch(tile) { case RawTile.AIR: return new Air(); - case RawTile.BOX: return new Box(); - case RawTile.FALLING_BOX: return new FallingBox(); - case RawTile.FALLING_STONE: return new FallingStone(); + case RawTile.BOX: return new Box(new Resting); + case RawTile.FALLING_BOX: return new Stone(new Falling); + case RawTile.FALLING_STONE: return new Stone(new Falling); case RawTile.FLUX: return new Flux(); case RawTile.KEY1: return new Key1(); case RawTile.KEY2: return new Key2(); case RawTile.LOCK1: return new Lock1(); case RawTile.LOCK2: return new Lock2(); case RawTile.PLAYER: return new Player(); - case RawTile.STONE: return new Stone(); + case RawTile.STONE: return new Stone(new Resting); case RawTile.UNBREAKABLE: return new Unbreakable(); default: assertExhausted(tile); } @@ -484,18 +489,16 @@ function handleInputs() { function updateMap() { for (let y = map.length - 1; y >= 0; y--) { for (let x = 0; x < map[y].length; x++) { - if ((map[y][x].isStone() || map[y][x].isFallingStone()) - && map[y + 1][x].isAir()) { - map[y + 1][x] = new FallingStone(); + if (map[y][x].isStony() && map[y + 1][x].isAir()) { + map[y][x].drop(); + map[y + 1][x] = map[y][x]; map[y][x] = new Air(); - } else if ((map[y][x].isBox() || map[y][x].isFallingBox()) - && map[y + 1][x].isAir()) { - map[y + 1][x] = new FallingBox(); + } else if (map[y][x].isBoxy() && map[y + 1][x].isAir()) { + map[y][x].drop(); + map[y + 1][x] = map[y][x]; map[y][x] = new Air(); - } else if (map[y][x].isFallingStone()) { - map[y][x] = new Stone(); - } else if (map[y][x].isFallingBox()) { - map[y][x] = new Box(); + } else if (map[y][x].isFalling()) { + map[y][x].rest(); } } } diff --git a/src/ch02/trafficLight.test.ts b/src/ch02/trafficLight.test.ts index 4b7f7a4..413efb2 100644 --- a/src/ch02/trafficLight.test.ts +++ b/src/ch02/trafficLight.test.ts @@ -14,13 +14,6 @@ class Car { } } -// interface TrafficLight { -// isRed(): boolean; -// isYellow(): boolean; -// isGreen(): boolean; -// updateCar(): boolean; -// } - interface TrafficLight { updateCar(): boolean; } From a8e4e99676e83b1a98ea0d539220cce56c930bbc Mon Sep 17 00:00:00 2001 From: leehoosgg Date: Wed, 27 Dec 2023 14:23:09 +0900 Subject: [PATCH 13/21] =?UTF-8?q?.prettierignore=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EB=AC=B4=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 개인적으로 사용하는 prettier 를 이 프로젝트에서 작동하지 않게 하는 파일입니다. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c558fad..85bae45 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .idea .vscode +.prettierignore node_modules dist From 44826c245853570ae771c890d7f79535ddf1fdec Mon Sep 17 00:00:00 2001 From: leehoosgg Date: Wed, 27 Dec 2023 14:24:10 +0900 Subject: [PATCH 14/21] =?UTF-8?q?=EC=A1=B0=EA=B1=B4=EB=AC=B8=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EB=B6=80=EC=88=98=EC=A0=81=EC=9D=B8=20=EB=8F=99?= =?UTF-8?q?=EC=9E=91=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - --- src/ch03/Reader.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ch03/Reader.ts b/src/ch03/Reader.ts index e38e51a..867207e 100644 --- a/src/ch03/Reader.ts +++ b/src/ch03/Reader.ts @@ -2,9 +2,11 @@ class Reader { private data: string[]; private current: number; + nextLine() { + this.current++; + } readLine() { - this.current++; return this.data[this.current] || null; } } @@ -13,7 +15,8 @@ const run = () => { const br = new Reader(); let line: string | null; - while ((line = br.readLine()) !== null) { - return line; + for (; br.readLine() !== null; br.nextLine()) { + let line = br.readLine(); + console.log(line); } }; From 755dc5474aeab5ec1190defa8d92d89872c07fff Mon Sep 17 00:00:00 2001 From: leehoosgg Date: Fri, 29 Dec 2023 10:40:25 +0900 Subject: [PATCH 15/21] =?UTF-8?q?updateTile=20=EC=9D=B8=EB=9D=BC=EC=9D=B8?= =?UTF-8?q?=ED=99=94=EC=99=80=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - --- index.ts | 247 ++++++++++++++++--------------------------------------- 1 file changed, 71 insertions(+), 176 deletions(-) diff --git a/index.ts b/index.ts index b0dd28e..caa9251 100644 --- a/index.ts +++ b/index.ts @@ -43,123 +43,78 @@ enum RawTile { interface Tile { isAir(): boolean; - isFlux(): boolean; - isUnbreakable(): boolean; - isPlayer(): boolean; - isStone(): boolean; - isBox(): boolean; isFalling(): boolean; isKey1(): boolean; isLock1(): boolean; isKey2(): boolean; isLock2(): boolean; draw(g: CanvasRenderingContext2D, x: number, y: number): void; - isEdible(): boolean; - isPushable(): boolean; - isStony(): boolean; - isBoxy(): boolean; + canFall(): boolean; moveHorizontal(dx: number): void; - moveVertical(dx: number): void; - drop(): void; - rest(): void; + moveVertical(dy: number): void; + update(x: number, y: number): void; } class Air implements Tile { isAir() { return true; } - isFlux() { return false; } - isUnbreakable() { return false; } - isPlayer() { return false; } - isStone() { return false; } - isBox() { return false; } isFalling() { return false; } isKey1() { return false; } isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } draw(g: CanvasRenderingContext2D, x:number, y: number) { } - isEdible() { return true; } - isPushable() { return false; } - isStony() { return false; } - isBoxy() { return false; } + canFall() { return false; } moveHorizontal(dx: number) { moveToTile(playerx + dx, playery); } - moveVertical(dx: number) { moveToTile(playerx, playery + dx); } - drop() { } - rest() { } + moveVertical(dy: number) { moveToTile(playerx, playery + dy); } + update(x: number, y: number) { } } class Flux implements Tile { isAir() { return false; } - isFlux() { return true; } - isUnbreakable() { return false; } - isPlayer() { return false; } - isStone() { return false; } - isBox() { return false; } isFalling() { return false; } isKey1() { return false; } isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } - isStony() { return false; } - isBoxy() { return false; } + canFall() { return false; } draw(g: CanvasRenderingContext2D, x: number, y: number) { g.fillStyle = '#999999'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } - isEdible() { return true; } - isPushable() { return false; } moveHorizontal(dx: number) { moveToTile(playerx + dx, playery); } - moveVertical(dx: number) { moveToTile(playerx, playery + dx); } - drop() { } - rest() { } + moveVertical(dy: number) { moveToTile(playerx, playery + dy); } + update(x: number, y: number) { } } class Unbreakable implements Tile { isAir() { return false; } - isFlux() { return false; } - isUnbreakable() { return true; } - isPlayer() { return false; } - isStone() { return false; } - isBox() { return false; } isFalling() { return false; } isKey1() { return false; } isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } - isStony() { return false; } - isBoxy() { return false; } + canFall() { return false; } draw(g: CanvasRenderingContext2D, x: number, y: number) { g.fillStyle = '#ccffcc'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } - isEdible() { return false; } - isPushable() { return false; } moveHorizontal(dx: number) { } - moveVertical(dx: number) { } - drop() { } - rest() { } + moveVertical(dy: number) { } + update(x: number, y: number) { } } class Player implements Tile { isAir() { return false; } - isFlux() { return false; } - isUnbreakable() { return false; } - isPlayer() { return true; } - isStone() { return false; } - isBox() { return false; } isFalling() { return false; } isKey1() { return false; } isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } - isStony() { return false; } - isBoxy() { return false; } + canFall() { return false; } draw(g: CanvasRenderingContext2D, x: number, y: number) { } - isEdible() { return false; } - isPushable() { return false; } moveHorizontal(dx: number) { } - moveVertical(dx: number) { } - drop() { } - rest() { } + moveVertical(dy: number) { } + update(x: number, y: number) { } } interface FallingState { @@ -189,175 +144,137 @@ class Resting implements FallingState { class Stone implements Tile { constructor(private falling: FallingState) {} isAir() { return false; } - isFlux() { return false; } - isUnbreakable() { return false; } - isPlayer() { return false; } - isStone() { return true; } - isBox() { return false; } isFalling() { return this.falling.isFalling(); } isKey1() { return false; } isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } - isStony() { return true; } - isBoxy() { return false; } + canFall() { return true; } draw(g: CanvasRenderingContext2D, x: number, y: number) { g.fillStyle = '#0000cc'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } - isEdible() { return false; } - isPushable() { return true; } moveHorizontal(dx: number) { this.falling.moveHorizontal(this, dx); } - moveVertical(dx: number) { } - drop() { this.falling = new Falling(); } - rest() { this.falling = new Resting(); } + moveVertical(dy: number) { } + update(x: number, y: number) { + if (map[y + 1][x].isAir()) { + this.falling = new Falling(); + map[y + 1][x] = this; + map[y][x] = new Air(); + } else if (map[y][x].isFalling()) { + this.falling = new Resting(); + } + } } class Box implements Tile { constructor(private falling: FallingState) {} isAir() { return false; } - isFlux() { return false; } - isUnbreakable() { return false; } - isPlayer() { return false; } - isStone() { return false; } - isBox() { return true; } isFalling() { return this.falling.isFalling(); } isKey1() { return false; } isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } - isStony() { return false; } - isBoxy() { return true; } + canFall() { return true; } draw(g: CanvasRenderingContext2D, x: number, y: number) { g.fillStyle = '#8b4513'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } - isEdible() { return false; } - isPushable() { return true; } moveHorizontal(dx: number) { this.falling.moveHorizontal(this, dx); } - moveVertical(dx: number) { } - drop() { this.falling = new Falling(); } - rest() { this.falling = new Resting(); } + moveVertical(dy: number) { } + update(x: number, y: number) { + if (map[y + 1][x].isAir()) { + this.falling = new Falling(); + map[y + 1][x] = this; + map[y][x] = new Air(); + } else if (map[y][x].isFalling()) { + this.falling = new Resting(); + } + } } class Key1 implements Tile { isAir() { return false; } - isFlux() { return false; } - isUnbreakable() { return false; } - isPlayer() { return false; } - isStone() { return false; } - isBox() { return false; } isFalling() { return false; } isKey1() { return true; } isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } - isStony() { return false; } - isBoxy() { return false; } + canFall() { return false; } draw(g: CanvasRenderingContext2D, x: number, y: number) { g.fillStyle = '#ffcc00'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } - isEdible() { return false; } - isPushable() { return false; } moveHorizontal(dx: number) { removeLock1(RawTile.LOCK1); moveToTile(playerx + dx, playery); } - moveVertical(dx: number) { + moveVertical(dy: number) { removeLock1(RawTile.LOCK1); - moveToTile(playerx, playery + dx); + moveToTile(playerx, playery + dy); } - drop() { } - rest() { } + update(x: number, y: number) { } } class Lock1 implements Tile { isAir() { return false; } - isFlux() { return false; } - isUnbreakable() { return false; } - isPlayer() { return false; } - isStone() { return false; } - isBox() { return false; } isFalling() { return false; } isKey1() { return false; } isLock1() { return true; } isKey2() { return false; } isLock2() { return false; } - isStony() { return false; } - isBoxy() { return false; } + canFall() { return false; } draw(g: CanvasRenderingContext2D, x: number, y: number) { g.fillStyle = '#ffcc00'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } - isEdible() { return false; } - isPushable() { return false; } moveHorizontal(dx: number) { } - moveVertical(dx: number) { } - drop() { } - rest() { } + moveVertical(dy: number) { } + update(x: number, y: number) { } } class Key2 implements Tile { isAir() { return false; } - isFlux() { return false; } - isUnbreakable() { return false; } - isPlayer() { return false; } - isStone() { return false; } - isBox() { return false; } isFalling() { return false; } isKey1() { return false; } isLock1() { return false; } isKey2() { return true; } isLock2() { return false; } - isStony() { return false; } - isBoxy() { return false; } + canFall() { return false; } draw(g: CanvasRenderingContext2D, x: number, y: number) { g.fillStyle = '#00ccff'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } - isEdible() { return false; } - isPushable() { return false; } moveHorizontal(dx: number) { removeLock2(RawTile.LOCK2); moveToTile(playerx + dx, playery); } - moveVertical(dx: number) { + moveVertical(dy: number) { removeLock2(RawTile.LOCK2); - moveToTile(playerx, playery + dx); + moveToTile(playerx, playery + dy); } - drop() { } - rest() { } + update(x: number, y: number) { } } class Lock2 implements Tile { isAir() { return false; } - isFlux() { return false; } - isUnbreakable() { return false; } - isPlayer() { return false; } - isStone() { return false; } - isBox() { return false; } isFalling() { return false; } isKey1() { return false; } isLock1() { return false; } isKey2() { return false; } isLock2() { return true; } - isStony() { return false; } - isBoxy() { return false; } + canFall() { return false; } draw(g: CanvasRenderingContext2D, x: number, y: number) { g.fillStyle = '#00ccff'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } - isEdible() { return false; } - isPushable() { return false; } moveHorizontal(dx: number) { } - moveVertical(dx: number) { } - drop() { } - rest() { } + moveVertical(dy: number) { } + update(x: number, y: number) { } } // Input Enum & Interface & Class @@ -366,43 +283,23 @@ enum RawInput { } interface Input { - isRight(): boolean; - isLeft(): boolean; - isUp(): boolean; - isDown(): boolean; handle(): void; } class Right implements Input { - isRight() { return true; } - isLeft() { return false; } - isUp() { return false; } - isDown() { return false; } - handle() { moveToTile(playerx + 1, playery); } + handle() { moveHorizontal(1); } } class Left implements Input { - isRight() { return false; } - isLeft() { return true; } - isUp() { return false; } - isDown() { return false; } - handle() { moveToTile(playerx - 1, playery); } + handle() { moveHorizontal(-1); } } class Up implements Input { - isRight() { return false; } - isLeft() { return false; } - isUp() { return true; } - isDown() { return false; } - handle() { moveToTile(playerx, playery - 1); } + handle() { moveVertical(-1); } } class Down implements Input { - isRight() { return false; } - isLeft() { return false; } - isUp() { return false; } - isDown() { return true; } - handle() { moveToTile(playerx, playery + 1); } + handle() { moveVertical(1); } } let playerx = 1; @@ -474,11 +371,27 @@ function moveToTile(newx: number, newy: number) { playery = newy; } +function moveHorizontal(dx: number) { + map[playery][playerx + dx].moveHorizontal(dx); +} + +function moveVertical(dy: number) { + map[playery + dy][playerx].moveVertical(dy); +} + function update() { handleInputs(); updateMap(); } +function updateMap() { + for (let y = map.length - 1; y >=0; y--) { + for (let x = 0; x < map[y].length; x++) { + map[y][x].update(x, y); + } + } +} + function handleInputs() { while (inputs.length > 0) { const input = inputs.pop(); @@ -486,24 +399,6 @@ function handleInputs() { } } -function updateMap() { - for (let y = map.length - 1; y >= 0; y--) { - for (let x = 0; x < map[y].length; x++) { - if (map[y][x].isStony() && map[y + 1][x].isAir()) { - map[y][x].drop(); - map[y + 1][x] = map[y][x]; - map[y][x] = new Air(); - } else if (map[y][x].isBoxy() && map[y + 1][x].isAir()) { - map[y][x].drop(); - map[y + 1][x] = map[y][x]; - map[y][x] = new Air(); - } else if (map[y][x].isFalling()) { - map[y][x].rest(); - } - } - } -} - function draw() { let g = createGraphics(); drawMap(g); From 5a9d2f1919f79852193e505b431faeefe0aa43b6 Mon Sep 17 00:00:00 2001 From: leehoosgg Date: Fri, 29 Dec 2023 16:45:19 +0900 Subject: [PATCH 16/21] =?UTF-8?q?FallStrategy=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=EB=A1=9C=20=EC=BD=94=EB=93=9C=20=EC=9D=B4=EA=B4=80=20?= =?UTF-8?q?=EB=B0=8F=20=EB=A9=94=EC=86=8C=EB=93=9C=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - --- index.ts | 70 ++++++++++++++++++++++++-------------------------------- 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/index.ts b/index.ts index caa9251..7762b51 100644 --- a/index.ts +++ b/index.ts @@ -43,13 +43,11 @@ enum RawTile { interface Tile { isAir(): boolean; - isFalling(): boolean; isKey1(): boolean; isLock1(): boolean; isKey2(): boolean; isLock2(): boolean; draw(g: CanvasRenderingContext2D, x: number, y: number): void; - canFall(): boolean; moveHorizontal(dx: number): void; moveVertical(dy: number): void; update(x: number, y: number): void; @@ -57,13 +55,11 @@ interface Tile { class Air implements Tile { isAir() { return true; } - isFalling() { return false; } isKey1() { return false; } isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } draw(g: CanvasRenderingContext2D, x:number, y: number) { } - canFall() { return false; } moveHorizontal(dx: number) { moveToTile(playerx + dx, playery); } moveVertical(dy: number) { moveToTile(playerx, playery + dy); } update(x: number, y: number) { } @@ -71,12 +67,10 @@ class Air implements Tile { class Flux implements Tile { isAir() { return false; } - isFalling() { return false; } isKey1() { return false; } isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } - canFall() { return false; } draw(g: CanvasRenderingContext2D, x: number, y: number) { g.fillStyle = '#999999'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); @@ -88,12 +82,10 @@ class Flux implements Tile { class Unbreakable implements Tile { isAir() { return false; } - isFalling() { return false; } isKey1() { return false; } isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } - canFall() { return false; } draw(g: CanvasRenderingContext2D, x: number, y: number) { g.fillStyle = '#ccffcc'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); @@ -105,12 +97,10 @@ class Unbreakable implements Tile { class Player implements Tile { isAir() { return false; } - isFalling() { return false; } isKey1() { return false; } isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } - canFall() { return false; } draw(g: CanvasRenderingContext2D, x: number, y: number) { } moveHorizontal(dx: number) { } moveVertical(dy: number) { } @@ -141,70 +131,76 @@ class Resting implements FallingState { } } +class FallStrategy { + constructor(private falling: FallingState) { } + isFalling() { return this.falling; } + update(tile: Tile, x: number, y: number) { + this.falling = map[y + 1][x].isAir() ? new Falling() : new Resting(); + this.drop(tile, x, y); + } + moveHorizontal(tile: Tile, dx: number) { + this.falling.moveHorizontal(tile, dx); + } + private drop(tile: Tile, x: number, y: number) { + if (this.falling.isFalling()) { + map[y + 1][x] = tile; + map[y][x] = new Air(); + } + } +} + class Stone implements Tile { - constructor(private falling: FallingState) {} + private fallStrategy: FallStrategy; + constructor(falling: FallingState) { + this.fallStrategy = new FallStrategy(falling); + } isAir() { return false; } - isFalling() { return this.falling.isFalling(); } isKey1() { return false; } isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } - canFall() { return true; } draw(g: CanvasRenderingContext2D, x: number, y: number) { g.fillStyle = '#0000cc'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } moveHorizontal(dx: number) { - this.falling.moveHorizontal(this, dx); + this.fallStrategy.moveHorizontal(this, dx); } moveVertical(dy: number) { } update(x: number, y: number) { - if (map[y + 1][x].isAir()) { - this.falling = new Falling(); - map[y + 1][x] = this; - map[y][x] = new Air(); - } else if (map[y][x].isFalling()) { - this.falling = new Resting(); - } + this.fallStrategy.update(this, x, y); } } class Box implements Tile { - constructor(private falling: FallingState) {} + private fallStrategy: FallStrategy; + constructor(falling: FallingState) { + this.fallStrategy = new FallStrategy(falling); + } isAir() { return false; } - isFalling() { return this.falling.isFalling(); } isKey1() { return false; } isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } - canFall() { return true; } draw(g: CanvasRenderingContext2D, x: number, y: number) { g.fillStyle = '#8b4513'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } moveHorizontal(dx: number) { - this.falling.moveHorizontal(this, dx); + this.fallStrategy.moveHorizontal(this, dx); } moveVertical(dy: number) { } update(x: number, y: number) { - if (map[y + 1][x].isAir()) { - this.falling = new Falling(); - map[y + 1][x] = this; - map[y][x] = new Air(); - } else if (map[y][x].isFalling()) { - this.falling = new Resting(); - } + this.fallStrategy.update(this, x, y); } } class Key1 implements Tile { isAir() { return false; } - isFalling() { return false; } isKey1() { return true; } isLock1() { return false; } isKey2() { return false; } isLock2() { return false; } - canFall() { return false; } draw(g: CanvasRenderingContext2D, x: number, y: number) { g.fillStyle = '#ffcc00'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); @@ -222,12 +218,10 @@ class Key1 implements Tile { class Lock1 implements Tile { isAir() { return false; } - isFalling() { return false; } isKey1() { return false; } isLock1() { return true; } isKey2() { return false; } isLock2() { return false; } - canFall() { return false; } draw(g: CanvasRenderingContext2D, x: number, y: number) { g.fillStyle = '#ffcc00'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); @@ -239,12 +233,10 @@ class Lock1 implements Tile { class Key2 implements Tile { isAir() { return false; } - isFalling() { return false; } isKey1() { return false; } isLock1() { return false; } isKey2() { return true; } isLock2() { return false; } - canFall() { return false; } draw(g: CanvasRenderingContext2D, x: number, y: number) { g.fillStyle = '#00ccff'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); @@ -262,12 +254,10 @@ class Key2 implements Tile { class Lock2 implements Tile { isAir() { return false; } - isFalling() { return false; } isKey1() { return false; } isLock1() { return false; } isKey2() { return false; } isLock2() { return true; } - canFall() { return false; } draw(g: CanvasRenderingContext2D, x: number, y: number) { g.fillStyle = '#00ccff'; g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); From 6068dff7e2d0f37a7cdc76818d6509808ed28d3f Mon Sep 17 00:00:00 2001 From: leehoosgg Date: Tue, 2 Jan 2024 15:19:02 +0900 Subject: [PATCH 17/21] =?UTF-8?q?Array.ts=20=EC=A0=84=EB=9E=B5=20=ED=8C=A8?= =?UTF-8?q?=ED=84=B4=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MinimumProcessor, SumProcessor 클래스 분리하여 컴포지션 --- src/ch03/Array.ts | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/src/ch03/Array.ts b/src/ch03/Array.ts index bf0b519..0a39c6b 100644 --- a/src/ch03/Array.ts +++ b/src/ch03/Array.ts @@ -1,23 +1,41 @@ class ArrayMinimum { - constructor(private accumulator: number) { } - + private processor: MinimumProcessor + constructor(private accumulator: number) { + this.processor = new MinimumProcessor(accumulator); + } process(arr: number[]) { - for (let i = 0; i < arr.length; i++) { - if (this.accumulator > arr[i]) { - this.accumulator = arr[i]; - } - return this.accumulator; - } + for (let i = 0; i < arr.length; i++) this.processor.processElement(arr[i]); + return this.processor.getAccumulator(); } } class ArraySum { - constructor(private accumulator: number) { } + constructor(private processor: SumProcessor) { + this.processor = new SumProcessor(accumulator); + } process(arr: number[]) { - for (let i = 0; i < arr.length; i++) { - this.accumulator += arr[i]; - } + for (let i = 0; i < arr.length; i++) this.processor.processElement(arr[i]); + return this.processor.getAccumulator(); + } +} + +class MinimumProcessor { + constructor(private accumulator: number) { } + getAccumulator() { + return this.accumulator; + } + processElement(e: number) { + if (this.accumulator > e) this.accumulator = e; + } +} + +class SumProcessor { + constructor(private accumulator: number) { } + getAccumulator() { return this.accumulator; } + processElement(e: number) { + this.accumulator += e; + } } From 20ecf29b3d8367aeaf26448809c8b06259e666d4 Mon Sep 17 00:00:00 2001 From: leehoosgg Date: Tue, 2 Jan 2024 15:38:33 +0900 Subject: [PATCH 18/21] =?UTF-8?q?Processor=20=EC=9D=B8=ED=84=B0=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=EB=A5=BC=20=EC=83=9D=EC=84=B1=ED=95=B4=20?= =?UTF-8?q?=EC=9C=A0=EC=82=AC=ED=95=9C=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - --- src/ch03/Array.ts | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/src/ch03/Array.ts b/src/ch03/Array.ts index 0a39c6b..57f98cc 100644 --- a/src/ch03/Array.ts +++ b/src/ch03/Array.ts @@ -1,30 +1,19 @@ -class ArrayMinimum { - private processor: MinimumProcessor - constructor(private accumulator: number) { - this.processor = new MinimumProcessor(accumulator); - } +class BatchProcessor { + constructor(private processor: ElementProcessor) { } process(arr: number[]) { for (let i = 0; i < arr.length; i++) this.processor.processElement(arr[i]); return this.processor.getAccumulator(); } } -class ArraySum { - constructor(private processor: SumProcessor) { - this.processor = new SumProcessor(accumulator); - } - - process(arr: number[]) { - for (let i = 0; i < arr.length; i++) this.processor.processElement(arr[i]); - return this.processor.getAccumulator(); - } +interface ElementProcessor { + processElement(e: number): void; + getAccumulator(): number; } -class MinimumProcessor { +class MinimumProcessor implements ElementProcessor { constructor(private accumulator: number) { } - getAccumulator() { - return this.accumulator; - } + getAccumulator() { return this.accumulator; } processElement(e: number) { if (this.accumulator > e) this.accumulator = e; } @@ -32,9 +21,7 @@ class MinimumProcessor { class SumProcessor { constructor(private accumulator: number) { } - getAccumulator() { - return this.accumulator; - } + getAccumulator() { return this.accumulator; } processElement(e: number) { this.accumulator += e; } From f50acdae1e1ef1bf384cb9070dc9c4295be57202 Mon Sep 17 00:00:00 2001 From: leehoosgg Date: Tue, 2 Jan 2024 15:55:59 +0900 Subject: [PATCH 19/21] =?UTF-8?q?remove=20=ED=95=A8=EC=88=98=EB=A5=BC=20?= =?UTF-8?q?=ED=95=98=EB=82=98=EB=A1=9C=20=ED=86=B5=ED=95=A9=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20=EC=9C=84=ED=95=9C=20=EC=9D=B8=ED=84=B0=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EB=8F=84=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - --- index.ts | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/index.ts b/index.ts index 7762b51..da2200b 100644 --- a/index.ts +++ b/index.ts @@ -206,11 +206,11 @@ class Key1 implements Tile { g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } moveHorizontal(dx: number) { - removeLock1(RawTile.LOCK1); + remove(new RemoveLock1()); moveToTile(playerx + dx, playery); } moveVertical(dy: number) { - removeLock1(RawTile.LOCK1); + remove(new RemoveLock2()); moveToTile(playerx, playery + dy); } update(x: number, y: number) { } @@ -242,11 +242,11 @@ class Key2 implements Tile { g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } moveHorizontal(dx: number) { - removeLock2(RawTile.LOCK2); + remove(new RemoveLock2()); moveToTile(playerx + dx, playery); } moveVertical(dy: number) { - removeLock2(RawTile.LOCK2); + remove(new RemoveLock2()); moveToTile(playerx, playery + dy); } update(x: number, y: number) { } @@ -338,18 +338,22 @@ function transformTile(tile: RawTile) { const inputs: Input[] = []; -function removeLock1(tile: RawTile.LOCK1) { - for (let y = 0; y < map.length; y++) { - for (let x = 0; x < map[y].length; x++) { - if (map[y][x].isLock1) map[y][x] = new Air(); - } - } +interface RemoveStrategy { + check(tile: Tile): boolean; +} + +class RemoveLock1 implements RemoveStrategy { + check(tile: Tile) { return tile.isLock1(); } +} + +class RemoveLock2 implements RemoveStrategy { + check(tile: Tile) { return tile.isLock2(); } } -function removeLock2(tile: RawTile.LOCK2) { +function remove(shouldRemove: RemoveStrategy) { for (let y = 0; y < map.length; y++) { for (let x = 0; x < map[y].length; x++) { - if (map[y][x].isLock2) map[y][x] = new Air(); + if (shouldRemove.check(map[y][x])) map[y][x] = new Air(); } } } From 0983348eed8dd9c8043d29662f45ddeebc113a48 Mon Sep 17 00:00:00 2001 From: leehoosgg Date: Tue, 2 Jan 2024 16:07:07 +0900 Subject: [PATCH 20/21] =?UTF-8?q?Key=20=EC=99=80=20Lock=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=EC=9D=98=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ts 내부에 동일 클래스명이 있어서 Locker 로 변경 --- index.ts | 110 ++++++++++++++++++++++--------------------------------- 1 file changed, 44 insertions(+), 66 deletions(-) diff --git a/index.ts b/index.ts index da2200b..1012017 100644 --- a/index.ts +++ b/index.ts @@ -195,71 +195,66 @@ class Box implements Tile { } } -class Key1 implements Tile { - isAir() { return false; } - isKey1() { return true; } - isLock1() { return false; } - isKey2() { return false; } - isLock2() { return false; } - draw(g: CanvasRenderingContext2D, x: number, y: number) { - g.fillStyle = '#ffcc00'; - g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); - } - moveHorizontal(dx: number) { - remove(new RemoveLock1()); - moveToTile(playerx + dx, playery); - } - moveVertical(dy: number) { - remove(new RemoveLock2()); - moveToTile(playerx, playery + dy); - } - update(x: number, y: number) { } +interface RemoveStrategy { + check(tile: Tile): boolean; } -class Lock1 implements Tile { - isAir() { return false; } - isKey1() { return false; } - isLock1() { return true; } - isKey2() { return false; } - isLock2() { return false; } - draw(g: CanvasRenderingContext2D, x: number, y: number) { - g.fillStyle = '#ffcc00'; - g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); +class RemoveLock1 implements RemoveStrategy { + check(tile: Tile) { return tile.isLock1(); } +} + +class RemoveLock2 implements RemoveStrategy { + check(tile: Tile) { return tile.isLock2(); } +} + +function remove(shouldRemove: RemoveStrategy) { + for (let y = 0; y < map.length; y++) { + for (let x = 0; x < map[y].length; x++) { + if (shouldRemove.check(map[y][x])) map[y][x] = new Air(); + } } - moveHorizontal(dx: number) { } - moveVertical(dy: number) { } - update(x: number, y: number) { } } -class Key2 implements Tile { +class Key implements Tile { + constructor( + private color: string, + private removeStrategy: RemoveStrategy + ) { } + isAir() { return false; } - isKey1() { return false; } + isKey1() { return true; } isLock1() { return false; } - isKey2() { return true; } + isKey2() { return false; } isLock2() { return false; } draw(g: CanvasRenderingContext2D, x: number, y: number) { - g.fillStyle = '#00ccff'; - g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); + g.fillStyle = this.color; + g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } moveHorizontal(dx: number) { - remove(new RemoveLock2()); + remove(this.removeStrategy); moveToTile(playerx + dx, playery); } moveVertical(dy: number) { - remove(new RemoveLock2()); + remove(this.removeStrategy); moveToTile(playerx, playery + dy); } update(x: number, y: number) { } } -class Lock2 implements Tile { +class Locker implements Tile { + constructor( + private color: string, + private lock1: boolean, + private lock2: boolean + ) { } + isAir() { return false; } isKey1() { return false; } - isLock1() { return false; } + isLock1() { return this.lock1 } isKey2() { return false; } - isLock2() { return true; } + isLock2() { return this.lock2; } draw(g: CanvasRenderingContext2D, x: number, y: number) { - g.fillStyle = '#00ccff'; + g.fillStyle = this.color g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } moveHorizontal(dx: number) { } @@ -318,6 +313,9 @@ function assertExhausted(x: never): never { throw new Error("Unexpected Object: " + x); } + + + function transformTile(tile: RawTile) { switch(tile) { case RawTile.AIR: return new Air(); @@ -325,10 +323,10 @@ function transformTile(tile: RawTile) { case RawTile.FALLING_BOX: return new Stone(new Falling); case RawTile.FALLING_STONE: return new Stone(new Falling); case RawTile.FLUX: return new Flux(); - case RawTile.KEY1: return new Key1(); - case RawTile.KEY2: return new Key2(); - case RawTile.LOCK1: return new Lock1(); - case RawTile.LOCK2: return new Lock2(); + case RawTile.KEY1: return new Key('#ffcc00', new RemoveLock1()); + case RawTile.KEY2: return new Key('#00ccff', new RemoveLock2()); + case RawTile.LOCK1: return new Locker('#ffcc00', true, false); + case RawTile.LOCK2: return new Locker('#00ccff', false, true); case RawTile.PLAYER: return new Player(); case RawTile.STONE: return new Stone(new Resting); case RawTile.UNBREAKABLE: return new Unbreakable(); @@ -338,26 +336,6 @@ function transformTile(tile: RawTile) { const inputs: Input[] = []; -interface RemoveStrategy { - check(tile: Tile): boolean; -} - -class RemoveLock1 implements RemoveStrategy { - check(tile: Tile) { return tile.isLock1(); } -} - -class RemoveLock2 implements RemoveStrategy { - check(tile: Tile) { return tile.isLock2(); } -} - -function remove(shouldRemove: RemoveStrategy) { - for (let y = 0; y < map.length; y++) { - for (let x = 0; x < map[y].length; x++) { - if (shouldRemove.check(map[y][x])) map[y][x] = new Air(); - } - } -} - function moveToTile(newx: number, newy: number) { map[playery][playerx] = new Air(); map[newy][newx] = new Player(); From 7474c003d652f5c69fb51ed901122856aa4bc434 Mon Sep 17 00:00:00 2001 From: leehoosgg Date: Tue, 2 Jan 2024 16:29:46 +0900 Subject: [PATCH 21/21] =?UTF-8?q?=EC=A0=84=EB=9E=B5=20=ED=8C=A8=ED=84=B4?= =?UTF-8?q?=20=EC=A0=81=EC=9A=A9=EC=9D=84=20=EC=9C=84=ED=95=9C=20KeyConfig?= =?UTF-8?q?uration=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EB=8F=84=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - --- index.ts | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/index.ts b/index.ts index 1012017..d10776f 100644 --- a/index.ts +++ b/index.ts @@ -215,11 +215,22 @@ function remove(shouldRemove: RemoveStrategy) { } } -class Key implements Tile { +class KeyConfiguration { constructor( private color: string, + private _1: boolean, private removeStrategy: RemoveStrategy ) { } + + getColor() { return this.color } + is1() { return this._1 } + getRemoveStrategy() { return this.removeStrategy }; +} + +class Key implements Tile { + constructor( + private keyConf: KeyConfiguration + ) { } isAir() { return false; } isKey1() { return true; } @@ -227,15 +238,15 @@ class Key implements Tile { isKey2() { return false; } isLock2() { return false; } draw(g: CanvasRenderingContext2D, x: number, y: number) { - g.fillStyle = this.color; + g.fillStyle = this.keyConf.getColor(); g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } moveHorizontal(dx: number) { - remove(this.removeStrategy); + remove(this.keyConf.getRemoveStrategy()); moveToTile(playerx + dx, playery); } moveVertical(dy: number) { - remove(this.removeStrategy); + remove(this.keyConf.getRemoveStrategy()); moveToTile(playerx, playery + dy); } update(x: number, y: number) { } @@ -243,18 +254,16 @@ class Key implements Tile { class Locker implements Tile { constructor( - private color: string, - private lock1: boolean, - private lock2: boolean + private keyConf: KeyConfiguration ) { } isAir() { return false; } isKey1() { return false; } - isLock1() { return this.lock1 } + isLock1() { return this.keyConf.is1() } isKey2() { return false; } - isLock2() { return this.lock2; } + isLock2() { return !this.keyConf.is1() } draw(g: CanvasRenderingContext2D, x: number, y: number) { - g.fillStyle = this.color + g.fillStyle = this.keyConf.getColor(); g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } moveHorizontal(dx: number) { } @@ -262,6 +271,9 @@ class Locker implements Tile { update(x: number, y: number) { } } +const YELLOW_KEY = new KeyConfiguration("#ffcc00", true, new RemoveLock1()); +const LIGHTGREEN_KEY = new KeyConfiguration("#ccffcc", false, new RemoveLock2()); + // Input Enum & Interface & Class enum RawInput { UP, DOWN, LEFT, RIGHT @@ -323,10 +335,10 @@ function transformTile(tile: RawTile) { case RawTile.FALLING_BOX: return new Stone(new Falling); case RawTile.FALLING_STONE: return new Stone(new Falling); case RawTile.FLUX: return new Flux(); - case RawTile.KEY1: return new Key('#ffcc00', new RemoveLock1()); - case RawTile.KEY2: return new Key('#00ccff', new RemoveLock2()); - case RawTile.LOCK1: return new Locker('#ffcc00', true, false); - case RawTile.LOCK2: return new Locker('#00ccff', false, true); + case RawTile.KEY1: return new Key(YELLOW_KEY); + case RawTile.KEY2: return new Key(LIGHTGREEN_KEY); + case RawTile.LOCK1: return new Locker(YELLOW_KEY); + case RawTile.LOCK2: return new Locker(LIGHTGREEN_KEY); case RawTile.PLAYER: return new Player(); case RawTile.STONE: return new Stone(new Resting); case RawTile.UNBREAKABLE: return new Unbreakable();