C语言之三字棋的简单实现及扩展

在我们学习完数组之后,我们完全可以利用数组相关知识来写一个微小型的游戏,比如说今天所说的——三子棋。

大纲:

   文件组成

   实现

   完整代码展示

   扩展

即:

一.文件组成:

在我们学习的过程中,我们要逐渐习惯多文件的书写方式,也就是模块化书写。

在本文中,笔者分为了三个文件来写,分别是:

  1.game.h——实现游戏函数的声明

  2.game.c——游戏函数的实现

  3.test.c —— 测试及游戏函数的调用

二.实现

0.文件的初始化

在这里我们分别在我们所创建的 test.c 和 game.c 包含我们的头文件——game.h

1.菜单的实现

在菜单中,我们设置玩家可以选择的模式,play and quit

以及,菜单怎么样多次循环选择,菜单的容错处理。这里,我们利用 do-while 来实现。

#define _CRT_SECURE_NO_WARNINGS 1//加这一句话是因为笔者采用的是 VS 编译器,为了防止一些不必要的错误出现

#include "game.h"

void menu()//列出可供玩家选择的模式
{
printf("**************************************************************\n");
printf("***************** 1.play ****************\n");
printf("***************** 0.exit ****************\n");
printf("**************************************************************\n");
} void play()
{ } int main()
{
int input;//在这里,我们利用玩家选择的模式来控制循环的终止
do
{
menu();
printf("请输入你的选择:");
scanf("%d", &input);
switch (input)
{
case 1://play
play();
break;
case 0://退出
printf("欢迎下次再来!\n");
break;
default://当玩家输入了非法字符,让其重新选择
printf("输入错误,请重新输入!\n");
}
} while (input);//当input为0时,停止循环 return 0;
}

运行效果:

现在,我们的菜单已经做好了,接下来要做的就是来打印我们的棋盘。

2.棋盘的打印

这里我们把打印函数的声明放在 game.h 文件里,把实现放在game.c 文件中

在写代码之前,我们先来想一想在棋盘打印中,我们能不能直接打印空格——这肯定是不能的,因为这样,我们在屏幕上什么都看不见 (≧∇≦)ノ

game.c:

#define _CRT_SECURE_NO_WARNINGS 1

#include"game.h"

void InitBoard(char board[3][3], int row, int col)//棋盘初始化
{
int i = 0, j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
} void DisplayBoard(char board[3][3], int row, int col)//棋盘打印函数
{
int i = 0, j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
{
printf("|");//分割列
}
}
printf("\n"); if (i < row - 1)
{
for (j = 0; j < 3; j++)
{
printf("---");//分割行
if (j < col - 1)
{
printf("|");
}
}
}
printf("\n");
}
}

注:

  为了避免文章赘余,test.c 以及 game.h不再表示

运行结果:

但是,我们这么写,会不会有问题?

值得注意的是,在这有人会把棋盘打印写成这个样子

void DisplayBoard(char board[3][3], int row, int col)//棋盘打印函数
{
for (int i = 0; i < 3; i++)
{
printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
if (i < 2)
{
printf("---|---|---\n");//分割行
}
}
}

这样,无非还是上面那个问题,代码写死,无法扩展

所以,我们在这利用宏来实现,棋盘的大小随我们的宏来改变

因此在这我们给出头文件的部分

#pragma once

#include<stdio.h>

#define ROW 3//利用宏来实现棋盘的大小
#define COL 3 void InitBoard(char board[ROW][COL], int row, int col);//棋盘初始化 void DisplayBoard(char board[ROW][COL],int row, int col);//棋盘打印函数

3.棋盘下子

1.玩家下子

在这里我们一共要注意几点:

  1.在下子之前,我们要判断玩家所要下的位置是否在棋盘内

  2.检测玩家要下的位置是否已有了棋子

  3.下子之后,检查棋盘的输赢状况 (这个我们后面再说)

