编程文档

编程 |《五子棋编程文档》

目录

想法

一直以为编程是一个人的事情,感觉程序的思想和整体的流程都在一个人的脑海中,无法共享和传递。但是一个好的程序,一个完整的项目都不是一个人努力的结果,是所有和我一样,有着对编程的热爱和怀揣梦想的程序员们一点一滴编写而成。其中不乏技术牛人和大神,但是他们并没有孤立起来,而是更加喜欢分享与讨论。

这一次希望可以通过多人协同编写一个小程序,来适应并锻炼自己学会分享、积极讨论、学习的能力。之所以选择五子棋这个小程序作为开端,是因为第一次多个人一起编写一个程序,大家都不会适应,甚至停滞不前,所以难度不应该太高,代码量少为特点。要以少写多说的方式来磨合大家,如果效果可以,后续可以逐步提升难度和代码量。


程序流程

伪代码

main()
{
	while(1)
		begin_game() // 开始游戏
}

begin_game() // 开始游戏
{
	initialize() // 初始化
	while(1)
		 key_input() // 按键输入
		 if xy:k?
		 	interface() // 刷新界面
		 else
		 	judge_conflict() // 判断占位	 
		 	judge_win_los() // 判断输赢
		 	interface() // 刷新界面
}

initialize() // 初始化
{
	 array[size] // 初始化棋子数组
	 cursor[size] // 初始化光标信息
	 interface() // 刷新界面
}

interface() // 刷新界面
{
	if Y:N? // 判断占位 输出提示信息
		print N 
	if Y:N? // 判断5连珠 输出提示信息
		if 0:1? // 输出胜负提示信息
			print 0
		else
			print 1
	for(;;)
		if array[0||1]?0:1 // 根据数组数据输出棋子排列 
}

key_input() // 按键输入
{
	getch(key)
	switch(key)
		case x return key // 按下方向键 返回按键值
		case y return key
		case x return key
		case y return key
		case k return key
}

judge_win_los() // 判断输赢
{
	for(;;)
		for(;;)
			if array[5?]?Y:N // 判断是否有五子连珠情况
				if array[0||1]?0:1 // 判断是黑子胜还是白子胜
}

judge_conflict() // 判断占位
{
	for(;;)
		for(;;)
			if array[0:0?]?Y:N // 判断是否占位
}

模块化

模块划分

  • 框架
  • 初始化
  • 输入
  • 悔棋
  • 判断胜负
  • 判断占用
  • 刷新界面

参数 接口

函数名

int start_game();            // 框架
int initialize();            // 初始化
int key_input();             // 输入
int refresh_the_interface(); // 刷新界面
int judge_conflict();        // 判断占用
int judge_win_los();         // 判断胜负

数组

int chess_array[15][15] = {0}; // 棋子排列 说明:0为无棋子,1为白棋,2为黑棋。

光标坐标

[7][7]        
 y  x    
 y * 15 + x
----------------------
[7][7]
 i  j 
 i * 15 + j
----------------------
int coordinate_x = 7; // 横坐标 说明:光标位置信息,x y同为7,代表光标在棋盘中央。
int coordinate_y = 7; // 纵坐标

标识符

int placeholder = 0; // 占位标识符       说明:0为没有占用,1为占用。
int win_and_los = 0; // 五子连珠标识符   说明:0为没有出现五子连珠, 1为有五子连珠出现。
int black_white = 0; // 黑白棋交替标识符  说明:奇数为黑棋,偶数为白棋。
int key_direction = 0; // 按键标识符     说明:0为方向键,1为空格。

循环变量

int i = 0;
int j = 0;
int k = 0;
int l = 0;

编程规范

0.规范制定说明

本套C语言编程规范为提高代码质量、便于维护、协同编码、可移植等特点而编写。要求所有参与编码人员要严格遵循本编程规范。

参考文献:

  • 华为C语言开发编程规范。
  • 阿里巴巴Java开发手册。

