楼主:10月1日签到帖--以及技术讨论,申酷及转载到技术板块技术, 申酷, 讨论
本帖最后由 icecut 于 2010-10-3 01:55 编辑
if (floor < 50 && date.day == 1) score++
// 或者
for(int i = 1;i <= 50;i++)
{
if (date.day > 1)
break;
floor.score++;
}
================================
50
从一个问题谈程序架构设计。
作者:icecut
mail:icecut@qq.com
写于:2010年10月3日01点38分
初发:bbs.21ic.com
由于各种原因,出现小的bug请加注释处理。
bug还是比较多,大家看了自己知道就行了。都比较明显。例如某个++没有初始化。前面结果分析不正确。我认为可以不做修改。
转载请保留此权利声明。
为了稳定性,我在10.2做最后更新:因为需求变了。不可能有50人来这里,因为他们都去广场了。
并且lz算第一楼而不是0,这是这2个code的区别,然后我在附加一个需求就是灌水是不是有效。
咱们按有效处理。以前每人一分颗粒度足够小,这样分不完的就继续分。直到最后后来的就没了。
int GetLinesBeforeDate(int month, int day)
{
return 10;// 我人工统计的。省略了接口。不包括lz自己,因为我没有回帖占楼。如果有应该在本函数过滤掉。
// 正常情况请返回arraylist,java的。这里就不需要了。我为了简化不重要的东西。
}
void main(){
int nTotle = 50;
int nFloor = GetLinesBeforeDate(10, 1);
int *pFloors = malloc(nFloor*sizeof(int));
int nCount = 0;
while (nTotle > 0)
{
// 一分一分的分。
nCount++;
nCount = nCount%nFloor;// 0..9
// 过滤楼主
if (nCount == 0)continue;
pFloors[nCount]++;
nTotle--;
}
// 输出结果省略,释放内存
free(pFloors);
}
// 大家会觉得这样循环效率多烂啊。直接nTotle/(10-1)得到整数,初始化给所有非lz的人。然后剩下的分数每人一分,优先前面。
那程序关键部分就是这个样子。
// 初始化
for (i = 1; i <= nTotle; pFloors[i++] = nTotle/(nFloor-1));// 最后那个1可以换成GetLZcountBefore(10,1);
i=1;
nTotle%=(nFloor-1);// 最后那个应该换成GetLZcountBefore(10,1);这样如果lz帖子不是1,修改的地方就会限制在一处。搞个宏定义也比直接写1好,但是本帖子就没必要了。滥用宏定义也会不爽。
while(i < n)
{
pFloors++;
}
上面就是最逻辑的代码。但是在空间上对lz没做初始化。建议初始化0。
==================华丽丽的分割线===========================================
到此,程序员就认为完美了。太棒了。
没过几天,这帖子就会火了。因为“客户”有争执,我早来他晚来,一楼就差一分不公平,并且最后来到的那几个,分数都一样,更不公平。
下面悲剧开始了:
一分不行咱们就2分至少还是等差数列。这样剩下的又除不尽了。这群用户是多么的难缠啊。
但是这样还是不满足啊。
然后开始争论灌水怎么处理,
然后开始争论,给分与来的早晚有关系,这个关系不简单的是与楼层有关,而是与lz发帖的时间有关,尤其是抢沙发的人对此要求迫切。
我想大多数人肯定就骂了。我写的这么好的算法,又快,效率也高。他们怎么那么多毛病啊。代码就想自己的孩子,谁也不舍得送人重新造人。可是想要一个男孩,已经有2个女孩的就不能再生,当需求和自己亲生骨肉产生冲突的时候,有三种处理方法。第一种:提前b超,扼杀与前期。第二种,遗弃/送人然后重生,第三种,不生了就这么样吧。写代码也有这三种,第一种是提前重构代码,在速度与需求扩展折中。第二种是推倒代码重写。第三种,那就是算了。我辞职吧。把风险还给公司。这么一比较,大家都很明白。可是如何去重构代码呢?
====================华丽丽的分割线重新登场======================================================
1.不要钻牛角尖,第二种优化代码在应用层基本不合适,在系统层很合适。因为前者是多变的。后者是固定的。
2.这两种代码,第一种所有人都说烂,你怎么说好?lz不是傻子吧?就算改不全都是推倒重写吗?
其实代码就是孙悟空的金箍棒,能长能短,能粗能细,这样才能游刃有余。(突然想把此文链接到技术区。唉。不知道有没有特权搞一下)
那好,你们这些客户放马过来,我一个狗皮膏药全给你堵住。
那第一个需求叫做:来者有份,先到先得。就是我最原始的规定。
语言描述为for (i = 1; i <= min(nTotle, GetLinesBeforeDate(10, 1)); pFloors[i++] = 1);
tips:c语言常常把i用在后面判断for循环的结果。而c++或者非c99格式的for(int i=0:...更注重结构化,i是不可以复用的,设计的时候最好考虑语言区别不建议过程化的东西带入到结构化里面去。都有合适的描述。
那遇到来的人少,而又不能浪费这50分的时候,那些困难又怎办呢?
第二个需求叫做:早来捧场多发奖金。白天一小时一元,晚上一小时1毛,早来早得送完为止。大家看看超市商场是不是都这么写啊?
语言描述为 if(leftValue > 0) bonus = (18:00 -time)×0.9+(24:00-time)*0.1
假如还没发完呢?喜钱一般不能剩下。剩下庄主会发怒的。你这程序搞不定那一分钱不给,直接退货。老板表示鸭梨很大
第三个需求火热出炉:随机抛,谁抢着谁的。每次扔一分,庄主表示非常热闹,对软件验收非常期待。
语言描述:nSelect = nFloor×random(time);
写到这里大家是不是觉得,那个高速高效的算法真的是一丘之貉呢?
看到这里,大家都觉得挺简单。分成3部分加进去就行了。我估计大部分人都高高兴兴的添上3部分,赶紧下班吃饭。
可是悲剧又来了。刚上公交车就接到老板电话。经济危机来了,况且庄主是个才人。这红包里面啊不全是钱,有的就是庄主写的福字,寿字等字。一共n个。对于我这文章啊。就是随机赠送本文一copy。这个要和钱一起抛。每次是抛钱还是字,谁也不知道。并且提示啊,明年还要添加抽奖,抽奖用的钱必须是喜钱,不能自带。但是有抽奖环节就没抛奖环节。
于是刚才那些匆匆添上的人表示一头黑线。。。。好多人开始不做开发想转销售了,或者考虑离开公司了,有的考虑不如回家了。这工作太不爽了。就tmd一个代码工人啊。和民工板砖没区别。。。
=================华丽丽的分割线总会华丽丽的出现================================================================================
对于程序员的反应,老板深感忧虑,于是请人来培训。培训的这哥们懒。就会打比方,代码一点不看。听了这个需求啊,哈哈大笑。
于是去一个开发机器上,把vs2008的工程考过来。让大家看,一运行,就提示错误gdiplus.dll的某个接口不对。。。。员工又是一脸黑线。同样是gdi+的dll怎么就不能用呢。于是他又重新考了一个版本正确的,软件得以运行。
留下 几句话就走了:有时候啊,一把锁有一把钥匙是好事。如果是公共设施(比如水表的钥匙),相关部门有一把万能钥匙更方便。
什么意思呢。抬腿大家都会,但走的是齐步还是正步?靠的是大脑。这就是代码隔离,把易错的,重复的等功能代码集合起来到时候有问题啊,改一个地方就够了。归一化。
如何去设计参数最重要。那这个函数就是决策函数经济危机来之前我觉得如下构造就比较好
int/*收获的钱*/ just(int step/*第几个阶段*/, int nTotle/*庄主剩下的喜钱*/, int id/*返回金钱的所属人,只用于抽奖*/)
{
int nRet = 0;
static int s_nSelect = Random(GetSysTime());//静态变量初始化一次。
if (nTotle <= 0 || id == 0)//没钱没法玩,lz不让玩
return 0;
switch(step)
{
case step1:
// for (i = 1; i <= min(nTotle, GetLinesBeforeDate(10, 1)); pFloors[i++] = 1);
// 对比一下上面的过程化程序设计与下面的结构化程序设计--参与时间的限定在外围。过时的人不让参加
// 只要剩下钱,参与的第一阶段就能拿到钱。
nRet = 1;
break;
case step2:
nRet = (18:00 -time)×0.9+(24:00-time)*0.1;
break;
case step3:
defaule:// 最后一个循环直到没钱。
//nRet = nFloor×random(time);这种返回值在某一个参量时修改功能是不被允许的。这样在逻辑上又把分离给搞成不完全分离了。
// 不改变返回值结构的情况下如何处理呢。1.生成抽奖人的数,对其他人返回0,此人返回奖金1
if (id == s_nSelect)
{
nRet = 1;
s_nSelect = Random(GetSysTime());
}
break;
}
}
那我把刚才的最原始代码复制过来,看看能改多少?
void main(){
int nTotle = 50;
int nFloor = GetLinesBeforeDate(10, 1);
int *pFloors = malloc(nFloor*sizeof(int));
// 规范代码必须初始化
memset(pFloors, 0, nFloor*sizeof(int));
int nCount = 0;
int nStage = 0;
while (nTotle > 0)
{
nCount++;
if (nCount == nFloor)
{
nStage++;
nCount =0;// 这里为什么不写1直接过滤楼主?因为以后可能lz参与活动并有一定收益。
}
nCount = nCount%nFloor;// 0..9
// 过滤楼主
//if (nCount == 0)continue;--删掉,放到just里面判断楼主不参与活动,以后很可能楼主也参与
char nGetMoney = just(nStage, nTotle, nCount);
//pFloors[nCount]++;
pFloors[nCount] += nGetMoney;
//nTotle--;
nTotle -= nGetMoney;
}
// 输出结果省略,释放内存
free(pFloors);
}
================================
以后只要修改just就可以满足老板各种玩法。一点风险都没有,测试和修改超级简单。为测试人员也节约了时间。开发人员也不再犯愁了。
(全文完)