void PlayerMove(char board[ROW][COL], int row, int col)//玩家下棋
{
int x, y;
printf("玩家走:\n");
printf("请输入你所要落子的坐标:");
scanf("%d%d", &x, &y);
if (board[x - 1][y - 1]!=' ')//坐标被占用
{
printf("该坐标已被占用,请重新下子!\n");
}
else if (!((x > 0 && x <= row) && (y > 0 && y <= col)))
{
printf("该坐标为非法坐标,请重新输入!\n");//坐标非法
}
else
{
board[x - 1][y - 1] = '*';//玩家落子,暂时用 * 来表示
}
}

2.电脑下子

再这里我们暂不深究,使用随机函数来生成一个坐标来下子

void ComputerMove(char board[ROW][COL], int row, int col)//电脑下棋
{
int x, y;
printf("电脑走:");
while (1)
{
x = rand() % row;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';//这里我们用 # 来表示电脑下棋
break;
}
}
}

4.胜负的判定

在这里,我们用一个函数的返回值来表示输赢的各个情况。

#-----电脑赢

*-----玩家赢

C-----继续下子

F-----和局

int ISFULL(char board[ROW][COL], int row, int col)
{
int i = 0, j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
return 0;
}
}
return 1;
} char ISWIN(char board[ROW][COL], int row, int col)
{
int i = 0, j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col - 2; j++)
{
//判断横行
if (board[i][j] == board[i][j + 1] && board[i][j] == board[i][j + 2] && board[i][j] != ' ')
return board[i][j];
//判断主对角线
else if (board[i][j] == board[i + 1][j + 1] && board[i + 2][j + 2] == board[i][j] && board[i][j] != ' ')
return board[i][j];
//判断副对角线
else if (board[col - 1 - i][j] == board[col - 2 - i][j + 1] && board[col - 3 - i][j + 2] == board[col - 1 - i][j] && board[col - 1 - i][j] != ' ')
return board[col - 1 - i][j];
}
}
for (i = 0; i < row - 2; i++)
{
for (j = 0; j < col; j++)
{
//判断竖行
if (board[i][j] == board[i + 1][j] && board[i][j] == board[i + 2][j] && board[i][j] != ' ')
return board[i][j];
}
}

    //判断是否满盘---放在最后是因为最后一步的判断
    if (1 == ISFULL(board, row, col))
    {
      return 'F';
    }

return 'C';
}

到这,我们的三子棋似乎已经编完了,先看一下运行结果:

    

在这个过程中,我们会发现电脑下的特别快(当然,这跟我们的懒惰有关……)所以我们在电脑下的步骤中加一个Sleep()函数来延长电脑所用时间

已即,我们可以下一次子就清一下屏,这样看起来比较舒服

所以

最后的代码部分:

#pragma once

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<Windows.h> #define ROW 3//利用宏来实现棋盘的大小
#define COL 3 void InitBoard(char board[ROW][COL], int row, int col);//棋盘初始化 void DisplayBoard(char board[ROW][COL], int row, int col);//棋盘打印函数 void PlayerMove(char board[ROW][COL], int row, int col);//玩家下棋 void ComputerMove(char board[ROW][COL], int row, int col);//电脑下棋 char ISWIN(char board[ROW][COL], int row, int col);//判断输赢 int ISFULL(char board[ROW][COL], int row, int col);//判断棋盘是否已满

game.h

#define _CRT_SECURE_NO_WARNINGS 1

#include"game.h"