1.标识符命名与定义

建议使用unix like风格给标识符命名,即单词用小写字母,每个单词直接用下划线“_”分割。

例如:text_mutextest_onekernel_text_address。

我们对标识符定义主要是为了让团队的代码看起来尽可能统一,有利于代码的后续阅读和修改。标识符的命名要清晰明了有明确含义,同时使用完整的单词或大家基本可以理解的缩写,避免使人产生误解。尽可能给出描述性名称,不要节约空间,让别人很快理解你的代码更重要。

示例:

好的命名:

int  error_number;
int  number_of_completed_connection; 

不好的命名:

int  n;
int  n_comp_conns;

原则:除了常见的通用缩写以外,不使用单词缩写,不得使用汉语拼音。

建议:

  • 尽量避免名字中出现数字编号,除非逻辑上的确需要编号。
  • 代码中的命名均不能以下划线开始,也不能以下划线符号结束。
  • 重构/修改部分代码时,应保持和原有代码的命名风格一致。
  • 全局变量应增加“g_”前缀。
  • 禁止使用单字母命名变量,但允许定义ijkl作为局部循环变量。
  • 常量和宏的定义应该全部大写,多个单词应使用“_”相隔。
  • 严禁使用未经初始化的变量作为右值。
  • 变量初始化必须赋予初值。

2.函数

函数设计的精髓:编写整洁函数,同时把代码有效组织起来。

整洁函数要求:代码简单直接、不隐藏设计者的意图、用干净利落的抽象和直截了当的控制语句将函数有机组织起来。

示例:

static void calibrate_run_measurement_overhead(void)
{
	u64 T0, T1, delta, min_delta = 1000000000ULL;
	int i;

	for (i = 0; i < 10; i++)
    {
		T0 = get_nsecs();
		burn_nsecs(0);
		T1 = get_nsecs();
		delta = T1-T0;
		min_delta = min(min_delta, delta);
	}
	run_measurement_overhead = min_delta;

	printf("run measurement overhead: %Ld nsecs\n", min_delta);
}

建议:

  • 一个函数仅完成一个功能。
  • 重复代码应该尽可能提炼成函数。
  • 避免函数过长,新增函数不超过100行(非空非注释行)。
  • 避免函数的代码块嵌套过深,新增函数的代码块嵌套不超过4层。
  • 函数的参数个数不超过5个。

3.参数/接口

在开始编码之前,应该对各个模块的接口和传递的参数做详细的讨论并制定计划。

例如:编写1 - 100之间所有所有偶数和奇数和的两个函数。

#include <stdio.h>
int even(int number_even[]);
int odd(int number_odd[]);
int main(){
	int number[100] = {0}, *p, i;
	int sum_odd = 0, sum_even = 0;
	p = number;
	for (i = 0; i < 100; i++){
		number[i] = i + 1;
	} 
	sum_even = even(p);
	sum_odd = odd(p);
	printf("odd = %d\neven = %d", sum_odd, sum_even);
	system("pause>nul"); 
	return 0;
}
int even(int *number_even){
	int i = 0, sum_even = 0;
	for (i = 0; i < 100; i++){
		if (( number_even[i] % 2 ) == 0){
			sum_even++;
		}
	} 
	return sum_even;
}
int odd(int *number_odd){
	int i = 0, sum_odd = 0;
	for (i = 0; i < 100; i++){
		if (( number_odd[i] % 2 ) != 0){
			sum_odd++;
		}
	} 
	return sum_odd;
}

对于数组的传递,是传值还是传址要做明确说明。

4.关于注释

因首次采用模块化多人协同编程,建议所有变量(包括全局变量)定义语句的上方使用单行注释加以阐述和说明此变量的作用,语言简洁、易懂。最好不要超过一行。

示例:

模块说明:

/*
 * lib/prio_tree.c - priority search tree
 *
 * Copyright (C) 2004, Rajesh Venkatasubramanian <vrajesh@umich.edu>
 *
 * This file is released under the GPL v2.
 *
 * Based on the radix priority search tree proposed by Edward M. McCreight
 * SIAM Journal of Computing, vol. 14, no.2, pages 257-276, May 1985
 *
 * 02Feb2004	Initial version
 */
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/prio_tree.h>

单行注释:

/*
 * Maximum heap_index that can be stored in a PST with index_bits bits
 */
static inline unsigned long prio_tree_maxindex(unsigned int bits)
{
	return index_bits_to_maxindex[bits - 1];
}

建议

  • 对于每个模块应使用块注释在模块上方说明作用和功能,语言简洁、易懂。
  • 模块应标明作者、创建时间、修改时间、修改内容、参考文献等相关信息。
  • 建议不要在模块或函数内部加入过多的注释影响阅读。注释的作用是解释难以表达的抽象意图,而不是重复描述代码。
  • 如模块或函数有重大重构或修改时应标明修改时间和修改内容。
  • 建议注释应放在其代码上方相邻位置或右方,不可放在下面。如放于上方则需与其上面的代码用空行隔开,且与下方代码缩进相同。

5.排版与格式

程序的可读性和可维护性除了编码好坏外,还要很重要的因素是编码时的排版与格式。在此次协同编码过程中,也应该注意排版风格一致、美观。

示例:

int swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems,
		                 enum dma_data_direction dir, struct dma_attrs *attrs)
{
	struct scatterlist *sg;
	int i;

	BUG_ON(dir == DMA_NONE);

	for_each_sg(sgl, sg, nelems, i) 
	{
		phys_addr_t paddr = sg_phys(sg);
		dma_addr_t dev_addr = phys_to_dma(hwdev, paddr);

		if (swiotlb_force || !dma_capable(hwdev, dev_addr, sg->length)) 
		{
			void *map = map_single(hwdev, sg_phys(sg),sg->length, dir);
			if (!map) 
			{
				/* Don't panic here, we expect map_sg users to do proper error handling. */
				swiotlb_full(hwdev, sg->length, dir, 0);
				swiotlb_unmap_sg_attrs(hwdev, sgl, i, dir,attrs);
				sgl[0].dma_length = 0;
				return 0;
			}
			sg->dma_address = swiotlb_virt_to_bus(hwdev, map);
		} 
		else
		{
			sg->dma_address = dev_addr;
		}
		sg->dma_length = sg->length;
	}
	return nelems;
}
EXPORT_SYMBOL(swiotlb_map_sg_attrs);

建议:

  • 程序块应采用缩进风格编写,每级缩进为1个tab(4个空格)。
  • 建议相对独立的程序块之间、变量说明之后必须加空行。
  • 多个短语句(包括赋值语句)不允许写在同一行内,即一行只写一条语句。
  • if、for、do、while、case、switch、default等语句独占一行。
  • 在两个以上的关键字、变量、常量进行对等操作时,它们之间的操作符之前、之后或者前后要加空格;进行非对等操作时,如果是关系密切的立即操作符(如->),后不应加空格。
  • 注释符(包括„/‟„//‟„/‟)与注释内容之间要用一个空格进行分隔。
  • 所有花括号必须独占一行,if语句即使一条表达式也要加花括号。

6.可移植性

为确保每个函数和模块有较高的可移植性,再此规定使用统一的平台Visual Studio 2013及以上版本。

参考样例

  • 棋盘界面

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hHlrTRot-1605602404693)(file:///E:/C/%E4%BA%94%E5%AD%90%E6%A3%8B/1.jpg?lastModify=1489205640)]

  • 光标及棋子

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-15ckag6A-1605602404695)(E:\C\五子棋\2.jpg)]

  • 胜负检查 and 判断占用

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IW1aO7cQ-1605602404697)(E:\C\五子棋\3.jpg)]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值