본문으로 건너뛰기

c-implementation

테트리스 by C 언어

이 글은 기존 블로그의 원문에서 가져왔습니다. 원문 작성일: 2021-11-02

양옆 화살표와 왼쪽 쉬프트로 할 수 있는 테트리스입니다.

#include <stdio.h>
#include <time.h>
#include <windows.h>
#include <stdlib.h>
 
int btn_left = 2, btn_right=3, btn_3=4;
int x, y, rotat, blockType;
void sumList(int block_list[16][10], int map_list[16][10]);
int is_crash(int list1[16][10], int list2[16][10]);
 
int what_height(int map[16][10]){
  // 가장 높이 있는 부분의 좌표를 반환한다. 
  // return : 가장 높이 있는 부분의 좌표 
  // parameter : 배경 데이터  
  for(int i = 15; i>=0; i--){
    for(int j=0; j<10; j++){
      if(map[i][j]) break;
      else return(i);
    }
  }
}
 
void rotate_block(int block_list[16][10], int map_list[16][10]){
     // 블럭을 x, y를 중심으로 90도 돌린다. 
     // return : 없음
    // parameter : 블럭 데이터, 배경 데이터
    int list[16][10];
      for (int r=0; r<16; r++){
        for (int c=0; c<10; c++){
              list[r][c] = block_list[r][c]; 
        }
      }
      int lastRotat=rotat;
    if (blockType==1){
        if (rotat==0){
            rotat=1;
            block_list[y][x-1]=0;
            block_list[y][x-2]=0;
            block_list[y][x+1]=0;
            block_list[y+1][x]=1;
            block_list[y-1][x]=1;
            block_list[y+2][x]=1;
        }else {
            rotat=0;
            block_list[y][x-1]=1;
            block_list[y][x-2]=1;
            block_list[y][x+1]=1;
            block_list[y+1][x]=0;
            block_list[y-1][x]=0;
            block_list[y+2][x]=0;
        }
    } else if (blockType!=2){
        for (int r=y-1; r<=y+1; r++){
            for (int c=x-1; c<x+1; c++){
                block_list[y][x-1]=list[y+1][x];
                block_list[y][x+1]=list[y-1][x];
                block_list[y+1][x]=list[y][x+1];
                block_list[y-1][x]=list[y][x-1];
                block_list[y+1][x-1]=list[y+1][x+1];
                block_list[y-1][x-1]=list[y+1][x-1];
                block_list[y-1][x+1]=list[y-1][x-1];
                block_list[y+1][x+1]=list[y-1][x+1];
            }
        }
    }
 
  
      if (is_crash(block_list, map_list)){
        for (int r=0; r<16; r++){
              for (int c=0; c<10; c++){
                block_list[r][c] = list[r][c]; 
              }
        }
        rotat = lastRotat;
      }
}
 
void random_block(int block_list[16][10]){
  // 랜덤으로 블럭을 소환한다. 
  //return : 없음  
  //parameter : 블럭 데이터
  srand(time(0)); 
  int num = rand()%7;
  blockType=num;
  switch(num) {
    case 0:
      block_list[0][5]=1;
      block_list[0][4]=1;
      block_list[1][5]=1;
      block_list[1][6]=1;
      y=0; x=5;
      rotat=0;
      break;
    case 1:
      block_list[0][3]=1;
      block_list[0][4]=1;
      block_list[0][5]=1;
      block_list[0][6]=1;
      y=0; x=5;
      rotat=0;
      break;
    case 2:
      block_list[1][4]=1;
      block_list[0][4]=1;
      block_list[0][5]=1;
      block_list[1][5]=1;
      y=0; x=5;
      break;
    case 3:
      block_list[0][5]=1;
      block_list[0][6]=1;
      block_list[1][5]=1;
      block_list[1][4]=1;
      y=0; x=5;
      rotat=0;
      break;
    case 4:
      block_list[0][5]=1;
      block_list[0][6]=1;
      block_list[0][4]=1;
      block_list[1][5]=1;
      y=0; x=5;
      rotat=0;
      break;
    case 5:
      block_list[0][5]=1;
      block_list[0][6]=1;
      block_list[0][4]=1;
      block_list[1][4]=1;
      y=0; x=5;
      rotat=0;
      break;
    case 6:
      block_list[0][5]=1;
      block_list[0][6]=1;
      block_list[0][4]=1;
      block_list[1][6]=1;
      y=0; x=5;
      rotat=0;
      break;
  }
}
 
 
void graphic(int list1[16][10], int list2[16][10]){
  // 블럭 데이터와 배경 데이터를 합쳐서 텍스트로 출력한다. 
  //return : 없음  
  //parameter : 블럭 데이터, 배경 데이터  
  printf("////////////////////////////////////////\n");
  for (int r=0; r<16; r++){
    for (int c=0; c<10; c++){
      printf(" %s", (list1[r][c]||list2[r][c])?"@": ".");
    }
    printf("\n");
  }
  printf("/////////////////////////////////////////\n");
}
 
int is_crash(int list1[16][10], int list2[16][10]){  
  // 블럭 데이터와 배경 데이터가 곂치는 부분이 있는지 확인한다. 
  // return : 곂치는 지에 대한 boolean 값 
  // parameter : 블럭 데이터와 배경 데이터  
  int sum1=0, sum2=0;
  for (int r=0; r<16; r++){
    for (int c=0; c<10; c++){
      if (2==list1[r][c]+list2[r][c]){
        return 1;
      }
    }
  }  
  return 0;
}
 
int drop_block(int block_list[16][10], int map_list[16][10]){
  // 블럭을 한칸 밑으로 이동시키고 밑이 막혔을 때는 그 블럭을 배경에 추가하고 새로운 블럭을 추가한다. 
  // return : 블럭이 밑으로 이동했는지에 대한 boolean 값  
  // 블럭 데이터와 배경 데이터  
  int list[16][10];
  for (int r=0; r<16; r++){
    for (int c=0; c<10; c++){
      list[r][c] = block_list[r][c]; 
    }
  }
  for (int r=14; r>=0; r--){
    for (int c=0; c<10; c++){
      block_list[r+1][c] = block_list[r][c]; 
    }
  }
  for (int c=0; c<10; c++){
    block_list[0][c]=0;
  }
  if (is_crash(block_list, map_list)){
    for (int r=0; r<16; r++){
      for (int c=0; c<10; c++){
        block_list[r][c] = list[r][c]; 
      }
    }
    sumList(block_list, map_list);
    random_block(block_list);
  }else {
    y+=1;
    return 1;
  }
}
 
void sumList(int block_list[16][10], int map_list[16][10]){
  // 블럭데이터에 있는 블럭을 배경 데이터에 추가하고 블럭 데이터는 초기화한다. 
  // return : 없음 
  // parameter : 블럭데이터와 배경데이터  
  for (int r=0; r<16; r++){
    for (int c=0; c<10; c++){
      if (block_list[r][c])
        map_list[r][c]=block_list[r][c];
      block_list[r][c]=0; 
    }
  }
} 
 
void move_block(int block_list[16][10], int map_list[16][10], int moveDirection){
  // 횡방향으로 블럭을 이동시킨다.  
  //return : 없음  
  //parameter : 블럭데이터와 배경데이터, 이동 방향 (왼쪽 -1, 오른쪽 +1) 
  int list[16][10];
  for (int r=0; r<16; r++){
    for (int c=0; c<10; c++){
      list[r][c] = block_list[r][c]; 
    }
  }
 
  for (int r=0; r<16; r++){
     for (int c=(moveDirection==-1?1:9); c!=(moveDirection==-1?10:-1); c=c-moveDirection){
      block_list[r][c+moveDirection] = block_list[r][c];
    }
  }
  
  if (is_crash(block_list, map_list)){
    for (int r=0; r<16; r++){
      for (int c=0; c<10; c++){
        block_list[r][c] = list[r][c]; 
      }
    }
  }else{
    x+=moveDirection;
  }
}
 
void erase_line(int map_list[16][10], int block_list[16][10]){
  // 한 줄이 꽉 찼는지 검사하고 꽉 찼으면 지운다. 
  //return : 없음  
  //parameter : 배경데이터, 블럭데이터  
  for (int r=14; r>0; r--){
    int sumOfLine=0;
    for (int c=1; c<9; c++){
      sumOfLine+=map_list[r][c];
    }
    if (sumOfLine==8){
      for (int r2=r-1; r2>=0; r2--){
        for (int c=0; c<10; c++){
          map_list[r2+1][c] = map_list[r2][c]; 
        }
      }
      graphic(map_list, block_list);
    }
  }
}
 
int main(void){
 
    int map_list[16][10]={
  {1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  {1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  {1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  {1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  {1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  {1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  {1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  {1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  {1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  {1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  {1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  {1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  {1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  {1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  {1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
  {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 
  };
  int block_list[16][10]={
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 
  };
  long currentTime, lastTime=clock(); 
  random_block(block_list);
  while(1){
    currentTime = clock();
 
    erase_line(map_list, block_list);
    
    if (lastTime+1000 <= currentTime){
      drop_block(block_list, map_list);
      graphic(map_list, block_list);
      lastTime=clock();
    }
 
    if (GetAsyncKeyState(VK_LEFT)){
      move_block(block_list, map_list, -1);
      Sleep(500);
    } else if (GetAsyncKeyState(VK_RIGHT)){
      move_block(block_list, map_list, 1);
      Sleep(500);
    } else if (GetAsyncKeyState(VK_LSHIFT)){
        rotate_block(block_list, map_list);
        Sleep(500);
    }
  }
}

결과적으로 아래와 같이 테트리스를 할 수 있다.