#define __SPACE_TORUNEEDO__ // ノーマルテトリスの場合はこの行を無効にする。
#define __WIN_DOWS__ // linux でコンパイルする場合はこの行を無効にする。
// テトリス
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __WIN_DOWS__
// ---------- windwos依存部分 ----------
#include <windows.h>
#include <conio.h>
// キーボードからの一文字入力(待ち無し)
int gc(void){
int r=0,i;
if(kbhit()){r = getch();}
i=32;while(i-->0){if(kbhit()){getch();}}//余分なキーリピート分を捨てる
return r;
}
// 1/60秒間、処理を停止する(ウエイト処理)
// 引数i * 1/60秒間の停止
void s6(int i){Sleep(16*i);}
// 画面の文字をすべてクリアーする関数
void cl(void){}
// カーソル位置をセットする関数
void sc(int x, int y){
COORD a; a.X=x; a.Y=y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),a);
}
// ---------- windows依存部分ここまで ----------
#else
// ---------- linux依存部分(たぶんwindowsだと、書き方違う部分) ----------
// キーボードからの一文字入力(待ち無し)
#include <termios.h>
int gc(void) {
struct termios t0, t1;
tcgetattr(fileno(stdin), &t0);
t1 = t0;
t1.c_lflag &= ~ICANON;
t1.c_cc[VMIN] = 0;
tcsetattr(fileno(stdin), TCSANOW, &t1);
int r = getchar();
int i = 32;
while(i-- > 0){
getchar();
} //余分なキーリピート分を捨てる
tcsetattr(fileno(stdin), TCSANOW, &t0);
return r;
}
// 1/60秒間、処理を停止する(ウエイト処理)
// 引数i * 1/60秒間の停止
#include <time.h>
void s6(int i) {
struct timespec req = {0,16*1000*1000}, rem;
req.tv_nsec *= i;
nanosleep(&req, &rem);
}
// 画面の文字をすべてクリアーする関数
void cl(void) {
printf("%c[2J", 0x1B);
}
// カーソル位置をセットする関数
void sc(int x, int y) {
printf("%c[%d;%dH", 0x1b, y+1, x+1);
}
// ---------- linux依存部分ここまで ----------
#endif // __WIN_DOWS__
// ---------- テトリス本体部分(libcのみ) ----------
#define N 0xE007
#define F 0xFFFF
struct Player {
unsigned short V[32], _V[32], B[32], _B[32], M, _M;
int x, y;
int c;
int Score, Lines, Level;
int down_flag, gameover_flag;
};
void initB(struct Player* a)
{
unsigned short* p = a->B;
int i = 24;
while(i-- > 0){*p++ = N;}
*p = F;
}
int delB(struct Player* a)
{
static int score_table[] = {0, 40, 100, 300, 1200};
unsigned short* p = a->B + 4;
int cnt = 0;
int j = 20;
while(j-->0){
if(*p == 0xFFFF){
*p = 0xE007;
cnt++;
}
p++;
}
a->Score += score_table[cnt];
a->Lines += cnt;
return cnt;
}
void sortB(struct Player* a)
{
unsigned short *p, *q;
p = q = a->B + 4 + 20 - 1;
int i, j;
i = j = 20;
while(j-- > 0) {
if(*p != N) {
*q-- = *p | N;
i--;
}
p--;
}
j = i;
while(j-- > 0) {
*q-- = N;
}
}
void rot_r_M(struct Player* a)
{
static int trans_table[] = {2,5,8,11, -3,0,3,6, -8,-5,-2,1, -9,-6,-3,16};
int* t = trans_table;
unsigned short tmp = a->M;
a->M = 0;
unsigned short mask = 1;
int i = 16;
while(i-- > 0) {
a->M |= (*t > 0) ? (tmp & mask) << *t : (tmp & mask) >> -(*t);
mask <<= 1;
t++;
}
}
void rot_l_M(struct Player* a)
{
rot_r_M(a);
rot_r_M(a);
rot_r_M(a);
}
void nextM(struct Player* a)
{
static unsigned short shape_table[] = {0x72, 0x132, 0x462, 0x223, 0x226, 0x2222, 0x33};
a->x = 3;
a->y = -2;
a->M = a->_M;
a->_M = shape_table[rand() % 7];
}
void O(int i){
static char outtxt_table[][10]={" ", "回", "\n"};
printf("%s", outtxt_table[i]);
}
void printI(struct Player* a)
{
int x;
sc(0, 4); printf("___");
sc(26, 4); printf("___");
a->Level = (a->Lines / 20) + 1;
sc(0, 25);
printf("[Scr:%6d] [Line:%3d] [Lv:%2d]\n", a->Score, a->Lines, a->Level);
}
int errchkV(struct Player* a)
{
unsigned short* p = a->B;
unsigned short* q = a->V;
int i = 32;
while(i-- > 0) {
if((*q & *p) != *p){
return 1;
}
p++;
q++;
}
p = a->B;
i = 5;
while(i-->0){
if(*p++ != N){
sc(10, 11);
printf(" GameOver ");
sc(0, 28);
a->gameover_flag = 1;
}
}
return 0;
}
int nV(struct Player* a)
{
unsigned short* p = a->B;
unsigned short* q = a->V;
int i = 32;
while(i-- > 0) {*q++ = *p++;}
unsigned short tmp = a->M;
q = a->V + 4 + (a->y - 1);
i = 4;
while(i-- > 0) {
*q++ ^= (tmp & 0xF) << (3 + a->x);
tmp >>= 4;
}
tmp = a->_M;
q = a->V + 1;
i = 4;
while(i-- > 0) {
*q++ ^= (tmp & 0xF) << 10;
tmp >>= 4;
}
return errchkV(a);
}
void write_m_B(struct Player* a)
{
unsigned short tmp = a->M;
unsigned short* q = a->B + 4 + (a->y - 1);
int i = 4;
while(i-->0){
*q++ ^= (tmp & 0xF) << (3 + a->x);
tmp >>= 4;
}
}
void initV(struct Player* a)
{
int j = 32;
while(j-- > 0) {a->V[j] = 0;}
}
void printV(struct Player* a)
{
int cnt=0;
unsigned short* q = a->_V;
unsigned short* p = a->V;
int j = 0;
while(j < 25) {
unsigned short mask = 1;
int i = 0;
while(i < 16) {
if((*p & mask) != (*q & mask)){
sc(i * 2, j);
if(*p & mask) {
O(1);
}
else{
O(0);
}
cnt++;
}
mask <<= 1;
i++;
}
p++;
q++;
j++;
}
j = 32;
while(j-- > 0) {a->_V[j] = a->V[j];}
if(cnt > 0){sc(0,26);}
fflush(stdout);
}
void clearV(struct Player* a){
int j = 32;
while(j-- > 0) {a->_V[j] = ~(a->V[j]);}
}
void controlT(struct Player* a){
int key = gc();
if(key == 'n'){
a->y++;
if(a->down_flag > 0){a->down_flag = 999;}
}
else if(key == ' '){
while(!nV(a)){
a->y++;
}
a->down_flag = 100;
}
else{
if(a->c++ >= 400 * (1.0 / (a->Level * a->Level))) {
a->y++;
a->c=0;
}
}
if(key == 'j'){
a->x--;
if(nV(a)){
a->x++;
}
}
if(key == 'k'){
a->x++;
if(nV(a)){
a->x--;
}
}
if(key == 'f'){
rot_r_M(a);
if(nV(a)){
rot_l_M(a);
}
}
if(key == 'd'){
rot_l_M(a);
if(nV(a)){
rot_r_M(a);
}
}
}
void printOP(void)
{
sc(9,6);printf(" テ ト リ ス ");
sc(5,9);printf(" prease enter start ");
sc(4,12);printf(" 操作方法 ");
#ifdef __SPACE_TORUNEEDO__
sc(6,5);printf(" スペーストルネード ");
sc(4,13);printf(" <j>:左へトルネード ");
sc(4,14);printf(" <k>:右へトルネード ");
sc(4,15);printf(" <n>:仮想ダウン ");
sc(4,17);printf(" <f>:右ローリング ");
sc(4,18);printf(" <d>:左ローリング ");
sc(4,19);printf(" <space> : アタック ");
#else
sc(4,13);printf(" <j>:左へ移動 ");
sc(4,14);printf(" <k>:右へ移動 ");
sc(4,15);printf(" <n>:下ダウン ");
sc(4,17);printf(" <f>:右回転 ");
sc(4,18);printf(" <d>:左回転 ");
sc(4,19);printf(" <space>:ハードドロップ ");
#endif // __SPACE_TORUNEEDO__
sc(4,22);printf(" Copyright2011 >>316 ");
sc(4,23);printf(" BSD license ");
}
struct Player* newPlayer(void)
{
struct Player* a = (struct Player*)malloc(sizeof *a);
a->Score = 0;
a->Lines = 0;
a->Level = 1;
a->M = 0;
a->_M = 0;
a->x = 0;
a->y = 0;
a->c = 0;
a->down_flag = 0;
a->gameover_flag = 0;
return a;
}
int main(void)
{
struct Player* p1 = newPlayer();
int _a; srand((int)&_a);
int fb = 1;
cl();
initV(p1); initB(p1);
nV(p1); printV(p1); printI(p1); printOP();
getchar();gc();
cl(); clearV(p1); printV(p1);
nextM(p1); nextM(p1);
nV(p1); printV(p1); printI(p1);
while(p1->gameover_flag == 0){
controlT(p1);
if(nV(p1)) {
if(p1->down_flag == 0) {p1->down_flag = 1;}
p1->y--;
nV(p1);
if(p1->down_flag > 5){
write_m_B(p1);
nextM(p1);
if(delB(p1)) {nV(p1); printV(p1); printI(p1); s6(15); sortB(p1);}
nV(p1); printV(p1); s6(8);
p1->down_flag = 0;
}
else{
p1->down_flag++;
}
}
#ifdef __SPACE_TORUNEEDO__
{
#else
if(fb > 0) {
#endif // __SPACE_TORUNEEDO__
int _y = p1->y;
while(!nV(p1)) {
p1->y++;
}
p1->y--;
#ifdef __SPACE_TORUNEEDO__
if(p1->y - _y > 0){
#else
if(p1->y - _y > 4){
#endif // __SPACE_TORUNEEDO__
nV(p1);
}
else{
p1->y = _y;
nV(p1);
}
p1->y = _y;
}
printV(p1);
s6(1);
fb = -fb;
}
free(p1); p1 = 0;
return 0;
}
// 操作方法:
// j,k 左右の移動 d,f 左右の回転 n 下移動 スペース ハードドロップ Ctrl+c 終了