void InitBoard(char board[ROW][COL], int row, int col)//棋盘初始化
{
int i = 0, j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
} //void DisplayBoard(char board[3][3], int row, int col)//棋盘打印函数
//{
// for (int i = 0; i < 3; i++)
// {
// printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
// if (i < 2)
// {
// printf("---|---|---\n");
// }
// }
//} void DisplayBoard(char board[ROW][COL], int row, int col)//棋盘打印函数
{
int i = 0, j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
{
printf("|");//分割列
}
}
printf("\n"); if (i < row - 1)
{
for (j = 0; j < 3; j++)
{
printf("---");//分割行
if (j < col - 1)
{
printf("|");
}
}
}
printf("\n");
}
} void PlayerMove(char board[ROW][COL], int row, int col)//玩家下棋
{
int x, y;
printf("玩家走:\n");
while (1)
{
printf("请输入你所要落子的坐标:");
scanf("%d%d", &x, &y);
if (!((x > 0 && x <= row) && (y > 0 && y <= col)))
{
printf("该坐标为非法坐标,请重新输入!\n");//坐标非法
}
else if (board[x - 1][y - 1] != ' ')//坐标被占用
{
printf("该坐标已被占用,请重新下子!\n");
}
else
{
board[x - 1][y - 1] = '*';//玩家落子,暂时用 * 来表示
break;
}
}
system("cls");
} void ComputerMove(char board[ROW][COL], int row, int col)//电脑下棋
{
int x, y;
printf("电脑走:\n");
Sleep(1000);
while (1)
{
x = rand() % row;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';//这里我们用 # 来表示电脑下棋
break;
}
}
system("cls");
} int ISFULL(char board[ROW][COL], int row, int col)
{
int i = 0, j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
return 0;
}
}
return 1;
} char ISWIN(char board[ROW][COL], int row, int col)
{
int i = 0, j = 0; for (i = 0; i < row; i++)
{
for (j = 0; j < col - 2; j++)
{
//判断横行
if (board[i][j] == board[i][j + 1] && board[i][j] == board[i][j + 2] && board[i][j] != ' ')
return board[i][j];
//判断主对角线
else if (board[i][j] == board[i + 1][j + 1] && board[i + 2][j + 2] == board[i][j] && board[i][j] != ' ')
return board[i][j];
//判断副对角线
else if (board[col - 1 - i][j] == board[col - 2 - i][j + 1] && board[col - 3 - i][j + 2] == board[col - 1 - i][j] && board[col - 1 - i][j] != ' ')
return board[col - 1 - i][j];
}
}
for (i = 0; i < row - 2; i++)
{
for (j = 0; j < col; j++)
{
//判断竖行
if (board[i][j] == board[i + 1][j] && board[i][j] == board[i + 2][j] && board[i][j] != ' ')
return board[i][j];
}
} //判断是否满盘---放在最后是因为最后一步的判断
if (1 == ISFULL(board, row, col))
{
return 'F';
}
return 'C';
}

game.c

#define _CRT_SECURE_NO_WARNINGS 1//加这一句话是因为笔者采用的是 VS 编译器,为了防止一些不必要的错误出现

#include "game.h"

void menu()//列出可供玩家选择的模式
{
printf("**************************************************************\n");
printf("***************** 1.play ****************\n");
printf("***************** 0.exit ****************\n");
printf("**************************************************************\n");
} void play()
{
int ret;
char board[ROW][COL] = { 0 };
InitBoard(board, ROW, COL); DisplayBoard(board, ROW, COL);
while (1)
{
PlayerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = ISWIN(board, ROW, COL);
{
if (ret != 'C')
break;
} ComputerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = ISWIN(board, ROW, COL);
{
if (ret != 'C')
break;
}
}
switch (ret)
{
case 'F':
printf("和局!\n");
system("pause");
system("cls");
break;
case '#':
printf("电脑赢!\n");
system("pause");
system("cls");
break;
case '*':
printf("玩家赢!\n");
system("pause");
system("cls");
break;
default:
break;
}
} int main()
{
srand((unsigned)time(NULL));//随机种子的初始化
int input;//在这里,我们利用玩家选择的模式来控制循环的终止
do
{
menu();
printf("请输入你的选择:");
scanf("%d", &input);
switch (input)
{
case 1://play
system("cls");
play();
break;
case 0://退出
printf("欢迎下次再来!\n");
break;
default://当玩家输入了非法字符,让其重新选择
system("cls");
printf("输入错误,请重新输入!\n");
}
} while (input);//当input为0时,停止循环 return 0;
}

test.c

三.扩展

1.五子棋的实现

五子棋的实现仅仅只改变了判断规则,其它方式都没变。

判断代码:

char ISWIN(char board[ROW][COL], int row, int col)
{
int i = 0, j = 0; for (i = 0; i < col; i++)
{
for (j = 0; j < col - 4; j++)
{
//判断横行
if (board[i][j] == board[i][j + 1] && board[i][j] == board[i][j + 2] && board[i][j] == board[i][j + 3] && board[i][j] == board[i][j + 4] && board[i][j] != ' ')
return board[i][j];
//判断对角线
else if (board[i][j] == board[i + 1][j + 1] && board[i + 2][j + 2] == board[i][j] && board[i][j] == board[i + 3][j + 3] && board[i][j] == board[i + 4][j + 4] && board[i][j] != ' ')
return board[i][j];
else if (board[col - 1 - i][j] == board[col - 2 - i][j + 1] && board[col - 3 - i][j + 2] == board[col - 1 - i][j] && board[col - 4 - i][j + 3] == board[col - 2 - i][j + 1] && board[col - 5 - i][j + 4] == board[col - 2 - i][j + 1] && board[col - 1 - i][j] != ' ')
return board[col - 1 - i][j];
}
}
for (i = 0; i < col - 4; i++)
{
for (j = 0; j < col ; j++)
{
//判断竖行
if (board[i][j] == board[i + 1][j] && board[i][j] == board[i + 2][j] && board[i][j] == board[i + 3][j] && board[i][j] == board[i + 4][j] && board[i][j] != ' ')
return board[i][j];
}
}
//判断是否满盘
if (1 == ISFULL(board, row, col))
{
return 'f';
} return 'c';
}

2.玩家对战玩家

只需将电脑下子的部分,替换成玩家下子即可

完整五子棋-人人对战代码:

#pragma once
#include <stdio.h>
#include<stdlib.h>
#include<time.h>
#include<Windows.h> #define ROW 10
#define COL 10 //初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col); //打印棋盘
void DisplayBoard(char board[ROW][COL], int row, int col); //玩家走
void Player1Move(char board[ROW][COL],int row, int col); //玩家2走
void Player2Move(char board[ROW][COL], int row, int col); //电脑走
void ComputerMove(char board[ROW][COL], int row, int col); //判断输赢
char ISWIN(char board[ROW][COL], int row, int col); //判断棋盘是否已满
int ISFULL(char board[ROW][COL], int row, int col);

