Skip to content

Instantly share code, notes, and snippets.

@kazmura11
Last active August 29, 2015 13:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kazmura11/9699645 to your computer and use it in GitHub Desktop.
Save kazmura11/9699645 to your computer and use it in GitHub Desktop.
Hit And Blow (Master Mind) Sample
// ===================================================================
// Created By Kaz Ozzy(fa11enprince)
// テキトーに使ってください。
// Rev1. 2014/06/13
// Rev2. 2014/07/19
// 重大なバグ修正(乱数生成部)
// ===================================================================
#ifdef _WIN32
#define _CRT_SECURE_NO_WARNINGS
#include <ctype.h>
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
// CygwinだとMSゴシックフォントで横棒の幅が微妙なのでハイフンに
// C99以前でもコンパイルできるように…(配列の要素数にconst intダメなんだよね)
// ===================================================================
// 定数
// ===================================================================
#define BUF_SIZ 128
#define ELEMENT_NUM 4
static const char Title[] = "Hit And Blow";
static const char Boxes[] =
" ┌---┐ ┌---┐ ┌---┐ ┌---┐ \n"\
" │ │ │ │ │ │ │ │ \n"\
" └---┘ └---┘ └---┘ └---┘ ";
static const char InputBoxes[] =
" ┌---┐ ┌---┐ ┌---┐ ┌---┐ \n"\
" │ %d │ │ %d │ │ %d │ │ %d │ \n"\
" └---┘ └---┘ └---┘ └---┘ \n";
static const char Explanation[] =
"%dケタの数を当ててね!\n"\
"%dケタの数字をスペースで区切って入力してください(半角)\n"\
"qだけを入力するとこのゲームを終了します。\n"\
"例)Number > 1 2 3 4\n";
// ===================================================================
// プロトタイプ宣言
// ===================================================================
void create_answers(int *answers);
int scan_numbers(int *digits);
int analyze_token(char *input, int *digits);
int judge_bytes_eats(int *digits, int *answers, int *eats, int *bytes);
void print_result(int eats, int bytes);
// ===================================================================
// 答えの乱数を生成
// @return なし
// ===================================================================
void create_answers(int *answers)
{
int random = 0;
unsigned int t = 0;
int i;
int j;
srand((unsigned int)time(NULL));
for (i = 0; i < ELEMENT_NUM; i++)
{
do
{
random = (int)(rand() % 10);
for (j = 0; j < i; j++)
{ // 一致したらやり直し
if (answers[j] == random)
{
break;
}
}
}
while (j < i); // 終了条件:i == j
// -> それぞれ違う数の組み合わせが見つかった!
answers[i] = random;
}
}
// ===================================================================
// 入力文字を読み取る
// @return 1:終了, 0:成功
// ===================================================================
int scan_numbers(int *digits)
{
int ret = 0;
char input_numbers[BUF_SIZ + 1];
printf("Number > ");
fgets(input_numbers, sizeof(input_numbers), stdin);
fflush(stdin); // 余分な入力値を捨てる
ret = analyze_token(input_numbers, digits);
return ret;
}
// ===================================================================
// スペースで区切られた文字を数値に変換する処理
// Hit And Blowの本当の処理とは関係がない
// @return 0:成功, 1:終了
// ===================================================================
int analyze_token(char *input, int *digits)
{
const char Delim = ' ';
int i;
int j;
int len_input = 0;
int len_tmp = 0;
char *tmp;
int elem = 0; // 入力語数 4を想定
int pos = 0; // 現在走査している文字列の先頭位置
int word_seq = 0; // 1語の連続要素数(長さ)
len_input = strlen(input);
if (len_input <= 1)
{
printf("何か入力して下さい。\n");
return 0;
}
// 終了
if (input[0] == 'q')
{
printf("終了します。\n");
return 1;
}
// 末尾の改行を取り除く
input[len_input - 1] = '\0';
// 文字の要素数を数える & 文字列をNULL文字によって分解する
for (i = 0; input[i] != '\0'; i++)
{
if (input[i] == Delim)
{
input[i] = '\0'; // 区切り文字(スペース)をnull文字にする
// 文字の要素が前にあるか?連続スペース対応
if (word_seq > 0)
{
elem++;
}
word_seq = 0;
}
else
{
word_seq++; // スペース以外なら加算
}
}
if (word_seq > 0)
{
elem++; // 最後に文字があれば加算
}
// 要素数OKか?
if (elem != ELEMENT_NUM)
{
printf("スペースで区切って4つ入力してください。\n");
return 0;
}
for (i = 0; i < elem; i++)
{
// NULL文字である限りすっ飛ばす
for (j = pos; input[j] == '\0'; j++)
{
pos++;
}
tmp = &input[pos]; // 分解された各文字にアクセス
len_tmp = strlen(tmp); // その後の長さを取得する
pos += (len_tmp + 1); // 次の位置へ更新する
if (len_tmp != 1)
{
printf("%dケタ目の入力値(%s)は1ケタの数字ではありません。\n",
i + 1, tmp);
return 0;
}
// プロトタイプ宣言は VC/gccともにint isdigit(int c)
#ifdef _WIN32 /* If VC++ (Windows) */
// -1 ~ 255の値を渡さないとダメだからunsignedで!
if (isdigit((unsigned char)tmp) != 0)
#else /* If gcc (Linux) */
if (isdigit(tmp) != 0)
#endif
{
printf("%dケタ目の入力値(%s)は数字ではありません。\n",
i + 1, tmp);
return 0;
}
digits[i] = atoi(tmp);
}
printf(InputBoxes,
digits[0], digits[1], digits[2], digits[3]);
return 0;
}
// ===================================================================
// どれだけeatでどれだけbyteか判定する
// ? Eat(s) ? Byte(s)を表示する
// @return -1: 継続, 0: 終了
// ===================================================================
int judge_bytes_eats(int *digits, int *answers, int *eats, int *bytes)
{
int i;
int j;
*eats = 0;
*bytes = 0;
for (i = 0; i < ELEMENT_NUM; i++)
{
if (digits[i] == answers[i])
{
(*eats)++;
}
for (j = 0; j < ELEMENT_NUM; j++)
{
if (digits[i] == answers[j])
{
(*bytes)++;
}
}
}
return (*eats == ELEMENT_NUM) ? 0 : -1;
}
// ===================================================================
// 結果を表示
// @return なし
// ===================================================================
void print_result(int eats, int bytes)
{
char bufEats[BUF_SIZ] = { 0 };
char bufBytes[BUF_SIZ] = { 0 };
char buf[BUF_SIZ] = { 0 };
if (eats <= 1)
{
sprintf(bufEats, "%d eat, ", eats);
}
else
{
sprintf(bufEats, "%d eats, ", eats);
}
if (bytes <= 1)
{
sprintf(bufBytes, "%d byte.", bytes);
}
else
{
sprintf(bufBytes, "%d bytes.", bytes);
}
sprintf(buf, "%s%s\n", bufEats, bufBytes);
printf(buf);
if (eats == ELEMENT_NUM)
{
printf("正解です!おめでとう\n");
}
}
// ===================================================================
// エントリーポイント
// ===================================================================
int main()
{
int digits[ELEMENT_NUM] = { 0 };
int answers[ELEMENT_NUM] = { 0 };
int eats = 0;
int bytes = 0;
int is_clear = 0;
int ret = 0;
printf("%s\n", Title);
printf(Explanation, ELEMENT_NUM, ELEMENT_NUM);
printf("%s\n", Boxes);
create_answers(answers);
while (1)
{
#ifdef _DEBUG
printf("答え: %d %d %d %d\n",
answers[0], answers[1], answers[2], answers[3]);
#endif
ret = scan_numbers(digits);
if (ret == 1)
{
break;
}
is_clear = judge_bytes_eats(digits, answers, &eats, &bytes);
print_result(eats, bytes);
if (is_clear == 0)
{
break;
}
}
return 0;
}
@kazmura11
Copy link
Author

まだ3って書いたままのところがあったのと、j++をfor文の中に書けばいいのにそうしてなかったところを修正。バグってはいませんでした。3とか4を直接リテラルで書かなきゃ前者のミスはなかったんですがまぁいいや。

@kazmura11
Copy link
Author

ちょっとスペース読み飛ばし周りでバグってたので修正。変数名もわかりやすく命名し直し

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment