Skip to content

Instantly share code, notes, and snippets.

@shiracamus
Last active January 13, 2019 06:19
Show Gist options
  • Save shiracamus/464a0cee29a7ddb13ef8aeb2d81c0765 to your computer and use it in GitHub Desktop.
Save shiracamus/464a0cee29a7ddb13ef8aeb2d81c0765 to your computer and use it in GitHub Desktop.
//
// 昔懐かし、CBM-3032のようなキャラクタゲームを
// ncurseswで実現。
// Raging robots.
//
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
#include <locale.h>
#include <ncursesw/ncurses.h>
#define NUM_ROCK (120)
#define NUM_ROBOT (12)
#define rnd(x) (rand() % (x))
#define center(x) ((x) / 2)
typedef const char * const String;
typedef int X, Y, Width, Height;
// class Symbol extends String {
typedef String Symbol;
static Symbol ROCK = "#";
static Symbol ROBOT = "@";
static Symbol PLAYER = "O";
static Symbol CRASH = "X";
static Symbol SPACE = " ";
// }
// class Screen {
struct {
Width width;
Height height;
} screen;
void screen_open() {
initscr(); // 画面初期化
noecho(); // キーボードエコーなし
curs_set(0); // カーソル非表示
getmaxyx(stdscr, screen.height, screen.width); // 画面サイズ取得
screen.width /= 2; // 全角文字表示で2倍幅になるので画面幅を半分に見立てる
}
void screen_close() {
endwin();
}
void screen_text(X x, Y y, String message) {
move(y, x * 2);
addstr(message);
}
bool screen_contains(X x, Y y) {
return 0 <= x && x < screen.width
&& 0 <= y && y < screen.height;
}
// }
// class Character {
typedef struct {
bool is_vaild;
X x;
Y y;
} character_t, *Character;
void Character_put(Character this, X x, Y y, Symbol symbol) {
this->is_vaild = true;
this->x = x;
this->y = y;
screen_text(this->x, this->y, symbol);
}
void Character_put_random(Character this, Symbol symbol) {
Character_put(this, rnd(screen.width), rnd(screen.height), symbol);
}
void Character_put_center(Character this, Symbol symbol) {
Character_put(this, center(screen.width), center(screen.height), symbol);
}
bool Character_hit(Character this, const Character target) {
return this != target
&& target->is_vaild
&& this->x == target->x
&& this->y == target->y;
}
// }
// class Rock extends Character {
typedef character_t rock_t;
typedef Character Rock;
static rock_t rocks[NUM_ROCK];
static const Rock rocks_end = &rocks[NUM_ROCK];
void rocks_init() {
for (Rock rock = rocks; rock != rocks_end; rock++)
Character_put_random(rock, ROCK);
}
bool rocks_hit(const Character target) {
for (Rock rock = rocks; rock != rocks_end; rock++)
if (Character_hit(rock, target)) return true;
return false;
}
// }
// class Robot extends Character {
typedef character_t robot_t;
typedef Character Robot;
static robot_t robots[NUM_ROBOT];
static const Robot robots_end = &robots[NUM_ROBOT];
void robots_init() {
for (Robot robot = robots; robot != robots_end; robot++)
Character_put_random(robot, ROBOT);
}
bool robots_hit(const Character target) {
for (Robot robot = robots; robot != robots_end; robot++)
if (Character_hit(robot, target)) return true;
return false;
}
void robots_move(const Character target) {
for (Robot robot = robots; robot != robots_end; robot++) {
if (!robot->is_vaild) continue;
// 現表示消去
screen_text(robot->x, robot->y, SPACE);
// ターゲット(プレイヤー)を追いかけるように移動
if (robot->x < target->x) robot->x += 1;
if (robot->x > target->x) robot->x -= 1;
if (robot->y < target->y) robot->y += 1;
if (robot->y > target->y) robot->y -= 1;
// 他のロボットや岩に衝突してなければ表示
if (robots_hit(robot) || rocks_hit(robot))
robot->is_vaild = false;
if (robot->is_vaild)
screen_text(robot->x, robot->y, ROBOT);
}
}
bool robots_are_wiped() {
for (Robot robot = robots; robot != robots_end; robot++)
if (robot->is_vaild) return false;
return true;
}
// }
// class Player extends Character {
typedef character_t player_t;
typedef Character Player;
static player_t player;
void player_init() {
Character_put_center(&player, PLAYER);
}
void player_move() {
player_t move = player;
do {
switch(getch()) {
case '7': move.x -= 1, move.y -= 1; break;
case '8': move.x += 0, move.y -= 1; break;
case '9': move.x += 1, move.y -= 1; break;
case '4': case 'u': move.x -= 1, move.y += 0; break;
case '5': case 'i': move.x += 0, move.y += 0; break;
case '6': case 'o': move.x += 1, move.y += 0; break;
case '1': case 'j': move.x -= 1, move.y += 1; break;
case '2': case 'k': move.x += 0, move.y += 1; break;
case '3': case 'l': move.x += 1, move.y += 1; break;
default: continue;
}
} while (false);
if (screen_contains(move.x, move.y)) {
screen_text(player.x, player.y, SPACE);
player = move;
screen_text(player.x, player.y, PLAYER);
}
}
bool player_is_crashed() {
return robots_hit(&player) || rocks_hit(&player);
}
// }
// class Game {
void game_show_instruction() {
clear();
printw("Raging robots Ver 0.8\n"); // printwで、stdscrに出力します。
printw("Mission : survive from raging robots.\n");
printw("%s -- 岩 , 自分やロボットが当たると死ぬ\n", ROCK);
printw("%s -- ロボット , 段階的に追い詰めてくるロボット\n", ROBOT);
printw("%s -- プレイヤー , キーで操作し、岩にロボットを誘って\n", PLAYER);
printw(" 消滅させよう。\n");
printw("\n");
printw("キーコントロール テンキー \n");
printw(" 7 8 9 7 8 9 \n");
printw(" ↖ ↑ ↗ ↖ ↑ ↗ \n");
printw(" u← i→ o 4← 5→ 6 \n");
printw(" ↙ ↓ ↘ ↙ ↓ ↘ \n");
printw(" j k l 1 2 3 \n");
printw("\n");
printw(" 'i' と '5' は、自分が動かず、ロボットが動くだけです。\n");
printw(" Ctrl-Cで、止まります。\n");
printw(" Good Luck\n");
printw("Hit a key to start game\n");
getch();
}
void game_init() {
clear();
rocks_init();
robots_init();
player_init();
// 処理簡略化のため、特に岩とロボットと、プレイヤーの
// 初期位置のバッティングは考えないこととします。
}
typedef enum { WIN, LOSE } GameResult;
GameResult game_fight() {
while (true) {
player_move();
if (player_is_crashed()) return LOSE;
robots_move(&player);
if (player_is_crashed()) return LOSE;
if (robots_are_wiped()) return WIN;
}
}
void game_play() {
game_show_instruction();
game_init();
if (game_fight() == WIN) {
screen_text(0, 0, "You Win!!\n");
} else{
screen_text(player.x, player.y, CRASH);
screen_text(0, 0, "You Lose.\n");
}
}
// }
bool try_again() {
printw("Try Again? [y/n] ");
while (true) {
int c = getch();
if (c == 'y') return true;
if (c == 'n') return false;
}
}
int main() {
setlocale(LC_ALL, "");
srand((unsigned)time(NULL));
screen_open();
do {
game_play();
} while (try_again());
screen_close();
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment