본문 바로가기

삽질한것들

[javascript] Array.fill 포인터 문제

this.state = {
      stage: new Array(stageX).fill(
		new Array(stageY).fill({ background: '', settle: false })
      )
      ,
      ....
}

자 요놈은 Tetris에서 state constructor 내부 분장이다. 실행시키면 다음과 같은 결과가 나온다.

 

 

concatStageByBlock ({ pos, background }: { pos: [number, number][]; background: string }, isSettle: boolean, stage?: ModelStage): ModelStage {
    const copyStage = stage ? [...stage] : [...this.state.stage]

    pos.forEach(posItem => {
      pos.forEach(posItem => {
	      copyStage[posItem[0]][posItem[1]] = {
	        background,
	        settle: isSettle
      	  }
      })
    })

    return copyStage
  }

요놈은 { pos: [[0, 1], [0, 2], [0, 3]], background: 'red' } 등을 받으면 위 stage와 합쳐서 새로운 stage를 내보내는 함수다.

 

그럼 이제 테스트를 해보겠다.

 

/*  block.ts */
const blocks: ModelBlock[] = [
  // ㄱ
  {
    shape: [
      [true, true, true],
      [true, false, false],
      [false, false, false]
    ],
    background: '#186BD6'
  },
  {
    shape: [
      [true, false, false],
      [true, true, true],
      [false, false, false]
    ],
    background: '#DE651B'
  },
  // ㄱ + ㄴ
  {
    shape: [
      [false, true, false],
      [true, true, false],
      [true, false, false]
    ],
    background: '#ED5056'
  },
  {
    shape: [
      [true, false, false],
      [true, true, false],
      [false, true, false]
    ],
    background: '#4ABA54'
  },
  // ㅡ
  {
    shape: [
      [true, true, true, true],
      [false, false, false, false],
      [false, false, false, false],
      [false, false, false, false]
    ],
    background: '#68C5DB'
  },
  // ㅗ
  {
    shape: [
      [true, false, false],
      [true, true, false],
      [true, false, false]
    ],
    background: '#C57CEA'
  },
  // ㅁ
  {
    shape: [
      [true, true],
      [true, true]
    ],
    background: '#F6C643'
  }
]

const getBlock = (): ModelBlock => {
  return blocks[Math.floor(Math.random() * blocks.length)]
}


/* stage.tsx */

... 
  concatStageByBlock ({ pos, background }: { pos: [number, number][]; background: string }, isSettle: boolean, stage?: ModelStage): ModelStage {
    const copyStage = stage ? [...stage] : [...this.state.stage]

    pos.forEach(posItem => {
      pos.forEach(posItem => {
	      copyStage[posItem[0]][posItem[1]] = {
	        background,
	        settle: isSettle
      	  }
      })
    })

    return copyStage
  }
 
  constructor (props: StageProps) {
    super(props)

    this.state = {
      stage:
        this.concatStageByBlock({
          pos: this.shapeBlockPosPareser(props.userBlock),
          background: props.userBlock.background
        }, false, props.stage)
      ,
      userBlock: props.userBlock,
      predictionBlock: props.predictionBlock
    }
  }
...

요렇게 대강 랜덤으로 블럭 가져오는 함수랑 연결해서 stage가 만들어줬을때 블럭 하나를 그려줘봤다.

 

 

결과화면

엌ㅋㅋㅋㅋㅋ

결과화면을 보면 통채로 바뀐걸 볼수있다. 이걸로 한참 삽질하다가 MDN 문서에 나와있는 Array.fill을 보면 새 Array를 만들어줬을때 fill에 넘겨준 값이 객체인경우 같은 포인터를 참조한다는것을 알수 있었다.

 

 

빠르게 바꿔주고...

stage: new Array(stageX).fill(
   new Array(stageY).fill({ background: '', settle: false })
)

// 요부분을

stage: Array.from(new Array(stageX), () => new Array(stageY).fill({ backgrond: '', settle: false }))

// 이렇게 바꿔줫다. map을 써도 된다!

삽질 끝....

반응형

'삽질한것들' 카테고리의 다른 글

wsl2 localhost <=> wsl2 host  (0) 2020.12.10
BACKEND DEVOPS 세팅 삽질  (0) 2020.10.29
Vue extends, mixin의 "자세한" 차이  (0) 2020.08.12
vue cli 3 sass resource 공유  (0) 2020.08.10