game.h

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h" void InitBoard(char board[ROW][COL], int row, int col)
{
int i = 0, j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
} void DisplayBoard(char board[ROW][COL], int row, int col)
{
int i = 0, j = 0;
for (i = 0; i < col; i++)
printf(" %d", i + 1);
printf("\n");
for (i = 0; i < row; i++)
{
printf("%2d", i + 1);
for (j = 0; j < col; j++)
{
printf(" %c ",board[i][j]);
if (j < col - 1)
printf("|");
}
printf("\n"); //打印分割行
if (i < row - 1)
{
printf(" ");
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
} void Player1Move(char board[ROW][COL], int row, int col)
{
int i = 0, j = 0;
while (1)
{
printf("请输入玩家1要下的棋的坐标:");
scanf("%d%d", &i, &j);
//检查是否越界
if (1 <= i && i <= row && j >= 1 && j <= col)
{
if (board[i-1][j-1] != ' ')
printf("此坐标已被占用!\n");
else
{
board[i-1][j-1] = '*';
break;
}
}
else
printf("坐标非法访问!\n");
}
system("cls");
} void Player2Move(char board[ROW][COL], int row, int col)
{
int i = 0, j = 0;
while (1)
{
printf("请输入玩家2要下的棋的坐标:");
scanf("%d%d", &i, &j);
//检查是否越界
if (1 <= i && i <= row && j >= 1 && j <= col)
{
if (board[i - 1][j - 1] != ' ')
printf("此坐标已被占用!\n");
else
{
board[i - 1][j - 1] = '#';
break;
}
}
else
printf("坐标非法访问!\n");
}
system("cls");
} //void ComputerMove(char board[ROW][COL], int row, int col)
//{
// int i = 0, j = 0;
// printf("电脑走:\n");
// while (1)
// {
// i = rand() % row;
// j = rand() % col;
// if (board[i][j] == ' ')
// {
// board[i][j] = '#';
// break;
// }
// }
// Sleep(1000);
// system("cls");
//} int ISFULL(char board[ROW][COL], int row, int col)
{
int i = 0, j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
return 0;
}
}
return 1;
} char ISWIN(char board[ROW][COL], int row, int col)
{
int i = 0, j = 0; for (i = 0; i < col; i++)
{
for (j = 0; j < col - 4; j++)
{
//判断横行
if (board[i][j] == board[i][j + 1] && board[i][j] == board[i][j + 2] && board[i][j] == board[i][j + 3] && board[i][j] == board[i][j + 4] && board[i][j] != ' ')
return board[i][j];
//判断对角线
else if (board[i][j] == board[i + 1][j + 1] && board[i + 2][j + 2] == board[i][j] && board[i][j] == board[i + 3][j + 3] && board[i][j] == board[i + 4][j + 4] && board[i][j] != ' ')
return board[i][j];
else if (board[col - 1 - i][j] == board[col - 2 - i][j + 1] && board[col - 3 - i][j + 2] == board[col - 1 - i][j] && board[col - 4 - i][j + 3] == board[col - 2 - i][j + 1] && board[col - 5 - i][j + 4] == board[col - 2 - i][j + 1] && board[col - 1 - i][j] != ' ')
return board[col - 1 - i][j];
}
}
for (i = 0; i < col - 4; i++)
{
for (j = 0; j < col ; j++)
{
//判断竖行
if (board[i][j] == board[i + 1][j] && board[i][j] == board[i + 2][j] && board[i][j] == board[i + 3][j] && board[i][j] == board[i + 4][j] && board[i][j] != ' ')
return board[i][j];
}
}
//判断是否满盘
if (1 == ISFULL(board, row, col))
{
return 'f';
} return 'c';
}

game.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h" void menu()
{
printf("*********************************************\n");
printf("******* 1.play *********\n");
printf("******* 0.quit *********\n");
printf("*********************************************\n");
} int choice()
{
int input = 0;
printf("请输入你的选择:");
scanf("%d", &input);
return input;
} void game()
{
char ret;
char board[ROW][COL] = { 0 };
InitBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL);
while (1)
{
Player1Move(board, ROW, COL); DisplayBoard(board, ROW, COL); ret = ISWIN(board, ROW, COL);
{
if (ret != 'c')
break;
} Player2Move(board, ROW, COL); DisplayBoard(board, ROW, COL); ret = ISWIN(board, ROW, COL);
{
if (ret != 'c')
break;
}
}
switch (ret)
{
case 'f':
printf("和局!\n");
break;
case '#':
//printf("电脑赢!\n");
printf("玩家2赢!\n");
break;
case '*':
printf("玩家1赢!\n");
break;
default:
break;
}
} void play()
{
int input;
do
{
menu();
input = choice();
system("cls");
switch (input)
{
case 1:
game();
break;
case 0:
printf("谢谢使用,欢迎下次再来!\n");
break;
default:
system("cls");
printf("输入错误,请重新输入!\n");
break;
}
} while (input);
} int main()
{
play();
return 0;
}

test.c

3.电脑下棋的探究

对此我们的算法肯定是需要极大的改进的

建议:

  1.不在用随机函数代替机器大脑

  2.电脑根据情况堵截

关于三子棋的讲解便到此为止。

笔者水平有限,若有错误之处,还望多多指正。

