코드스피츠 74 4회차
프로그램 짤때는 권한과 책임이 일치하게 짜야 된다. 권한과 책임이 일치하면 그것을 역활이라고 한다.
TETRIS
객체후보
- STAGE(현재 스테이지 정보)
- SCORE(점수 및 계산법)
- BLOCK(범용 블록정의) - 색깔, 회전
- 게임본체
- 범용 패널
- 시작화면
- 스테이지 종료
- 죽음
- 클리어
- 결과 화면
추상화 
- 일반화(카테고라이즈) - 기준점은 역활이다
- 모델링 - 기억해야만 하는것
- 그룹핑 - 랜덤하게 묶이는것(권한)
직접 통신 방법 보다 인터페이스를 통해서 통신해야 된다. 수정에 열려있다.
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 
 | const Stage = class{
 init(listener){
 this.listener = listener;
 }
 clear(){
 this.stage = 0;
 this.next();
 }
 next(){
 if(this.stage++ < Stage.maxStage){
 this.speed = 500 - 450 * this.stage / Stage.maxStage;
 this.listener();
 }
 }
 [Symbol.toPrimitive](hint){
 return `<div>Stage ${this.stage}</div>`;
 }
 };
 
 Stage.maxStage = 20;
 
 const Score = class{
 init(listener){
 this.listener = listener;
 }
 clear(){
 this.curr = this.total = 0;
 }
 add(line, stage){
 const score = parseInt((stage * 5) * (2 * line));
 this.curr += score, this.total += score;
 this.listener();
 }
 [Symbol.toPrimitive](hint){
 return `<div>Stage ${this.curr} / ${this.total}</div>`;
 }
 };
 
 | 
블록 부모 클래스 정의
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | const Block  = class{
 constructor(color){
 Object.assign(this,{color, rotate:0});
 }
 left(){
 if(--this.rotate <0){
 this.rotate = 3;
 }
 }
 right(){
 if(++this.rotate <3){
 this.rotate = 0;
 }
 }
 getBlock(){
 throw 'override!';
 }
 };
 
 
 | 
블록 자식클래스 정의
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 
 | const blocks = [class extends Block, ....];
 
 class extends Block{
 constructor(){
 super('#f8cbad');
 }
 getBlock(){
 return this.rotate % 2 ? [[1],[1],[1],[1]] : [[1,1,1,1]]
 }
 
 };
 
 
 class extends Block{
 constructor(){
 super('#ffe699');
 }
 getBlock(){
 switch (this.rotate){
 case 0:return [[0,1,0],[1,1,1]];
 case 1:return [[1,0],[1,1],[1,0]];
 case 2:return [[1,1,1],[0,1,0]];
 case 3:return [[0,1],[1,1],[0,1]];
 }
 }
 
 };
 
 
 | 
위에서 자식 클래스에서 중복이 생김
부모 클래스에 추가작업
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | const Block  = class{
 constructor(color){
 Object.assign(this,{color, rotate:0});
 }
 left(){
 if(--this.rotate <0){
 this.rotate = 3;
 }
 }
 right(){
 if(++this.rotate <3){
 this.rotate = 0;
 }
 }
 getBlock(){
 return this.blocks[this.rotate];
 }
 };
 
 
 | 
랜더러 생성
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 
 | const Renderer = class{
 constructor(col, row, base, back){
 Object.assign(this,{col, row, base, back, blocks:[]});
 }
 
 clear(){
 throw 'override!';
 }
 
 render(data){
 if(!(data instanceof Data)) throw 'invalid data';
 this._render(data);
 }
 _render(data){
 throw 'override!';
 }
 };
 
 
 | 
데이터 생성
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | const Data = class extends Array{
 constructor(col, row,){
 Object.assign(this,{col, row});
 }
 
 cell(row,col,color){
 if(row > this.row || col > this.col) throw 'invalid';
 (this[row] || (this[row] = []))[col] = color;
 }
 
 row(row, ...color){
 color.forEach((v, i)=> this.cell(row,i,v));
 }
 
 all(...rows){
 rows.forEach((v, i)=> this.row(i, ...v));
 }
 };
 
 
 | 
랜더러 상속후 구현
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 
 | const el = el=>document.createElement(el);
 const back = (s, v){
 s.backgroundColor = v;
 };
 
 const TableRenderer = class extends Renderer{
 constructor(col, row, base, back, style){
 super(col, row, el('table'), back)
 const {col, base, blocks} = this;
 base.style.cssText = style;
 let i = this.row;
 while (i--){
 const tr = base.appendChild(el('tr'));
 const curr = [];
 let j = col;
 blocks.push(curr);
 while (j--) curr.push(tr.appendChild(el('td')).style);
 }
 }
 clear(){
 this.blocks.forEach(curr=>curr.forEach(s=>back(s,this.back)));
 }
 _render(v){
 this.blocks.forEach((curr,i)=>curr.forEach((s,j)=>back(s, v[i][j])));
 }
 
 };
 
 
 | 
캔버스
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 
 | const el = el=>document.createElement(el);
 const back = (s, v){
 s.backgroundColor = v;
 };
 
 const CanvasRenderer = class extends Renderer{
 constructor(col, row, back, style){
 super(col, row, el('canvas'))
 const {col, base, blocks} = this;
 base.style.cssText = style;
 Object.assign(this, {
 width:base.width = parseInt(base.style.width),
 height:base.height = parseInt(base.style.height),
 cellSize:[base.width/col,base.height/row],
 ctx:base.getContext('2D')
 });
 }
 clear(){
 this.ctx.clearRect(0,0,this.width, this.height);
 }
 _render(v){
 this.clear();
 const {col, ctx, cellSize:[w,h]} = this;
 let {row:i} = this;
 while (i--){
 let j = col;
 while (j--){
 ctx.fillStyle = v[i][j];
 ctx.fillRect(j*w,I*h,w,h);
 }
 }
 }
 
 };
 
 
 | 
참조