* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "napi/native_api.h"
#include "common/plugin_common.h"
#include <js_native_api_types.h>
#include <node_api.h>
#include <sstream>
#include <string.h>
#include <thread>
#include "uv.h"
#include "chess.h"
int Max(int nums[4])
{
int max = nums[0];
for (int i = 1; i < 4; i++) {
if (nums[i] > max)
{
max = nums[i];
}
}
return max;
}
int GetMaxNumDirection(int nums[4])
{
int max = nums[0];
int direction = 1;
for (int i = 1; i < 4; i++) {
if (nums[i] > max)
{
max = nums[i];
direction = i + 1;
}
}
return direction;
}
void ClearData() {
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
chessBoard[i][j] = 0;
}
}
result[0] = NO_WIN;
result[1] = SIZE + 1;
result[2] = SIZE + 1;
aiCoiledNum = 0;
}
int GetNumHorizontal(int x, int y, int chessType) {
int total = 0;
for (int a1 = 1; a1 < WIN_NUM; a1++) {
if (y - a1 < 0) {
break;
}
if(chessBoard[x][y - a1] != chessType) {
break;
}
total++;
}
if (total >= WIN_NUM) {
return total;
}
for (int a1 = 1; a1 < WIN_NUM; a1++) {
if (y + a1 >= SIZE) {
break;
}
if(chessBoard[x][y + a1] != chessType) {
break;
}
total++;
}
return total;
}
int GetNumVertical(int x, int y, int chessType) {
int total = 0;
for (int a1 = 1; a1 < WIN_NUM; a1++) {
if (x - a1 < 0) {
break;
}
if(chessBoard[x - a1][y] != chessType) {
break;
}
total++;
}
if (total >= WIN_NUM) {
return total;
}
for (int a1 = 1; a1 < WIN_NUM; a1++) {
if (x + a1 >= SIZE) {
break;
}
if(chessBoard[x + a1][y] != chessType) {
break;
}
total++;
}
return total;
}
int GetNumLeftSlash(int x, int y, int chessType)
{
int total = 0;
for (int a1 = 1; a1 < WIN_NUM; a1++) {
if (x - a1 < 0 || y - a1 < 0) {
break;
}
if(chessBoard[x - a1][y - a1] != chessType) {
break;
}
total++;
}
if (total >= WIN_NUM) {
return total;
}
for (int a1 = 1; a1 < WIN_NUM; a1++) {
if (x + a1 >= SIZE || y + a1 >= SIZE) {
break;
}
if(chessBoard[x + a1][y + a1] != chessType) {
break;
}
total++;
}
return total;
}
int GetNumRightSlash(int x, int y, int chessType) {
int total = 0;
for (int a1 = 1; a1 < WIN_NUM; a1++) {
if (x - a1 < 0 || y + a1 >= SIZE) {
break;
}
if(chessBoard[x - a1][y + a1] != chessType) {
break;
}
total++;
}
if (total >= WIN_NUM) {
return total;
}
for (int a1 = 1; a1 < WIN_NUM; a1++) {
if (x + a1 >= SIZE || y - a1 < 0) {
break;
}
if(chessBoard[x + a1][y - a1] != chessType) {
break;
}
total++;
}
return total;
}
void PutInt2Char(char * charData, int beginIndex, int endIndex, int intValue) {
if (intValue < 10) {
charData[beginIndex] = '0';
charData[endIndex] = intValue + '0';
} else {
charData[beginIndex] = 1 + '0';
charData[endIndex] = (intValue - 10) + '0';
}
}
void AIPlay()
{
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
if (chessBoard[i][j] != 0)
continue;
LOGD("判断四个方向连子");
int numHorizontal = GetNumHorizontal(i, j, AI_CHESS);
int numVertical = GetNumVertical(i, j, AI_CHESS);
int numLeftSlash = GetNumLeftSlash(i, j, AI_CHESS);
int numRightSlash = GetNumRightSlash(i, j, AI_CHESS);
int nums[4] = { numHorizontal, numVertical, numLeftSlash, numRightSlash };
int maxNum = Max(nums);
if (maxNum >= WIN_NUM - 1) {
LOGD("AI已获胜");
chessBoard[i][j] = AI_CHESS;
result[0] = AI_WIN;
result[1] = i;
result[2] = j;
return;
}
}
}
LOGD("判断对手是否有大于三子的情况");
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
if (chessBoard[i][j] == USER_CHESS || chessBoard[i][j] == AI_CHESS)
continue;
int numHorizontal = GetNumHorizontal(i, j, USER_CHESS);
int numVertical = GetNumVertical(i, j, USER_CHESS);
int numLeftSlash = GetNumLeftSlash(i, j, USER_CHESS);
int numRightSlash = GetNumRightSlash(i, j, USER_CHESS);
int nums[4] = { numHorizontal, numVertical, numLeftSlash, numRightSlash };
int maxNum = Max(nums);
int direction = GetMaxNumDirection(nums);
if (maxNum == 3) {
LOGD("对手已经三子,此时要分情况,有边界的三子不用堵,没有边界的三子需要堵");
if (direction == 1) {
LOGD("水平线有三子");
int num;
int numDirection1 = 0;
for (num = 1; num <= 3; num++) {
if (j - num < 0) {
break;
}
if (chessBoard[i][j - num] != USER_CHESS) {
break;
}
numDirection1++;
}
if (numDirection1 == 3) {
if (j - num - 1 >= 0) {
if (chessBoard[i][j - num - 1] == NO_CHESS) {
chessBoard[i][j] = AI_CHESS;
result[0] = 0;
result[1] = i;
result[2] = j;
return;
}
}
} else if (numDirection1 == 2) {
chessBoard[i][j] = AI_CHESS;
result[0] = NO_WIN;
result[1] = i;
result[2] = j;
return;
}
else if (numDirection1 == 1) {
chessBoard[i][j] = AI_CHESS;
result[0] = NO_WIN;
result[1] = i;
result[2] = j;
return;
}
else if (numDirection1 == 0) {
if (j + num < SIZE) {
if (chessBoard[i][j + num + 1] == NO_CHESS) {
chessBoard[i][j] = AI_CHESS;
result[0] = NO_WIN;
result[1] = i;
result[2] = j;
return;
}
}
}
}
else if (direction == 2) {
LOGD("竖直线有三子的情况");
int num;
int numDirection2 = 0;
for (num = 1; num <= 3; num++) {
if (i - num < 0) {
break;
}
if (chessBoard[i - num][j] != USER_CHESS) {
break;
}
numDirection2++;
}
if (numDirection2 == 3) {
if (i - num - 1 >= 0) {
if (chessBoard[i - num - 1][j] == NO_CHESS) {
chessBoard[i][j] = AI_CHESS;
result[0] = NO_WIN;
result[1] = i;
result[2] = j;
return;
}
}
}
else if (numDirection2 == 2) {
chessBoard[i][j] = AI_CHESS;
result[0] = NO_WIN;
result[1] = i;
result[2] = j;
return;
} else if (numDirection2 == 1) {
chessBoard[i][j] = AI_CHESS;
result[0] = NO_WIN;
result[1] = i;
result[2] = j;
return;
}
else if (numDirection2 == 0) {
if (i + num < SIZE - 1) {
if (chessBoard[i + num + 1][j] == NO_CHESS) {
chessBoard[i][j] = AI_CHESS;
result[0] = NO_WIN;
result[1] = i;
result[2] = j;
return;
}
}
}
}
else if (direction == 3) {
LOGD("左斜线有三子的情况");
int num;
int numDirection3 = 0;
for (num = 1; num <= 3; num++) {
if (i - num < 0 || j - num < 0) {
break;
}
if (chessBoard[i - num][j - num] != USER_CHESS) {
break;
}
numDirection3++;
}
if (numDirection3 == 3) {
if (i - num - 1 >= 0 && j - num - 1 >= 0) {
if (chessBoard[i - num - 1][j - num - 1] == NO_CHESS) {
chessBoard[i][j] = AI_CHESS;
result[0] = NO_WIN;
result[1] = i;
result[2] = j;
return;
}
}
}
else if (numDirection3 == 2) {
chessBoard[i][j] = AI_CHESS;
result[0] = NO_WIN;
result[1] = i;
result[2] = j;
return;
}
else if (numDirection3 == 1) {
chessBoard[i][j] = AI_CHESS;
result[0] = NO_WIN;
result[1] = i;
result[2] = j;
return;
}
else if (numDirection3 == 0) {
if (i + num < SIZE - 1 && j + num < SIZE - 1) {
if (chessBoard[i + num + 1][j + num + 1] == NO_CHESS) {
chessBoard[i][j] = 2;
result[0] = NO_WIN;
result[1] = i;
result[2] = j;
return;
}
}
}
}
else if (direction == 4) {
LOGD("判断右斜线有三子的情况");
int num;
int numDirection4 = 0;
for (num = 1; num <= 3; num++) {
if (i - num < 0 || j + num >SIZE - 1) {
break;
}
if (chessBoard[i - num][j + num] == USER_CHESS) {
break;
}
numDirection4++;
}
if (numDirection4 == 3) {
if (i - num - 1 >= 0 && j + num + 1 <= SIZE - 1) {
if (chessBoard[i - num - 1][j + num + 1] == NO_CHESS) {
chessBoard[i][j] = AI_CHESS;
result[0] = NO_WIN;
result[1] = i;
result[2] = j;
return;
}
}
}
else if (numDirection4 == 2) {
chessBoard[i][j] = AI_CHESS;
result[0] = NO_WIN;
result[1] = i;
result[2] = j;
return;
}
else if (numDirection4 == 1) {
chessBoard[i][j] = AI_CHESS;
result[0] = NO_WIN;
result[1] = i;
result[2] = j;
return;
}
else if (numDirection4 == 0) {
if (i + num < SIZE - 1 && j - num >
0)
{
if (chessBoard[i + num + 1][j - num - 1] == NO_CHESS) {
chessBoard[i][j] = AI_CHESS;
result[0] = NO_WIN;
result[1] = i;
result[2] = j;
return;
}
}
}
}
}
else if (maxNum == WIN_NUM - 1 || maxNum == WIN_NUM) {
LOGD("对手有四子或五子,一定要堵");
chessBoard[i][j] = AI_CHESS;
result[0] = NO_WIN;
result[1] = i;
result[2] = j;
return;
}
}
}
int totalNum = 0;
int emptyNum = 0;
LOGD("判断对手连子情况结束,开始连自己五子");
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
if (chessBoard[i][j] == AI_CHESS) {
totalNum++;
}
if (chessBoard[i][j] == NO_CHESS) {
emptyNum++;
}
}
}
if (emptyNum == 0) {
result[0] = NO_WIN;
result[1] = SIZE + 1;
result[2] = SIZE + 1;
return;
}
if (totalNum == 0) {
LOGD("第一次落子");
chessBoard[7][7] = AI_CHESS;
result[0] = NO_WIN;
result[1] = 7;
result[2] = 7;
return;
}
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
if (chessBoard[i][j] != NO_CHESS)
continue;
int numHorizontal = GetNumHorizontal(i, j, AI_CHESS);
int numVertical = GetNumVertical(i, j, AI_CHESS);
int numLeftSlash = GetNumLeftSlash(i, j, AI_CHESS);
int numRightSlash = GetNumRightSlash(i, j, AI_CHESS);
int nums[4] = { numHorizontal, numVertical, numLeftSlash, numRightSlash };
int maxNum = Max(nums);
if (maxNum > aiCoiledNum) {
chessBoard[i][j] = AI_CHESS;
result[0] = NO_WIN;
result[1] = i;
result[2] = j;
aiCoiledNum = maxNum;
return;
} else if (maxNum >= 1) {
result[0] = NO_WIN;
result[1] = i;
result[2] = j;
}
}
}
chessBoard[result[1]][result[2]] = AI_CHESS;
}
static napi_value Put(napi_env env, napi_callback_info info) {
napi_status status;
size_t requireArgc = 2;
size_t argc = 2;
napi_value args[2];
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
napi_valuetype valuetype;
status = napi_typeof(env, args[0], &valuetype);
if (status != napi_ok) {
return nullptr;
}
if (valuetype != napi_number) {
napi_throw_type_error(env, NULL, "Wrong arguments");
return nullptr;
}
status = napi_typeof(env, args[1], &valuetype);
if (status != napi_ok) {
return nullptr;
}
if (valuetype != napi_number) {
napi_throw_type_error(env, NULL, "Wrong arguments");
return nullptr;
}
int x1;
napi_get_value_int32(env, args[0], &x1);
int y1;
napi_get_value_int32(env, args[1], &y1);
chessBoard[x1][y1] = USER_CHESS;
int result = 0;
int numHorizontal = GetNumHorizontal(x1, y1, USER_CHESS);
if (numHorizontal >= WIN_NUM - 1) {
LOGD("PUT 获胜");
ClearData();
result = USER_WIN;
napi_value returnValue = nullptr;
napi_create_int32(env, result, &returnValue);
return returnValue;
}
int numVertical = GetNumVertical(x1, y1, USER_CHESS);
if (numVertical >= WIN_NUM - 1) {
LOGD("PUT 获胜");
ClearData();
result = USER_WIN;
napi_value returnValue = nullptr;
napi_create_int32(env, result, &returnValue);
return returnValue;
}
int numLeftSlash = GetNumLeftSlash(x1, y1, USER_CHESS);
if (numLeftSlash >= WIN_NUM - 1) {
LOGD("PUT 获胜");
ClearData();
result = USER_WIN;
napi_value returnValue = nullptr;
napi_create_int32(env, result, &returnValue);
return returnValue;
}
int numRightSlash = GetNumRightSlash(x1, y1, USER_CHESS);
if (numRightSlash >= WIN_NUM - 1) {
LOGD("PUT 获胜");
ClearData();
result = USER_WIN;
napi_value returnValue = nullptr;
napi_create_int32(env, result, &returnValue);
return returnValue;
}
napi_value returnValue = nullptr;
napi_create_int32(env, result, &returnValue);
return returnValue;
}
struct CallbackContext {
napi_env env = nullptr;
napi_ref callbackRef = nullptr;
int status = -1;
napi_async_work worker = nullptr;
char retData[7] = { '0', ',', '0', '0', ',', '0', '0' };
};
static napi_value Deal(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 0 };
napi_value thisVar = nullptr;
void * data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_function) {
return nullptr;
}
CallbackContext * asyncContext = new CallbackContext();
asyncContext->env = env;
napi_create_reference(env, argv[0], 1, &asyncContext->callbackRef);
napi_value resultData = nullptr;
napi_get_undefined(env, &resultData);
napi_value resource = nullptr;
napi_create_string_utf8(env, "NativeAPI", NAPI_AUTO_LENGTH, &resource);
napi_create_async_work(env, nullptr, resource,
[](napi_env env, void * data) {
LOGD("async_work 1");
CallbackContext * asyncContext1 = (CallbackContext *)data;
asyncContext1->status = 0;
AIPlay();
asyncContext1->retData[0] = result[0] + '0';
PutInt2Char(asyncContext1->retData, 2, 3, result[1]);
PutInt2Char(asyncContext1->retData, 5, 6, result[2]);
if (result[0] == 2) {
ClearData();
}
asyncContext1->status = 1;
},
[](napi_env env, napi_status status, void * data) {
LOGD("async_work 2");
CallbackContext * asyncContext2 = (CallbackContext *)data;
if (asyncContext2->status == 1) {
napi_value result = nullptr;
napi_get_undefined(env, &result);
napi_value callback = nullptr;
napi_get_reference_value(asyncContext2->env, asyncContext2->callbackRef, &callback);
napi_value retArg;
napi_create_string_utf8(asyncContext2->env, asyncContext2->retData, 7, &retArg);
napi_value ret;
napi_call_function(asyncContext2->env, nullptr, callback, 1, &retArg, &ret);
napi_delete_reference(env, asyncContext2->callbackRef);
napi_delete_async_work(env, asyncContext2->worker);
}
},
(void *)asyncContext, &asyncContext->worker);
napi_queue_async_work(env, asyncContext->worker);
return resultData;
}
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
napi_property_descriptor desc[] = { { "deal", nullptr, Deal, nullptr, nullptr, nullptr, napi_default, nullptr },
{ "put", nullptr, Put, nullptr, nullptr, nullptr, napi_default, nullptr } };
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
return exports;
}
EXTERN_C_END
static napi_module demoModule = {
.nm_version = 1,
.nm_flags = 0,
.nm_filename = nullptr,
.nm_register_func = Init,
.nm_modname = "libcard",
.nm_priv = ((void *)0),
.reserved = {0},
};
extern "C" __attribute__((constructor)) void RegisterModule(void)
{
napi_module_register(& demoModule);
}