C语言之三字棋的简单实现及扩展的更多相关文章

  1. C语言实现简单php自定义扩展

    1.下载php源码 下载地址:http://cn2.php.net/get/php-5.6.29.tar.gz/from/this/mirror 传到/usr/local/src/下 上传命令:rz ...

  2. GO语言练习:实现最简单的http helloword 服务器

    用Go语言实现一个最简单的http服务器端,主要用到了package io, log, net/http 这个3个库. 用到的函数包括: http.Handle() http.HandlerFunc( ...

  3. C语言开发CGI程序的简单例子

    这年头用C语言开发cgi的已经不多,大多数的web程序都使用java.php.python等这些语言了. 但是本文将做一些简单的cgi实例. 首先配置环境 #这里是使用的apache AddHandl ...

  4. 【笔记】嵩天.Python语言程序设计.完成两个简单实例(温度转换和绘图)

    [博客导航] [Python相关] 目标 使用PyCharm,完成两个小实例的编写和运行.一个是温度转换,一个是蟒蛇图形绘制. 过程 1.先设置project目录,虽然命名不是很正式,主要不太习惯软件 ...

  5. 函数式语言(Functional language)简单介绍

    函数式语言(functional language)一类程序设计语言,是一种非冯·诺伊曼式的程序设计语言.函数式语言主要成分是原始函数.定义函数和函数型. 函数式语言有:Haskell,Clean,M ...

  6. C语言程序设计(三) 简单的算术运算和表达式

    第三章 简单的算术运算和表达式 算数运算符:一元.二元.三元(条件运算符) 1/2是整型除法,1.0/2是浮点数除法 求余运算(%)限定参与运算的两个操作数必须为整数,不能对两个实型数据进行求余运算 ...

  7. 适合刚刚学习编程的萌新:C语言编程学习制作超简单又好玩的报数游戏!

    C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构.C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现 ...

  8. C语言中如何写一个简单可移植而又足够随机的随机数生成器

    在C语言中标准库中的随机数产生函数的返回可能不是最优的,因为有些随机数生成器的低位并不随机,而另一些返回随机数的函数实现上又太复杂鸟.所以rand()%N并不是一个好方法,牛人给出的建议是使用: ra ...

  9. 用c语言实现三子棋

    1 game.c://实现三子棋的.c文件 #define _CRT_SECURE_NO_WARNINGS #include"game.h" void init_board(cha ...

随机推荐

  1. Codeforces Round #529 (Div. 3) F. Make It Connected (贪心,最小生成树)

    题意:给你\(n\)个点,每个点都有权值,现在要在这\(n\)个点中连一颗最小树,每两个点连一条边的边权为两个点的点权,现在还另外给了你几条边和边权,求最小权重. 题解:对于刚开始所给的\(n\)个点 ...

  2. Python 分析热卖年货,今年春节大家都在送啥?

    今年不知道有多少小伙伴留在原地过年,虽然今年过年不能回老家,但这个年也得过,也得买年货,给家人长辈送礼.于是我出于好奇心的想法利用爬虫获取某宝数据,并结合 Python 数据分析和第三方可视化平台来分 ...

  3. PAT l2-018 多项式A除以多项式B 【多项式+模拟】

    这仍然是一道关于A/B的题,只不过A和B都换成了多项式.你需要计算两个多项式相除的商Q和余R,其中R的阶数必须小于B的阶数. 输入格式: 输入分两行,每行给出一个非零多项式,先给出A,再给出B.每行的 ...

  4. React Portal All In One

    React Portal All In One react multi root https://reactjs.org/docs/portals.html https://zh-hans.react ...

  5. 前端架构模式 All In One

    前端架构模式 All In One 架构模式 同构 异构 微前端 Web Components 组件化 无框架 去框架 前后端分离 前端架构图 Clean Architecture https://b ...

  6. how to read the system information by using the node cli tool?

    how to read the system information by using the node cli tool? node cli & get system info demos ...

  7. Python Web Frameworks

    Python Web Frameworks top 10 Python web frameworks Django (Full-stack framework) Flask (Micro framew ...

  8. holy shit CSDN

    holy shit CSDN 垃圾 CSDN 到处都是垃圾文章, 无人子弟 到处都是垃圾广告,看的恶心 毫无底线,窃取别人的知识成果,毫无版权意识 垃圾爬虫,垃圾小号 ...等等 Google Sea ...

  9. foreign language learning

    foreign language learning free online learning websites 多邻国 https://www.duolingo.com 忆术家 https://www ...

  10. js repeatify & no for loop

    js repeatify & no for loop js repeatify https://www.sitepoint.com/5-typical-javascript-interview ...