教父的告白
一切都是纸老虎
posts - 82,  comments - 7,  trackbacks - 0
     摘要: Phing是什么?Phing是一个基于Apache Ant的项目代码构建系统.你可以用她做传统的构建系统能做的任何事情,比如GNU make,并且Phing使用简单的XML构建文件和可扩展的”任务”使之成为易于使用和极具可扩展性的框架.因为Phing是基于Ant的,所以本手册部分内容是摘自Ant手册.Phing & Binarycloud :历史Phing源自Bin...  阅读全文
posted @ 2010-04-08 15:08 暗夜教父 阅读(4606) | 评论 (0)编辑 收藏
数据库备份是很重要的。如果定期做好备份,这样就可以在发生系统崩溃时恢复数据到最后一次正常的状态,把损失减小到最少。
以前在FREEBSD系统里面都先把MYSQL停掉,然后直接用tar命令直接把数据库文件打包,下载到本地。如果要恢复数据库,也是直接上传,用tar解压,然后设置下权限就可以用了。

现在在windows下,本来用PHPmyadmin管理数据库是很好,但是本地的服务器,死活连不上数据库,新版的2.11的我都不知道怎么配置,汗死!用MySQL Control Center 等客户端软件也不行,晕死了! 无奈,只好用mysqldump 来备份了!

因为没有好好的准备 ,以为mysqldump 是 MYSQL解析器里面的命令-_-!! 死活运行不起来。
使用了之后,才发现。。原来,MYSQL的备份可以这么美的。哈哈。。(渐远!)

好了,收集了一些mysqldump命令的语法,先学学!
用mysqldump对MySQL数据库进行数据备份与恢复

MySQLl提供了一个mysqldump命令,我们可以用它进行数据备份,下面假设要备份yejihao_agent这个数据库:

#mysqldump -u root -p yejihao_agent > yejihao_agent.sql

按提示输入密码,这就把yejihao_agent数据库所有的表结构和数据备份到yejihao_agent.sql了,因为要总进行备份工作,如果数据量大会占用很大空间,这时可以利用gzip压缩数据,命令如下:

#mysqldump -u root -p yejihao_agent | gzip > yejihao_agent.sql.gz

系统崩溃,重建系统时,可以这样恢复数据:

#mysql -u root -p yejihao_agent < yejihao_agent.sql

从压缩文件直接恢复:

#gzip < yejihao_agent.sql.gz | mysql -u root -p yejihao_agent

/*************************************/
命令解释 
/************************************/

导出要用到MySQL的mysqldump工具,基本用法是:   

shell> mysqldump [OPTIONS] database [tables]   

如果你不给定任何表,整个数据库将被导出。   

通过执行mysqldump --help,你能得到你mysqldump的版本支持的选项表。   

注意,如果你运行mysqldump没有--quick或--opt选项,mysqldump将在导出结果前装载整个结果集到内存中,如果你正在导出一个大的数据库,这将可能是一个问题。   

mysqldump支持下列选项:   

--add-locks   
在每个表导出之前增加LOCK TABLES并且之后UNLOCK TABLE。(为了使得更快地插入到MySQL)。   
--add-drop-table   
在每个create语句之前增加一个drop table。   
--allow-keywords   
允许创建是关键词的列名字。这由表名前缀于每个列名做到。   
-c, --complete-insert   
使用完整的insert语句(用列名字)。   
-C, --compress   
如果客户和服务器均支持压缩,压缩两者间所有的信息。   
--delayed   
用INSERT DELAYED命令插入行。   
-e, --extended-insert   
使用全新多行INSERT语法。(给出更紧缩并且更快的插入语句)   
-#, --debug[=option_string]   
跟踪程序的使用(为了调试)。   
--help   
显示一条帮助消息并且退出。   
--fields-terminated-by=...   
    
--fields-enclosed-by=...   
    
--fields-optionally-enclosed-by=...   
    
--fields-escaped-by=...   
    
--fields-terminated-by=...   
这些选择与-T选择一起使用,并且有相应的LOAD DATA INFILE子句相同的含义。   
LOAD DATA INFILE语法。   
-F, --flush-logs   
在开始导出前,洗掉在MySQL服务器中的日志文件。   
-f, --force,   
即使我们在一个表导出期间得到一个SQL错误,继续。   
-h, --host=..   
从命名的主机上的MySQL服务器导出数据。缺省主机是localhost。   
-l, --lock-tables.   
为开始导出锁定所有表。   
-t, --no-create-info   
不写入表创建信息(CREATE TABLE语句)   
-d, --no-data   
不写入表的任何行信息。如果你只想得到一个表的结构的导出,这是很有用的!   
--opt   
同--quick --add-drop-table --add-locks --extended-insert --lock-tables。   
应该给你为读入一个MySQL服务器的尽可能最快的导出。   
-pyour_pass, --password[=your_pass]   
与服务器连接时使用的口令。如果你不指定“=your_pass”部分,mysqldump需要来自终端的口令。   
-P port_num, --port=port_num   
与一台主机连接时使用的TCP/IP端口号。(这用于连接到localhost以外的主机,因为它使用 Unix套接字。)   
-q, --quick   
不缓冲查询,直接导出至stdout;使用mysql_use_result()做它。   
-S /path/to/socket, --socket=/path/to/socket   
与localhost连接时(它是缺省主机)使用的套接字文件。   
-T, --tab=path-to-some-directory   
对于每个给定的表,创建一个table_name.sql文件,它包含SQL CREATE 命令,和一个table_name.txt文件,它包含数据。 注意:这只有在mysqldump运行在mysqld守护进程运行的同一台机器上的时候才工作。.txt文件的格式根据--fields-xxx和--lines--xxx选项来定。   
-u user_name, --user=user_name   
与服务器连接时,MySQL使用的用户名。缺省值是你的Unix登录名。   
-O var=option, --set-variable var=option设置一个变量的值。可能的变量被列在下面。   
-v, --verbose   
冗长模式。打印出程序所做的更多的信息。   
-V, --version   
打印版本信息并且退出。   
-w, --where='where-condition'   
只导出被选择了的记录;注意引号是强制的!   
"--where=user='jimf'" "-wuserid>1" "-wuserid<1"  

最常见的mysqldump使用可能制作整个数据库的一个备份:  

mysqldump --opt database > backup-file.sql   

但是它对用来自于一个数据库的信息充实另外一个MySQL数据库也是有用的:   

mysqldump --opt database | mysql --host=remote-host -C database   

由于mysqldump导出的是完整的SQL语句,所以用mysql客户程序很容易就能把数据导入了:   

shell> mysqladmin create target_db_name   
shell> mysql target_db_name < backup-file.sql  
就是  
shell> mysql 库名 < 文件名  

posted @ 2010-03-31 22:15 暗夜教父 阅读(389) | 评论 (0)编辑 收藏

转至游戏大观 http://www.gamelook.com/?p=1616


简介
Boomzap是一个完全虚拟的工作室。我们没有办公室,每个人都使用弹性工作时间在家工作。我们的团队包括了十多个全职员工,以及来自世界各地的兼职员工,如美国,日本,马来西亚,新加坡,俄罗斯,菲律宾。他们其中的大多数人一年只见过一次面,甚至很多核心的团队成员都从未彼此见过面。更不可想象的是,我们当中的很多成员都过着具有移动性的生活:例如我本人经常在西雅图,新加坡和横滨之间穿梭。我们从2005年开始就一直用这种方式工作,并取得了令人满意的成效。

 

我曾经多次被问起我们是怎么成功的使用这种工作方式的,我很乐意分享这其中的经验。虽然本文可能更适合于想我们这样的小型的偏外包行的工作室,但是传统大型工作室的管理者们应该也能从中获得一些有用的信息。首先我想说明一下为什么我们会采用目前这种工作方式,这种在家工作的分布式办公模式有什么优势:

 

接触到世界各地最好的开发者:我们能雇佣全球任何地方的任何人,而不用担心办公地点和护照等问题。我们的员工不必远离他们的居住地,远离他们的交际圈,来和我们一起工作。事实上,我们有些员工正是居住在十分偏远的地方,为我们工作,他们的家距离最近的游戏公司也有上百英里。

 

更低的劳动力成本+更低的生活成本=快乐的开发者(Lower Labor Costs + Cost of Living Adjustments = Happy Developers):因为亚洲的薪筹水平比北美要低,所以我们的人力成本很有竞争力。但是我们并没有把这当成是雇佣廉价劳动力的机会,我们没有根据当地的收入水平而降低员工的薪水,而是统一按照新加坡的薪筹水平来支付员工工资,不管员工在哪个国家。可能对于美国和英国的开发者来说这不是最好的策略,但是对于俄罗斯,马来西亚,菲律宾这些地方的员工来说,他们得到的薪筹在当地应该算是最好的。这样我们就能够聘用到这些地区最好的开发者,并让他们觉得非常开心。

 

更低的日常开销:我们不用为办公地点,电脑,用电,咖啡机甚至是便笺纸而花钱。当然我们的确会花一些钱来帮助员工们购置开发设备,但是要知道他们是游戏开发者,即使我们不帮他们购买,他们自己家里通常会拥有他们所能买得起的最好计算机。我们只是避免了传统办公室里的重复开销,并用这些省下来的钱来更好的补偿我们的员工罢了。

 

自由高效地安排工作和生活:我们的工作方式允许团队中的每个人自己安排工作时间,将工作效率最大化。这不仅节省了很多通常会被浪费掉的时间,例如成员之间的交流时间等,也让员工们能够有更多的时间去做一些在传统公司中不可能做到的事,例如上函授学校,在学校教等等。这种自由度所能为员工带来的好处和快乐是其它任何传统工作方式都无法比拟的,是无法简单用时间和金钱来衡量的。

 

工作与生活的平衡+金钱=忠诚无私的员工:简单来说,这种工作方式最终的结果就是我们的员工非常乐意为Boomzap工作。任何管理者都知道留住优秀的员工是公司成长的关键因素之一,我们的这种工作方式就是不仅让我们能从世界各地招聘到最好的员工,而且能留住他们。事实上,从2005年至今,我们还没有一个员工主动离职。

 

这些听起来很不错,不是吗?是的,确实很不错。但是其中的奥秘在于你能像管理一个传统工作室那样去管理一个虚拟的分布式的工作室。我们的具体管理策略很难在这里详细表述,所以在此我仅仅列出我们管理一个虚拟开发工作室的最重要的10条策略。简单来说,这些策略虽然对于我们来说很适用,但是你需要根据你的团队具体情况,你们的工作流程,团队结构来综合考虑这些是否适用于你们。

 

10条戒律
#1: 我们从不记录工作时间
我管理Boomzap所遇到的第一个问题就是:“你怎么知道他们是否在工作?”回答很简单:“无所谓。”我知道一个专业的开发者在40个小时一周的工作时间中能够完成多少工作。每周一我将这些工作分配下去,期望它在周末的时候能被完成。如果完成了,我不在乎他们花了多少时间去完成它。如果没完成,他们就得周末继续工作来确保它的完成。事实上,我非常希望他们能在40小时内完成我分配的任务,然后用剩余时间去做自己高兴做的任何事。

关于这个问题的经济帐很简单:如果你想鼓励你的员工更高效的工作,你就不能把“工作时间”固定下来,因为如果工作时间成为了常量,工作质量和数量就会反而成为变量。在传统工作室中,“工作时间”是固定不变的常量,对于高效完成工作的最好奖励就是你会获得更多的工作安排。更糟糕的情况是,在传统模式下,较差的员工所遗留下来的工作要交给较好的员工来做,因为较好的员工在相同时间内能完成更多的事情。这样你在不经意间就给了较差的员工一个奖励:少做些事,剩下的让较好的员工去做吧。这真的很糟糕。

相反在Boomzap,我们把工作质量和数量当作常量,然后允许员工自己用时间来衡量自己的工作效率:他们有一个任务列表和一个最低标准,然后自己安排时间去完成这些任务。如果他们能更快更好地完成任务,他们所获得的奖励就是有更多的剩余时间用来休息。如果他们不能完成任务,很快他们就会发现自己周末经常需要加班。在这种模式中,不具备效率的员工自然会被淘汰,因为他们有太多的工作需要加班去完成。同时,效率高的员工会发现自己拥有了更多的自由支配时间——自由支配时间就是对员工的一种很好的奖励。每天都能让你的好员工获得奖励,这可是很不错的魔咒哦。

 

#2: 我们会做Daily Build(每日构建)
在一个你不能在大厅里游走,查看每个人都在做什么,并给他们分配任务的虚拟工作室中,你需要一种至关重要的机制,来检查人们每天都在做什么,并对他们的工作给予反馈。为了解决这个问题,我们有一套非常严格的Daily Build策略。每一天结束的时候,我们会构建一个包含了所有最新美术资源和设计要素的游戏版本。我们根据这个最新的游戏版本来评价这一天的工作。这也是我们用来评价工作的唯一标准。我对员工的工作反馈当中有90%都是直接来自于这个daily build。我确保员工每天能拿到这份反馈意见,这样他们就能知道他们十分在朝着正确的方向前进。这样的daily build以及反馈过程是我们这个公司的生命血液。如果我们的daily build走向失败,那么整个项目也就走向失败了。

 

#3: 我们将全职员工和基于项目的特别员工混合编制在一起
有些工作只要有足够多的初级员工就能做得很好,有些工作交给擅长这方面的人来做,能做得更快更好,没必要使用你最好的资源来做所有的工作。问题是你很难用固定不变的薪水来长时间留住初级员工和专才。所以我们的策略是留住那些高级的通才,并让他们来做游戏中的核心设计和架构工作,然后将大量的内容制作外包给那些专门做这方面的人,以及我们雇佣的一些工作室。因为在任何时候我们的项目当中都有超过一半的成员是来自于我们雇佣的一次性合同工,这些人员是我们能够根据需要随时变更的,或者是根据需要缩减项目组成员,而不必裁减任何我们的员工。这对于现金流的控制及其有用。

关键在于我们外包的目的不是在于减少成本——事实上我们的很多合同工的成本比正式员工还要高——我们外包的目的是将我们工作室的空闲时间风险转移出去。举例来说,我们会将所有的网页,声音,大量的手绘背景,人物肖像等工作外包出去。这些工作都是熟练工们可以高效高质量完成的工作,并且都是只在项目开发中的某些特定阶段才需要的。当我们需呀他们的时候,我们支付比正常水平高的报酬给他们,而当我们不需要他们的时候,不用为了“解雇他们”而付出任何开销。

 

#4: 我们是否雇佣他为全职员工主要取决于他的性格
我们的工作方式对于成熟的,主动的,富于自律精神的人来说是最好不过的。但可惜的是很多优秀的程序员,美术和策划并不适合在家里依照自己的作息时间表来工作。你必须及其小心地进行测试,不要雇佣那些不适合这种方式的人。

我们的做法是对于每一个要加入我们工作室的成员,先进行一个月的考核,然后给他3个月的试用期。即使是我们很熟悉的开发者也是如此。第一个月的考核主要是考核对方的专业能力,判断他是否有能力完成这个工作。3个月的试用期里则是对他性格和自我管理能力的综合考察。有几次我们缩短了对一些人的3个月的试用期,随后我们便后悔了。此后我们再也不随便缩短试用期,对于不是很熟悉的人,我们甚至会延长3试用期。

这里的底线是,如果你将要让你的员工以这种方式工作,你必须要认识到有一些人——甚至包括一些十分优秀的程序员——就是无论如何也无法适应这种工作方式的。但是对于那些独立自主,善于自我激励的人,这种工作方式能起到很好的作用。

一些人将这种现象解释为“虚拟工作室不能雇佣那些年轻的没有经验的开发者”,我们不同意这个看法。我们的一些最好的员工恰恰是那些年轻的,很有动力的实习者。而那些无法适应这种方式的人往往是一些接受过专业训练的,有长期的传统游戏工作室经验的人。这里最重要的不是经验而是工作动力和个人品质。

 

#5: 我们用“基于项目的联盟结构”来取代权威
另一个我经常被问起的关于Boomzap结构的问题是:“你不能跟他们会面和交谈,那你到底怎么管理这些人呢?”用一个制作人的说法来问就是:“你怎么保证团队中的人所做出来的东西就是你想要的呢?”回答很简单,我们不保证。公司中的每个员工都被分配在一个特定的项目中。他们知道他们所在的项目是什么,在项目里他们有很大的自由和权利。我们的策划所做的是高度抽象化的设计,就像我们的任务一样。我们不对我们的员工做细致的管理,并不是因为我们讨厌细致的管理,仅仅是因为要做到细致管理,光是大量的邮件就够你受的了。相反的,我们建立3到4个人的小组,我们允许他们按照自己的意愿去做游戏。我们对他们的管理非常松散,给了他们足够的自由度,让他们能够自己做决定。

这种方法相对于传统的集中管理式的工作室来说,更像是一堆独立项目所组成的联盟。每个小组都有独立的权利可以对设计做出很大的改动,而不必去问总部这样做是否合适,由此而减少了大量的沟通成本。这种方法对于一个项目能力很强的团队来说,可以收到很好的效果,而对于项目能力较弱的团队来说,由于缺少了整体把握,可能会导致项目失败。所以了解你的员工的能力很重要。

有一句话是这么说的,接受那些并不是你所期望的,但是被完成得很好的工作,是成功的关键。在传统游戏工作室里,最常见的情况是整个项目组耗费了大量的时间,仅仅是为了实现其中某一个人的梦想,然后他们就在这无止尽的追求中反复修改,返工,试图让游戏更接近他的想法。请将项目托付和授权给你的项目组成员,客观地去取舍那些不是你想要的但是做得很好的东西。这样做有两大好处:1)你的组员们会由衷地感到高兴,因为他们自己做的东西能被最终放在游戏里面,而不必为了别人的想法去改变什么;2)有些时候那些你不想要的东西的确会比你脑子里的想法要更好一些。

记住,将项目托付给组员的同时,要将责任也托付给他们。如果你想要你的组员们真正地对自己的工作负起责任来,你就不能老是低估他们的工作,总是强迫他们按照你的意愿去返工。“这是不是我想要的?”这个并不是问题。你最好这样问自己:“这是不是玩家所喜欢的东西?”

 

#6: 我们雇佣那些会做实事的管理者
我们这种工作方式的一大优点是你无法隐藏那些对项目没有贡献的成员。那些潜伏传统大型工作室里,老是做一些“过程优化”和“促进会议”工作的中层管理者们在一个虚拟的工作室里就找不到这样的事可做。我们也一点儿也不因此而想念他们。团队中的每个人,甚至包括公司组建者,都会在项目里承担一定的工作,例如脚本编辑,测试,关卡设计等。因为我们评价一个员工的唯一标准就是他的工作有多少被包含在了我们的游戏中。正因为我们的管理者被迫要与项目的技术层面打交道,他们会对团队中的每一个成员在做什么都了如指掌,对某项工作到底要花多少人力来完成也会更加清楚。这样对项目所带来的好处是不言而喻的。

 

#7: 我们依赖于3P:PowerPoint, Prototypes(游戏原型), Photoshop
我希望我不是第一个告诉你这话的人,但是的的确确是没有人会阅读设计文档。事实上,当我以前在一个比较大型的工作室上班的时候,我就养成了一个习惯,我会在那些超过50页的设计文档中的某处插入一句话:“谁看到这句话我就给他5美元。”然而10年来从没有一个人来找我要过这5美元。这是个真实的故事。有问题的是,业界找到了一种方法来改变这种状况,开会,开大量的会议。然而作为一个虚拟工作室,我们不能像他们那样大量开会,我们甚至都不能彼此见面,因此我们只能想出另一种解决方法。

首先,我们用一个很短的PowerPoint演示稿来作为游戏的最初设计。这个PowerPoint文档中全是图片,扫描的手绘图,从其他游戏中引用的截图,google中搜索到的各种图片。是的,一个没有文字的文档。这个文档基本上是游戏中所有状态画面的设计草案,描绘出这个游戏大致的样子以及它的玩法。接下来,我们让程序员基于这份文档做出一个粗糙的游戏原型,原型中的图片就用PowerPoint文档中的图片,没有合适图片的就用灰色方块来替代。这个游戏原型,加上我们每天对于它的反馈和改进记录,就构成了我们的“策划案”。过了一段时间之后,当这个游戏原型变得真正好玩起来了,我们的美术就从这个原型游戏的截图开始,在Photoshop中设计它的画面,然后给出游戏mockup版本所需的所有图形资源。

当这些都完成之后,我们就进入完整开发阶段。通常会有一个人坐下来,利用现有的PowerPoint文档和游戏原型,列出一些列简单的任务列表,表明要让这个原型变成最终产品,还有哪些工作是需要去做的,这样的一些列表加上PowerPoint文档和与游戏原型,3者就构成了一个更接近于策划案的“策划案”。我们的大多数游戏都只有不超过20页的文档,而且我们还在考虑这20页是否太多了点。

 

#8: 我们使用“制作人兼程序(Producer-Programmers)”
我们开发中的另一个强大的秘密就是,我们的每一个项目都由一个制作人兼程序来负责。他是一个具备较高专业技能的程序员,不仅要完成游戏的核心代码,而且要从整体上来把握这个产品,把握这个游戏里面的所有方方面面。我们以这样的结构来搭建项目组有几个原因,最重要的一个原因就是:这样一来,与美术和音乐制作者打交道的人就是那个要把这些资源加入到游戏中的人。这样就减少了很多沟通环节,减少了很多由于沟通而带来的误差。而且这样一来制作人就可以直接去实现和测试自己的新想法,而不是当制作人有了新的想法后,要先去给程序员解释,然后再由程序员来实现。

 

#9: 我们创建了一套“简明可靠(Idiot-proof)”的工作流程
传统开发工作室经常需要消耗大量的“沟通时间”来帮助美术,策划和音乐制作者将他们的工作内容集成到游戏中去。因为我们没法让两三个人围坐在一张桌子周围来解决这类问题,也因为让我们的程序员来撰写详细的资源集成文档是一种浪费和幼稚,我们会花很长的时间来开发相应的自动化工具,确保所有这些资源能很简单地被加入到游戏中。

我们最大的工具就是Excel,我们用它来编写各种资源脚本,例如精灵列表,声音文件列表,关卡设计变量,物体变量,国际化字符串等等。每个Excel表格中会有一个很大的“导出”按钮,用来导出资源脚本,任何人都不能随意修改其中的内容。请记住,自动化意味着所有的错误都是系统错误,都是可以快速定位和解决的。同时因为所有的人都能很容易地阅读Excel表格,并填充里面的变量,大多数人都能清楚地知道如何将他们手头的资源集成到游戏中,这些过程都不需要程序员来干预。

我们的关卡设计工具也是很简单的。它们都是符合“所见即所得”思路的编辑器,可以直接从游戏中开启,仅用鼠标即可完成大多数操作。这让我们的设计人员能高效地设计和测试游戏中的关卡。因为决定哪些Excel表格会被游戏引擎处理的人同时也是导出Excel表单和关卡编辑器数据的人,这个过程保证了绝对的简明可靠。

 

#10: 我们只雇佣技术型的美工
最后需要说明的是,事实上我们没有多少全职的美术人员。我们会将大量的美术工作外包出去,尤其是各种花纹,背景,肖像,故事插图等等。所有这些都能迅速地被那些外包团队完成,然后返给我们,我们仅需要少量的工作将这些资源整合到游戏中即可。我们团队中的美术都是技术型的,他们对于我们的开发工具和相关技术比较了解,例如字体,动画物体,粒子,用户界面等。这样我们不仅可以不用在团队中维持那些概念美术,而且也避免了让我们去交那些临时合同工使用我们的工具。

虚拟工作室的9个关键工具
下面这些是我们的虚拟工作室中实际使用的用以帮助我们开发的工具。这个部分不是帮下面这些工具打广告,只是这些工具跟我们的所有人都合作愉快。你可能知道更好的选择,但我只是告诉你我们的选择:

1. CVS: 如果你在开发中还没有使用任何版本控制系统,那么迟早你会发现自己将大量的人力浪费在了解决无休止的文件错乱,版本错乱的问题中。在传统工作室中是如此,在虚拟工作室中这显得更加重要。你使用何种工具并不重要,但你一定要至少使用一种。我们用的是CVS,但这只是我们的选择。任何你觉得方便的工具都可以。

2. Basecamp: 我们项目中使用的一个小巧的在线团队合作工具。每月只需25美元,就能让我们创建无限量的工程,让发行商合作伙伴能直接看到我们的日常项目管理情况,创建项目进度的简单报表。方便地发布每天的新版本和项目日志。每当有新消息发布时还能自动发送通知邮件,你能通过回复邮件来自动将你的反馈发布到网站上。很酷。

3. MSN Messenger: 我们的工作室与MSN息息相关。我们要求所有员工在工作时保持MSN在线。他们还必须设置“如果我在xx分钟内不活动,则自动显示成离开”,这样我们就能知道我们是否能跟他们交谈。我们还要求他们在MSN中设置个性签名来表明他们目前正在做什么。因此如果他们要去看医生,就写上“看医生,3点回来”,或者当他们在做项目中的任务中时,就会写上“绘制背景图片”之类的。这样每个人都知道其他人都在做什么,而不必总去打扰别人。如果有人需要安静思考,那他就把自己的状态设置为“忙碌”。我们有条严格的规定“不要轻易去打扰正在忙碌中的人,除非有特别紧急的事”。所以如果有人想集中精力思考代码,或者解决难题,他们就可以避免被打扰而分散精力。但如果真的有紧急情况会影响到其他人的工作进度,我们依然能够及时联系到他。

4. SkypeIn 和 SkypeOut: 除了经常使用免费的Skype语音电话之外,我们还是用SkypeOut来呼叫真实电话。戴着耳麦来使用的话就比用手机要方便,能解放双手,而且价格很便宜,打到全世界各地都是2美分一分钟,接近于免费。更方便的是你能设定一个真实电话号码作为你的SkypeIn号码,让别人通过真实电话来呼叫你的Skype账号,对方会感觉就像在打本地电话一样。我们的工作室SkypeIn号码设在西雅图,因为我们的大多数雇员生活在那里,拨打本地号码会让他们感到无比亲切。你还能设定SkypeIn号码的转呼,这样当你指定的号码无人接听的时候还能转呼到任何其它电话上,包括你的手机。它还带有一个语音邮箱!最终的效果是,无论你身在何处,身在美国的人能免费呼叫你,你也能以两美分一分钟的价格呼叫任何人。这样,你的电子通讯交流问题就解决了。

5. Earth Class Mail: 怎样才能方式你的合作伙伴将支票和合同寄错地址?首先,强迫他们采用电子文档进行往来。Automated Clearing House(美国的一种基于电子自动清算系统)是免费使用的,大多数合同都能被扫描并转换成pdf格式。对于那些觉得有必要亲自去写支票和传统信件的Luddites(惟恐失业而反对用机器生产者),你可以在Earth Class Mail里建立一个邮箱,他们会将邮寄给你的真实信件的信封扫描,然后给你发送一封电子邮件通知。然后你对这封信下达指令,你可以转发这封信,粉碎它,或者打开它并扫描信件内容。这并不是免费服务,但是对于那些少量的你必须去接收的纸质信件来说,这种服务是很便宜的。他们在全美都有服务点。要小心:当你设置这个邮箱的时候,一定要选择non-PO-box类型,因为有时候邮递员不会投递PO邮箱。

6. MyFax: 在地球上,如果你拥有一台打印机,那你就没有理由去购买一台传真机。只要在MyFax设置一个账号,就能让所有发送给你的传真变成电子邮件发送给你。它不仅简单干净又便宜,更能重要的是,它能让你不管身在何处,都能拥有一个固定不变的,在美国的,完全免费的传真号码。

7. PayPal: 我想我没必要再告诉你如果你需要付款给全球各地的人,PayPal是你唯一的选择。我们使用它支付薪水给所有的美国和欧洲员工,这样不仅能立刻到账,还能生成一个很棒的支付记录。而且因为你能以多种形式为PayPal账户充值,你可以利用这点来形成一个短期的信用卡效果,用以缓解一定的资金短缺问题。

注:因为PayPal在某些国家的手续费过高,我们已经决定放弃使用它了。我们正在寻找一种替代方案,但是目前我们还在继续使用它。请根据您的具体情况考虑。

8. Your Mailing List Provider: 如果你在管理者一个休闲游戏工作室,你会有大量的电子邮件往来。有很多解决方案,但是最超值的是YMLP.com。它有一个很好的工具用于从各种来源中导入地址簿,还能直接从我们的网站中收集新的联系人地址。最重要的是即使你不能使用自己的笔记本电脑,也能从任何地方获取完整的邮件列表。你也能方便地分配邮件列表职责,从而让不同的人同时维护这个邮件列表,每个人都能拥有对问题的详细讨论记录。

9. 移动性的装备: 最后但也是很重要的一点,每次在购买新设备的时候,考虑它的移动性。我的家用工作站是一台Acer笔记本,自带内置摄像头和一块小型可折叠的第二屏幕。我还拥有一台USB供电的便携式袖珍扫描仪,一个迷你打印机和一个耳麦用于Skype。所有这些都能塞进一个小手提箱里(虽然我不是机场安全岗里的时髦青年)。我能在3分钟内打包我的所有设备然后带着他们前往任何地方。任何拥有一台桌子和Internet连接的地方都能作为我的办公室。提示:只有对于不太常用的东西才选择非USB供电的款式。这在跨洋履行中很有用,能让你的笔记本变成一个电源转换器,为所有周边设备提供电力。
总结
我并不期望我们的运作方式能适合所有其他人,但是我可以向你保证:这种方式对我们很有效。我希望你能从这里找到有用的东西,更希望你能联系我,告诉我你的想法,以及你们是怎么解决跟我们类似的问题的。
下面是关于这篇文章的讨论:
问:你们从这多多不同国家雇佣人员,怎么处理各地的法律问题呢?你们的公司需要在所有这些国家都注册吗?

答:不是,我们在美国和新加坡有注册,所以在这两个地方我们雇佣正式员工,而在其他地方我们只雇佣合同工(采用的合同只覆盖到了商业游戏开发的相关条款)。
问:你们怎么处理员工将开发完成的游戏泄露给盗版者这样的威胁?

答:就跟常规公司一样处理。如果是无意的,我们就严厉责备并警告他。如果是故意的,就解雇他。不知道美国或者英国公司还有什么不同的解决方式,除了诉讼他(浪费时间)或者报告警察。
问:我还注意到了Boomzap所开发的是一些“微型”游戏。

答:更准确的说法是“休闲”游戏。我们的团队的确也能大到包含10-12个人,但是我不会用这样的团队去开发像战争机器,刺客信条这样的游戏。并不仅仅是因为你会面临众多管理和控制问题,单单是将10-12GB的海量数据在Internet上频繁传输,就会对项目造成巨大的延误作用。我们的团队一般是3-7个人,包括处理图像和声音外包的人。
问:你们说你们会做Daily Build,但是你们怎么定义“一天的结束”呢,因为你们的团队成员可能遍布在各个时区。

答:每个项目里我们都会指派一个程序员作为构建管理员(Build-master),团队中的所有其他人都要在他指定的最后期限内提交自己的工作成果,然后他就会在每天自己工作完成之后构建一个当天的版本。实际的构建时间可以根据项目组各成员的工作时间,大家一起商量指定一个时间。
问:这方法只能在你有很强的管理能力的情况下才能起作用,这也是为什么团队规模不能很大的原因,如果你的管理层次变得更为复杂,而传统面对面的管理方法又用不上的话,这种方法就肯定不行了。当每个成员都具有责任心的时候,这样的团队行为才更像是一个商业行为。总之这种方法有好有坏。

答:有个方法可以缓解这种情况,就像我刚刚提到的,相对于一般游戏公司,我们倾向于雇佣更专业一些的人,这很有用。我们当中有很多人都有妻子和儿女,在虚拟工作室里工作让我们能更容易地照顾我们的孩子。你也能通过组建更小的团队来解决这个问题,10-12个人的组织会在虚拟环境中变得有些模糊,同时拥有3个5-8人的团队,每个团队拥有自己的确定权,这样会更好一些。最后,你必须雇佣优秀的制作人,他会花费大量时间去玩这个游戏,跟团队成员讨论这个游戏,并且直接参与游戏开发过程(是的,这意味着他们要制作关卡,测试,优化等。所有我们的制作人都会身兼策划的角色)。
问:从我个人观点来看,这种商业模式其实是“坐享游戏业界的成功果实”,因为你们没有培训,不能帮助员工提升自己的水平。

答:从某种程度上来说是对的。但事实上我们拥有一个非常强大的实习计划,并且我本人也是一直教授游戏开发课程的。我本人还是新加坡一些大学和研究机构的顾问,所有有机会能接触到一些非常有潜力的对游戏开发感兴趣的学生。没能让他们加入进来真是可惜。

对于我的学生,我们提供他们每周20小时的兼职打工机会,直到他们毕业。事实上在过去的两年中我们有两个游戏的策划是由这样的内部实习生来完成的。

posted @ 2010-03-31 15:47 暗夜教父 阅读(488) | 评论 (0)编辑 收藏
转至游戏大观 http://www.gamelook.com/?p=9322#_

项目要能顺利执行其实并不简单,如果又渉及多个单位合作,困难程度又大增。取得PMP或IPMP认证,只是证明个人具备了项目管理的基本功夫,距离实际运用其实还有很大的一段距离。
 

    以下是一位项目经理的工作日志片段,我们从他的工作日志来看项目经理的工作:

    //编者注:(不知啥原因,这段缺少,百度也没找到)

    以上只是项目经理工作的片段,相信每个项目经理应该都有自已悲惨的故事,程度恐怕只有过之而无不及。项目经理到底应该有那些看家本领呢?

一个称职的项目经理应该要其备以下的能力:

1. 要易于沟通

    笔者在2002年时曾经亲自问过美国的一位项目管理专家-Dr. William Wells(曾任美国阿波罗登月计划的计划主持人),问他一位项目经理最需要具备的功夫是什幺。那时他的回答是「一位项目管理最需具备的有三件事,第一是沟通,第二是沟通,第三还是沟通」。

    请您回想一下,在执行项目时,你花费最多时间在什么部份?跟领导报告工作进度、跟客户介绍产品及说明工作成果、跟项目成员交待工作、跟单位内的其它人员争取支持、跟合作厂商协调配合事项...对项目经理来说,一天内大部份的时间几乎都是在跟人沟通。

    沟通,可以很简单,也可以很复杂。对于部份人来说,反正沟通就是把我的意见表达出来吗,有什么难的。可是在项目过程中有那幺多的人与项目有关,因此要考量的,不仅是把意见表达出来而已,而在于「在什么样的时间,运用什么样的方式,将什么样的信息,传达给什么样的人」。

    很多项目经理都是属于「被动式的项目经理」。就是「你先说你要什么项目信息,我想办法去弄这些信息出来给你」。因此,信息整理的工作基本上是没有列入工作管制的,只能够见招拆招,抱着应付的心态来面对信息的供应。

    如果换个比较主动的角度来看,项目经理先了解每个与项目有关的人想要知道什么,这些信息一定有重复的地方,然后将这些信息做个整理归类,不等你开口要,我就先提供给你,让你对项目没有疑惑,化被动为主动。这些信息整理归类的动作,直接就纳入在项目经理的工作管制之中,这样对项目经理而言,也没有任何的「意外」。

    讲起来简单,做起来其实也不难,二个小时就可以做好沟通计划,几个步骤掌握住就好:

(1) 认识项目干系人
(2) 分析项目干系人的信息需求
(3) 依照信息需求找出信息种类
(4) 将信息种类归类
(5) 决定信息传递的周期
(6) 决定信息传递方式
(7) 搜集信息
(8) 传递信息
(9) 检讨信息传递成效

2. 要想的周全

    项目经理有点像魔术师。事前先考虑要表演那些魔术,然后将道具准备好,跟助手、灯光及舞台配合,先仿真演练几遍,指示每个人互动方法,并且事先想到如果发生问题时如何处置;确认都没有问题后,开始表演;表演时要掌控会场气氛,使整个场子有高潮迭起的感觉;如果环节出了问题,要马上能够应变,使节目能够继续下去,而不是就此停顿;节目结束后,感谢每个人的合作,同时检讨整个表演的过程需要改进的地方,如此一段表演才算正式收尾。

    项目经理的责任就是掌控全场,把这段表演完美无缺的呈现出来。不过太难了,执行过的项目的人都知道,首先客户的需求不容易了解,其次计划时间不够,再来执行时问题重重,等到收尾时只能草草了事。

    表演魔术可以事先演练,找出问题先解决,执行项目可没办法先来一遍。因此项目经理能不能够将未来半年、一年或二年如何执行及因应先「演」过一遍,就对项目的成功有很大影响了。而这就靠项目经理做「计划」的功夫。做计划其实是很烦人的事,相信每个人都有经验。必须考量有多少时间、要怎幺做、有谁可以做、技术上是否可以支持、关键技术是否可以掌握等,做到这个地步,恐怕早已是满身大汗。

    //编者注:很不错的小方法

    做个小练习:取一张白纸,在纸的上缘首先将要交给客户的产品以树状方式画出来。然后在纸的中间,将如何做出这项产品的主要工作步骤(5-6个即可),以流程图的方式由左至右用箭头连起来;需要供货商供货或其它单位配合的部份,以分支的方式指向各主要步骤。

    上述步骤,就是整个计划的基础了。由上图,可以发展出细部的工作步骤及时间、所需的人力资源及预算需求、采购品项及合同商要求等。如何发展出这些细节,限于篇幅,尔后再论。

    这样还不够的。再取一张白纸,将执行这些工作步骤所可能产生的问题列出来。这个是很关键的步骤,列的愈多,将来临机处理的状况愈少(试想如果项目执行过程中可能发生100个问题,你能事先考量到99个,你只要去担心那突然出现的1个;但如果你只事先考量到1个,那结果可就不得了了)。这些问题,就是你要先期处理,以减少处理意外状况的时间。

    二张纸,一个计划的框架就成形了。这样其实还不足以执行项目,但是最起码项目经理先将整个项目执行过程大概想了一遍(就有如魔术师先行彩排一样),同时也建立一个以后细部计划的基础。由以上的练习来看,做计划并不难,重点在于去不去想,去不去做。

3. 要能够预测结果

    日前一个朋友赴美,飞机误点,航空公司没有宣布会担误多久时间,因此在机场枯坐了三个钟头。搭乘那班班机的乘客,有的人需要转机,有的人有亲友在目的地机场接机,有的人初次访美。此时在机场看到每个人都是焦虑的眼神,焦虑的原因在于他们无法知道误点多少时间,所以没有办法控制之后的行程。你的项目是不是也是如此?

    计划是「想」,执行是「做」。真的去做的时候,碰到需求、能力、技术、管理、人力等问题,都会影响到执行效果。虽然最后都可以完成,但是如果无法推测完成的时间、成本及产出,项目经理就像是那些旅客一样──彷徨无助。所以项目经理除了要会做计划之外,还要能综合研判情势,预测项目时间、成本及产出的结果。

    以一个一年的项目来说,开始之后,项目经理就负了成败责任,所有的压力都落在项目经理肩上。每天项目经理要想的,不应该只是谁的问题要怎幺解决,今天的日子要怎么过,而是一年后的今天,我是否可以将客户要的东西按时交付、公司的项目盈余目标可以达成、今天无法达成的,剩下的时间里我应该怎么处理才能达成。所以总的来看,项目经理不仅要做Micro Management(细节管理),同时还要做到Macro Management(总体管理)。而要做到Macro Management最基本的作法就是从全面预测项目结果,并且采取各种因应作法。

    要如何预测结果?今天工作延误,明天也会延误,后天也照样会延误,以后到底要如何补回来呢?传统的项目经理在现在这个时点是没有概念的,结果是到项目要结束前才在赶工,到那时候才发现所要花的钱早就把利润吃光了。

    比较好的作法是今天发生问题了,找出原因,评估这个问题如何解决。如果一定得增加时间及人力,那幺假设今天这个工作得延长二周,照着时程表推下去,所有相关工作,包含对人力资源、合同商、成本的影响为何都要找出来;再往下看,推到项目完成期限,是否会延误(不是所有工作的延误都对项目完成时间有影响的!);如果有影响,就要思考后续的工作要如何先期调整,以适度的调配资源。要做这些评估,较简单的方式,可能仍得借助项目管理软件。目前项目管理软件,不论是国内或国外的,都能做到计划功能,也能够经由计划的调整,去分析对整体的影响。

    项目经理的工作其实是很复杂。对于一个不愿意看全局的项目经理,这些步骤全部在不知不觉中被省去。但是对于一个企业来说,由一位没有看家本领的项目经理来执行重要的项目,公司的时间、名誉、获利及质量保证,不仅仅是儿戏。您的项目经理有没有这些看家本领呢?

posted @ 2010-03-31 15:25 暗夜教父 阅读(122) | 评论 (0)编辑 收藏

大家好,今天亦乐首次为大家带来flash actionscript转载教程。首先声明出处(我自己是没时间写教程啦,要直接找我讨论还好)

 版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://goday.blogbus.com/logs/14062836.html

 

今天,我也正式宣布,开始成为闪客,以往对macromedia flash的许多头疼问题都被adobe解决了,以往一直否认我喜欢做flash,现在总算可以为adobe flash 自豪。非常有系统的developing方式。RIA 平台, on screen project就不这里说了。

 

这期带来的是flash极重要元素之一,event事件。在游戏里就是所谓的Trigger. Adobe改良后的,大家谓称的“冒泡机制”。有问题欢迎发问指教。

 

=思路大纲=

  1. ActionScript 2的问题
  2. AS3解决问题
  3. 结合问题,说明“冒泡”
  4. 冒泡的问题所在以及解决方法


1 - ActionScript 2的问题

stage里有一个mc,mc里有一个btn
点选mc实现拖动mc,鼠标松开停止拖动
点选mc实现mc隐藏。
最容易想到的方法,代码如下:

mc.onPress = function() {
        this.startDrag();
};
mc.onRelease = function() {
        this.stopDrag();
};
mc.btn.onPress = function() {
        mc._visible=false
};

表面来看,这个思路是正确的。(实际上没什么思路可言,很简单的方法。)
实际怎么样?当然是不能实现。
问题:点击btn,不能触发btn的动作!!!!
解释:  因为btn处于mc内部,mc被加上了事件以后,按照as2的事件机制,mc内部的btn甚至是其他的元件都不能接受事件。或者可以认为mc的事件覆盖了mc中其他元件的事件。
从非冒泡机制来说,在btn上点击鼠标,首先接受到点击事件的自然是btn的上一层(也就是mc),然后才是btn元件。Mc先接受到点击事件,触发相关的函数。然后呢?我们要实现的点击btn的效果没了。我们可以认为mc把我们的鼠标点击事件据为私有了,不再往下传递。(如果是冒泡机制的话,这个动作就回继续往下传递到btn,然后btn会执行。)那么这种效果在as2中还能实现么?答案自然是肯定的,不过方法就复杂了。
这里就不讨论了。As3已经成为主流。
但是as3中的冒泡机制,让我们可以简单的解决这样的难题。

2 - AS3解决问题

下面来看as3中怎么实现。
代码如下:

import flash.events.*;
mc.addEventListener(MouseEvent.CLICK,mcfunction);
mc.btn.addEventListener(MouseEvent.CLICK,btnfucntion);

function mcfunction(event:MouseEvent) {
        trace("mc click");
}
function btnfucntion(event:MouseEvent) {
        trace("btn click");
}

 

看看代码就觉得,好像没用什么特别的解决方法,就加两个侦听函数,就搞定了。
这个代码自然的不能再自然了,就好像做flash 先的安装软件一样。
但是如此自然的代码下面,使AS3的冒泡机制在提供支持。 

3 - 结合问题,说明冒泡机制:
Help中有一个冒泡机制的图,相信大家都已经看过了
这里我联系实例,另外做一个图,帮助各位理解。

2D2D13C9009ACC1FF3AADD80E5C4FB85 

上图为as2中的执行原理
下图为as3中的执行原理
 2D8D966808DAEEA2C9701B5E09B334FE 
上图也就是在as3中实现我们文章开始提出的例子的工作原理。
下面详细描述一下

捕获阶段:
鼠标在btn上发出点击事件,首先捕捉到该事件的事stage.,然后事件往下传递到mc,再到btn..(如果鼠标事件发生在btn按钮中的一个label上,那么该事件还会继续向下传递,直到找到label元件。)AS2中,一旦找到了可以相应事件的函数,就停止了,不会往下传递。这个道理应该说明白了
目标阶段
找到我们的鼠标最底层的目标,也就是btn以后,那么就开始执行btn的侦听函数了。
    如果鼠标事件发生的所在位置,是mc中的btn中的一个label。那么将先执行label的侦听函数。(当然我们的例子中没有label)
冒泡阶段:
执行了目标阶段的侦听函数以后,开始冒泡。
换一个说法是,返回btn的父级元件mc,如果能找到相关的侦听函数,那么就执行,如果没有,就继续往上冒泡到btn的父级元件mc的父级元件stage。看能不能找到相关的侦听函数。

注意一个:首先执行的函数一定是目标对象的侦听函数。就像我们上面的例子一样,点击btn会先trace(“btn click”),然后冒泡到mc,执行trace(“mc click”)..然后继续往上,如果stage我们也加一个侦听函数,执行语句,那么还会继续执行 trace(“stage click”).
到达stage顶层了,冒泡结束。
说到这里,各位看官也应该明白了as3的冒泡究竟是干什么用的了

4 - 冒泡的问题所在以及解决方法
  冒泡也有问题,并不是说它有缺陷,因为出现问题无法避免。
  问题在于,
  假如在上面的例子中,我们不想在点击btn冒泡阶段中执行mc的侦听函数,我们只想执行btn的侦听函数。怎么解决?
同样的问题延伸出去,可以得到很多扩展和应用。
那么我们需要阻止他的冒泡的时候执行相关的侦听函数。
Chm中的方法有

stopImmediatePropagation():void
防止对事件流中当前节点中和所有后续节点中的事件侦听器进行处理。
stopPropagation():void
防止对事件流中当前节点的后续节点中的所有事件侦听器进行处理。

用来修改我们上面的例子
代码如下:

import flash.events.*;
mc.addEventListener(MouseEvent.CLICK,mcfunction);
mc.btn.addEventListener(MouseEvent.CLICK,btnfucntion);
function mcfunction(event:MouseEvent) {
        trace("mc click");
}
function btnfucntion(event:MouseEvent) {
        trace("btn click");
        event.stopPropagation();//修改在此处。简单一句,解决问题
}

现在可以试试,点击btn运行得到的结果就是

代码:
btn click

说明,已经防止了冒泡阶段中对mc侦听函数的处理。也就没有trace(“mc click”)了
As3事件机制远远不像这里写的那么简单,还有很多东西需要研究。
本文只为抛砖引玉,让各位能先了解一下冒泡机制。
希望能多的朋友能提供相关的学习资料

posted @ 2010-03-15 15:03 暗夜教父 阅读(429) | 评论 (0)编辑 收藏
     摘要: 什么是反射反射 (Reflection) 是指在程序在运行时 (run-time) 获取类信息的方式. 诸如实现动态创建类实例, 方法等. 在很语言中都有相关的的实现, 如 Java 和 c# 等反射有什么用在 as3 与 as2 不同, 类实例中任何元素, 如变量 (variable), 访问器 (accessor, 即 getter / setter), 方法 (method) 都是不可被 f...  阅读全文
posted @ 2010-03-08 22:00 暗夜教父 阅读(1771) | 评论 (0)编辑 收藏

打麻将必胜绝技(珍藏版,逢赌必赢)(上)

        1.147,258规则:下家丢1万,3、4、7万基本不吃,2、5万可能要吃;

  2.牌过半旬,上家开始落风子,不要碰(碰听张除外);

  3.牌局一直不胡,最好不要动牌,要打熟张,牌一动就有吃大牌的可能;

  4.下家丢3、8万,有可能手握3、5、6、8万,打4、7万要小心一点;

  5.下家丢8、9万,有可能手中还有4、7万,打4、7万要小心一点;

  6.开始几圈,除嵌张、边张外,两头张最好不吃,先上别的张,等上家再拿到这种牌时,他还会打下来;

  7.手中有1万一张,2万一对这种牌型,别人丢3万,如有混(百搭)不要吃(吃听张除外);

  8.外面风子除东风外全都见了,不能打,有可能要杠开,至少看二圈再打;

  9.外面有7万碰掉,8万见二张,9万基本上有人碰;

  10.牌开始时先丢荡张,再丢风子,但是手中风子不可超过二张;

  11.自己无混(百搭)听张,比如2、5万,上家丢2、5万,如果你吃了可听2、5、8,没有必要吃;

  12.单吊不要吊一张都没有见过的张,最好吊两头都碰掉,外面见一张的张子或风子;

  13.开始几圈,有人丢东风,手中有东西风,要先丢西风,因有可能有人拿西风对,别人丢你将被轮出一圈,东风你还可能拿对。

  知已知彼战术①怎样猜牌

  猜牌有两个内容:

  (一) 进攻时:自己所想要上的张,上家有没有?肯不肯打?已经听张了,人家会不会打?是否就打?

  (二) 守势时:人家要什么牌?人家听什么牌?

  取攻势是求自己从速上张,尽早和出,以免人家和出,虽攻亦寓守意。

  取守势时则力求猜测准确,以缩小克牌的范围,而给自己出路,虽守亦含攻崐。

  猜牌有两种情况:

  (一) 初步的:下家大概有哪一路牌。这张牌打出去,大概有人要碰,要吃,或要和。

  (二) 铁定的:这一张牌打出去,一定有人和出,而且一定是某一家和出。

  前者是笼统的,可以根据统计、观测而得到答案;后者则是确定的,决非单凭估计而可得到答案。

  猜牌的根据是什么呢?

  猜牌总是根据种种现象做出判断的。在未列举及分析这些现象之前,得先说明一点:下列的现象虽然是分别举出,看来是个别的,然而这种种现象实际上又是互崐相联贯的。

  下面是据以猜牌的现象:

  (一) 河里的牌

  就是四家所打的牌。譬如:白板见了两张,倘若你手里还有一张白板,决计没有人要,也没有人再会打给你。这个例子似乎太幼稚了,然而你正可以从这个例子来加以推论。如八筒已见三张,九筒见一张,而你手里有七、八筒的六、九筒的搭子,必然极容易吃进或和出(倘若已经听张的话)。换一个例子来说,河里绝少五、六万,则四、七万便是人家容易吃进或和出的牌。

  不要以为这种现象是显而易见的,不少入局者正是忽略了这种现象而铸成错误的,如以为八筒(以八筒见三为例)是熟张而打八筒,这样在不觉中把本人的上好机会丢掉了;或是以为一万已见三、四次(以五、六万甚少为例),四万亦属可打。这是猜牌的初步概念;而成熟的准确猜牌大多建筑在初步概念上面。

  (二) 别家打牌的次序

  这一点我们在“控制下家”一节内已经讲过,应该随时记牢别家所打的牌的先后,同时可以猜想——他为什么先打那一张,后打这一张呢?其中必有道理。

  譬如:上家先打二筒,后打四筒。他也许是拆搭子;也许是打二筒时抓进一张五筒,而打四筒时已抓进六筒(因为有四筒一对),或者仍旧留有三、六筒搭子;也许是打二筒时抓进一张六筒,而打四筒时抓进一张七筒。

  倘若上家先打四筒,后打二筒。他也许是拆搭子;也许是本来有一筒一对,所以先打四筒,并不蚀搭,而打二筒时则希望一筒来碰,或把一筒一对做麻将。

  任何一张牌都可以研究,任何一张牌都会提供一种信息,因为谁都不会无缘无故打牌的。

  也许有人会说:我就是常常无缘无故打牌。不对,你有时所以随便打牌,是因为手里的牌闲张甚多,而这也是一种信息,也是一个缘故。

  下面再做进一步的解释。

  先打二筒,后打四筒是常例:先打四筒,后打二筒是反常。因为二筒较近幺、九。凡是反常的打法,常常含有明显的道理。

  倘若上家先打四筒,后打二筒,而河里并未见过一筒,他手里有一筒一对,便更有把握了。倘若能再有其他的现象来旁证这一点,那上家手里有一筒一对或一坎,便可准确地加以证实了。

  据以猜牌的现象彼此都有联系,这便是一个例子。当然这还是最简单的。

  (三) 打牌的姿势

  如手里是一副大牌,现出一种特殊紧张或过分仔细的精神状态,,象把十三张牌数一数,每打一张牌都可以考虑;在听张之前一张,故意把牌打得重一些,向桌上拼命一拍;正想吃进某一张牌,突被对家碰去,把拿出一半的牌重新缩回;想碰而不碰……。

  这种种动作都无形中告诉你:他手里有几张什么牌,并且一般都是不会错的。一个麻将技巧不熟练的人,几乎每一副牌都有这一类的表示;而熟练者有时也难免,你总可从中知道他手里的几张牌,再从旁证来加以证明,便可进一步知道他手中有什么牌要打,要吃,要和了。

  (四) 口中的惊叹语“啊呀!”或是类似的感叹词

  这大多是表现出某一张牌给人家碰去了,或抓去了;牌的变化时常会使人无意中说出许多话来,而从这些话中可以找到某些线索。 言语及姿态有时是故意制造出来的,然而只要能记牢他所说的话和动作,与牌和出后他所摊出的牌来加以对照,便可知道他的脾气——是真情的流露还是装模作崐样。

  打麻将需要应用心理学。倘能看透牌的路数,再加上心理推测,那猜牌的功夫便水到渠成了。

  (五) 最后的几张牌

  当一家的牌手中有四张的时候(或者时间已迟,手中剩七张牌时),他在抓进一张之后,换出一张来,你便可猜到他手中所有的牌。不过这种猜测,应该随时把他以往打牌的次序,和他的上家所打的牌加以验证,方可得到正确的答案。否则未必是准确的。

  在各种各样的牌都打过之后,所剩余的牌便可一目了然,别人听张的可能配合便有了限制,在这种时候,你便能寻到一种“有去无来”的答案(当然也应该有旁崐的佐证来确定)。

  上面举的五种现象,可以作为猜牌的根据,然而最根本的还是在掌握牌的路数。

  (1)很早打中、发、白,当有做平和的企图。

  (2)在打过二、三、四、五、六、七、八之后,打幺、九,非拆搭,即去衍张。

  (3)拆两头搭子,不是有做一色的嫌疑,就是大幺对子很多。

  (4)先打一,后打二,紧防三、六。

  (5)先打九,后打八,紧防四、七。

  (6)开大幺对,有好搭。

  (7)想吃不吃,必有同样的牌多张。

  (8)想碰不碰,不必防其碰大幺。

  (9)麻将头,不要三、四、六、七。

  (10)嵌二、八是上好搭子。

  (11)牌将完,需防半熟牌张。

  (12)幺、九少见,必有对子。

  (13)临危(指有大牌或将抓完时)而打生张,手中必有大牌。

  (14)打牌不顾一色,居心不良。

  上面所举的不过是最容易理解的,如能根据这些例子再加以融汇贯通,便能摸到猜牌的途径了。

  比如:在打过中心张子之后,突然又从里面打一张幺九(从原来的牌打出来,与抓来就打,分别甚大,打牌时非注意到此点不可),说明“非拆搭,即去衍张”,然而这二者又从何分别呢?

  倘若你有五、八索搭子,上家打了一张九索,当然可以希望他打一张八索给你,然而他在第二张抓进时,换出一张五索来,你便可不必再等候他的八索了,因他决不是拆边七索或嵌八索的搭子。倘若你能从另外的现象中看出,例如河里不见八索,而七、九索已各见三张,便可认定他有八索一对或一坎;否则他是抓进一张六索,换出一张九索的。

  又如先打一,后打二,固然要提防他有三、六的搭子;然而也许他是简单地拆一个边三的搭子,你紧防三、六岂非徒劳了吗!所以,在应用这种路数时,也得瞻前顾后,才可有比较可靠的答案。

  现在,我们要进一步来考虑一个更难以断定的因素,以作为猜牌的根据。

  “他是怎样打牌的?”这实是一个最紧要的因素,更透彻一些来说,他打牌的路数是怎样的?他的麻将技巧水准如何?他有无特殊的牌气?

  孙子兵法所谓:“知己知彼,方能克敌”。叉麻将亦应应用这个原则。根据我们的经验,可把麻将技巧分为上中下三级。而这三级是根据下列现象来区分的:

  (一)抓进六筒不会换出九筒的 譬如有七、八、九筒一顺,抓进一张六筒仍打六筒——这类人的麻将技巧仅能管理现成的牌,而换一张打的念头还不能产生。当然,听三交而不听,生熟张不甚明了之类的毛病也包括在内。 这是下级。

  (二)抓进六筒会打九筒的 同前例,能换打九筒,说明已看清九筒是大幺,比较地不易给人家便宜。他已经了解生熟张之别,在全副牌的过程中,可不至于蚀搭。 这是中级。

  (三)抓进九筒而换打六筒的 同前例,能这样打,说明水准更高了,因为他抓进一张九筒,而知九筒是生张,六筒的危险倒少,已能解除幺、九熟于中心张子的死限制,这显然是更进一级的技巧了。他不但能看透生张的分别、而且还会因时制宜,随机应变,已到出神入化的地步了。 这是上级。

  也有人用另外一种现象来区分的,即:

  下级——不知听一、四、七而听四、七,比如有二、三、三、四五,抓进一张六,不知打三而打六。

  中级——听一、四、七。

  上级——情愿不听一、四、七,而听嵌七。

  其理由与前述之例相同。下家者顾自己还顾不周全,中级者已能顾全自己而尚未臻化境,上级者则张张见血,知己知彼,能攻能守,灵活应用。

  在猜牌的因素中,这个估计是最根本的;因为你倘若对每个入局者的水准没有正确的估计,便会时常怀疑自己的猜测是错误的,以为他所打的牌出乎意料之外。其实是你自己想得不够周到。

  譬如:一家有八、九万两张,抓进一张六万时,在中、下级技巧必打九万,而上级技巧就未必如此,明乎此理,猜牌之术便属上乘了。

  阶段舍牌的策略

  在麻将中,舍牌十分重要。摸、吃、碰、杠属于进张,舍牌则是出张,故麻将技巧之高低、竞技之胜负,舍牌系于一半,甚至不止一半。麻将高手打得“精明”,主要是精在“舍牌”上。

  舍牌之重要性在于:

  第一、舍牌的安危可以打乱摸牌的顺序;

  第二、舍牌可决定各家战术的运用;

  第三、舍牌可促进他人入听的升级;

  第四、舍牌可破坏他人的战略部署;

  第五、舍牌又能牵制他人的牌势;

  第六、舍牌可放铳成全他人食用;

  第七、舍牌可迷惑他人,使自己食和;

  尤其是打新潮麻将,你舍牌精明,不点炮,既使别人和了88分值的大四喜、大三元,而你也只丢了8分。所以只要舍得精,不点炮或少点炮,再和上几把高番牌,大概就能稳操胜券。

  1.初期舍牌走单张

  初期舍牌大体上为一至四五巡。起手13张配牌,各家都不同程度地起几个长单张的风箭牌、么九牌和中张的荡张。这个阶段的舍牌顺序,一般是:风箭牌、么九牌和中张的荡张牌。

  牌战初期,一般是先舍单张的风、箭牌。打字牌的技巧是:先打风,后打箭。打风的次序是:先打客风,后打圈风和本门风,最后打中、发、白,也可以把本门风放在箭牌的后面打。

  如果起手配牌时,风箭牌就有八九张之多,且又有三对,就要留下,而奔“字一色”或“大小三元”、“大小四喜”或“全不靠”、“七星不靠”或“混一色”高、中番种去努力。

  2.么九牌的去与留

  行张时,如无风箭闲张,或已把风箭闲张打完情况下,万子、条子和筒子的中张(2至8色点)容易抓入靠张,不便先打(但设计牌局时,考虑到“清缺”、“混缺”及“缺一门”者除外),一般先把手中的么与九闲张打掉,因为么、九闲张各据首尾,抓靠张的机会比中张少一倍,所以在牌桌上,紧接风、箭之后,各家多都打么、九闲张。

  大凡起牌后,出牌不是风箭,也没有么九,出手就见中张或边张,说明这家牌局较佳或设计十三不靠,其余三家行张时,须多加提防。对于么九闲张的打法,也并非没有先后,常有以下几种情况:

  (l)对设计“清缺”、“混缺”、及“缺一门”的牌家来说,应首先打掉不需要的门类中的么与九;

  (2)在牌局中,现有的牌副、搭子或对子都以中张组成的,那么设计牌局时,必顺考虑“断么”的可能性,无论哪门的么、九牌,均可打掉;如果牌局中搭子和对子较多,准备依靠吃、碰、抓来组副,考虑留下一张尚未见面的么或九的荡张作单钓叫牌,成和希望就较大。所以,此种情况的么、九取舍,就要视牌局发展而定了;

  (3)如果牌副里已有l、2、3或者7、8、9的顺子副,那么,再打么、九闲张时,应与设计的“一般高”、“姐妹花”作一权衡,是打是留?先后次序都要统筹考虑;

  (4)对于牌局组成的后期,在原有边张搭子8、9的基础上,抓进同类牌6时,即应打9留6,成6、8嵌搭。小头也一样,如在原有边张搭子l、2基础上,抓进同类牌4时,也应打‘么”留个成2、4嵌搭。

  (5)凡属设计十三不靠牌局,除留箭风外,对于万子、条子和筒子,诚然保留么、九最佳,中间不靠牌张可扩展到4、5或6,进张副度拓宽,利于上张成和,诚然,这时的么九闲张,非但不能打掉,仍应视为牌张中的上乘了。中张,一旦上张成对,即好牌局中上乘的麻将头。类似这样的中张,闲而有用,当然在行张中是不会轻易舍出的。

  3.中盘舍牌观三家

  中盘阶段是作战激烈、紧张的阶段,一取一舍都关系到胜败,所以每舍一张牌都必须真正地把握住安全关,尽量做到所舍的牌让下家没有吃的、让别家没有碰的机会,更不能让别家有成和的可能。

  麻将实战中,牌势只要进入中盘阶段,各家的手牌无时不在起变化,摸打一至二巡牌后,以前的熟张在这个时候可能已经成为生张了,以前认为是安全牌,现在很有可能成为危险牌,此时若舍出不是被下家吃起,就是被其余的家成和,真是隔巡如生张,旧安变新危。

  麻将的舍牌要根据牌面和牌桌上的变化来制定对策及战略战术,做到看上家、默下家、盯对家。

  看上家。也就是应看明白上家打出什么样的花色牌,吃起、碰起什么花色的牌。因为他所吃、所碰之牌,即是他手中需要的花色;打出的牌,也是你可以吃起、碰起的花色。这样,你可判断出你自己应保留什么样的花色,才有迅速吃、碰牌的机会。如果你手中的花色,也是上家想留存、没有舍出来的,自然你就没有办法靠吃碰牌来迅速组合手中牌阵了。

  默下家。与看上家相反,下家正想靠你手中打出的牌来判断自己手牌中的去留。若你会出的牌,多是下家正想吃起的,那他当然就会很快地吃成一副一副的牌摊开亮出,并且叫听。故在打牌时,尽量不使下家能吃上自己舍出去的牌,就成了十分重要的思考内容。

  盯对家。既看上家、默下家,也必须盯住对家,这样三家人需要什么花色的牌,甚至可能需要什么牌点也在你预料之中,知己知彼,方能百战百胜。对于自己,要做什么花色的牌,成什么样的和对自己有利,必须考虑周密,这样才能一举成功。

  4.终盘舍牌防点炮

  终盘阶段是大家短兵相接、交锋决斗定胜负的阶段,丝毫不能疏忽大意。进人终盘阶段,有以下两种情况:

  一是四人中的两人或一人,依然保持着听牌,窥机食和。但因牌势的发展趋平,只好强行打牌,应酬战局。其他的各家均以防御为主,最后以少失分而收场。

  二是四人继续互相牵制,打出安全牌。事实上,其中一人或两人,早已放弃听牌,采取少失分的作战方案。

  凡是牌坛高手的对阵,这种局势并不是少见的,与初手者聚桌娱乐,推倒食和大不相同。设想,牌桌上有一或两名低手,欲使战局发展到终盘阶段,似乎是不可能的。

  下面谈谈几种牌的情况处理:

  ①放炮危险牌

  这里说的危险牌,是指将其放出后使他家成和的绝对危险牌。当牌局进入中盘阶段后期,对于任何舍牌,都充满着重重危险。

  实际上,有些牌在众多场合下,并非危险牌,但是感觉上又认为不是安全牌,这就是被放炮的KB观念影响所致。

  所以在这期间,每舍一张牌对旁家来说都不可能是安全牌,那么如何处理这些危险牌,需要进一步地探讨。除了绝对安全牌以外(如字牌东碰出,又摸入第四张),其他牌多少总带点危险性。现在就以放炮的危险牌为焦点,观察该点的变化。

  第一:放炮危险牌是指对方已经听张后所要的牌,一旦出现,即可成和。假如现在手中有某张牌,并非直接放炮的危险牌,但由于这张牌被对方碰而导致他完成大番的听

  张状态,那么这张牌应视为放炮危险牌。

  第二:如能看准对方在中盘战后期的番台状况,那么凡与其番台无关的种类牌,一大体上可算作安全牌。

  第三:放炮危险有时可从各家舍牌相的途径来推测,切舍种类少的牌,危险性大,尤其是生张牌,放炮危险性更大。

  第四:自己手牌中的暗坎和该同一线上的牌,是放炮的危险牌。例如手牌中有暗坎3条3张和6条1张,当桌面上一直没有出现这样的牌时,就可能有人听张的叫牌是3、6条,而他和牌的叫牌张数有二分之一把握在你的手中,这样就能极大程度地阻止他获胜。

  ②高度危险牌的舍法

  知道是放炮牌,谁也不会往外打。但是,如遇怀疑性的高度危险牌,就要看舍牌者的胆量和到底对该局牌的胜负抱什么样的期望而定了。自中盘阶段后期到终盘阶段,如自己的手牌没有可能构成多番牌姿,而对方的手牌颇有多番形态的预兆时,最好死了心不和,不打危险牌,甚至拆掉面子安全牌,以度过最后一两巡的摸牌难关,直到黄牌。

  ③放炮牌的处理方法

  第一:编入组合面子。牌局到了终盘期,既然放炮牌不能打,也不能孤单单地留在手牌里,妨碍自己和牌。这样,最好将放炮危险牌编到手牌牌面中去,这是最安全而且是最有利的战法。因为这样一来,这张放炮危险牌的左右联络牌也都打上了保险系数,均不会轻易舍出,使危险性大大减少。

  第二:立即退出胜负圈。麻将牌竞技中,能当机立断地退出胜负圈的做法,是极为明智的。尤其是多门听牌的牌姿,明知摸入危险牌,但惟恐扰乱了成形的牌势,却执意舍出,奢望侥幸过关。殊不知这样战法将会胜败立见,决无放炮与过关的五五开之说。

  第三:没有安全牌的困惑。在形形色色的牌姿中,常出现有人觉得手牌中没有安全牌可打的窘迫感。诚然,这是人为造成的,大体上可分为两种类型:其一,手牌中显露的朋组过多,饥不择食地见吃就吃、得碰便碰,既无算计,又不顾及战略,结果手牌相对减少,周旋余地缩小了,调整面也窄了。手头仅有几张牌,即出现没有安全牌可打的情况,以致给自己带来很大的困惑,甚至有放炮的危险。其二,虽然呈现未吃未碰的门前清状况,但一手13张牌仍觉得没有安全牌可打,这其实是恐惧心理。

  照常规战法,手牌中没有安全牌的说法是不切实际的。以三家对手均已听牌而言,每家通常是两门听,也就是说三家合计叫听六种待牌而已。这对门前清的13张手牌来说,至少手头上还有一半以上的牌是安全牌。即使手牌少的人,也不见得张张与他人叫听的待牌分毫不差。问题在于是否愿意舍听而后退一步,是否懂得计算舍牌相。所以,打出一张牌是不是安全,须凭技术高低去审定。

  打麻将必胜绝技(珍藏版,逢赌必赢)(下)      

         麻将理牌的实例剖析

  ①没有听张希望的牌姿:

  例1:中、白、发、东、南,l、2、6、9筒,6、8条,8、9万。

  显然,这铺牌里有5个单张字牌和3张老头牌(么九头),无法形成九种么九牌的倒牌。这种牌,可说是相当恶劣的手牌了。尽管其中尚有3组可构成面子牌张,但毕竟是机遇不佳的边搭l、2筒和8、9万与嵌搭6、8条。根据牌谱中所谓“起首三张单风箭,兵牌必难求听和”之训,这种牌即使每巡进张,也是距听张食和相当遥远的,大可不必认真组牌,势必作好不和的思想准备。

  所以在舍牌时,应视海牌而定,客风轻易不能抛出,三无牌也需慎重,否则将会加大别家的番和。待到别家打出之后,再追打熟张不迟,首先舍出的当然是老头牌了。

  在这种恶劣牌势的情况下,除追打熟张牌外,应留神对手中的某一家,估计和牌平平,即可尽量供牌,促其早成早和,少失番分。

  例2:中、发、东、北,2、5、9、9条,4、5、9筒,2、4万。

  这种牌势虽胜于上例,风箭少了一张,对子、搭子加嵌搭,单张中张牌5条两头尚有牌张,联络价值更大,但是距离听张仍然差得很远。如强行奢望和牌,必失大误。

  例3:发发、西、白,1、5、9筒,1、2、4、8条,4、5万。

  四张字牌之内,只有绿发对子为一要素。虽然1、2、4条为复合面子,但待牌只有3条一种,决非有利形势。4、5万与中张牌5筒给整个牌铺带来一线希望,惟独缺少麻将头。

  倘若依靠模入一张将头牌的话,至少也须换5到6次以上,这么遥远的行程,恐怕不及来张时,早已败北。故而战略上与例2相同,照例1打法,多是有益无损的。

  ②接近听牌的“未知数”:

  例4:中中、白,1、4、5、8筒,3、6条,1、2、7、9万。

  此例的红中对子系一要素,加上4、5筒子,1、2万边搭以及7、9万嵌搭,合为面子牌的4个要素。倘若3与6条中的一张牌与摸进的任何一张中张条子再组成一个面子的话,即有了

  5个要素,从而具备了听牌资格。

  牌谱中有句话:“副副求和,败可立见”,说明求和心切者,往往极易他人放铳。因此,每当使用本例牌促成叫听之后,必须居安思危,不要抱太大希望。待你手牌理顺之际,殊不

  知别人已早“磨刀霍霍”,准备食和了。

  例5:东、南南、西,1、2、3、6筒,2、3条,1、7、9万。

  这里已有现成的4个要素,即门风对子一组,123筒一副,2、3条搭子与7、9万嵌搭,当然如能摸进一张与中张6筒相联络的牌,牌面即可重现生机了。

  对于上述要素,一旦吃碰形成面子牌朋组时,就须在理牌时小心斟酌了。虽说单张的东、南两风属客风牌,本可舍弃。但是,对于本例实战情况来看,有时留下一张风牌(自然是“海”内尸牌未见或只见一张的),作单钓叫牌,对和牌极为有利。

  例6:白白、南,1、2条,3、4万,1、222、6、8筒。

  乍看,这副牌比较整洁,有白板一对,1、2条边搭,2、4万嵌搭,6、8筒嵌搭,以及1、222筒的复合面子共5个要素。但是,这种牌的潜在性危机极大,无论边搭、嵌搭与复合面子,可待牌全部是3与7的尖张牌,这些尖张牌对于高手而言,极难舍出,单纯依靠吃进组成朋组的机会是极少,尚余的一半机会只能靠自己摸进了。假如平均每摸3手可得一张的话,起码也需12巡摸牌才行。

  例7:东、西,1、2、3、77万,2、5、8条,3、7、9筒

  这副牌反而比上例牌有利。尽管单张牌较多,但极易得手上张,这是老麻将们坚信不移的。字牌虽有两张,且为客风牌,即便打出也无大碍。这里,7万对子为将头,123万一副,7、9筒为嵌搭,虽说只有3个要素,但上张极快。其中万子与筒子任意进牌,都能组成复合面子,决不成荡张。对条子来说,首先应打掉中张5条(这是许多人所不愿的),从战术上看,舍出5条后,尚有2与8条两张,除摸进倒运的5条外,无论进什麽张了,都能组成一对要素,这是高手们非常明白的。

  所以说,倘若打的顺的话,最快只需5手(摸5次牌)便可叫听了。

  ③具有成和把握的牌姿:

  例8:东东,2、7、8筒,3、5、7、8条,1、3、4、6万。

  这副牌本身已经有5组要素,除单张牌为2筒外,可将复合面子中的1、6万视为单张牌对待。

  首先,舍牌是2筒无疑了。万一上张牌出现嵌2万或嵌5万时,就可拆掉3、5条嵌搭。反之,出现嵌4条的话,首先应打出6万。因为6万中张的危险性大于老头牌1万,在旁家尚未上手之前舍掉,可避免放铳。一旦叫听叫和时,再打1万,也不致失误。

  例9:南、发发,3、5、6、8筒,5、6条,11、3、4万。

  这也是5个要素齐备的牌。除单张南风牌外,复合面子的3、8筒,也可视为可舍的单张牌。

  如果进张南风对或任意一张筒子时,舍牌就应仔细了。当然,首先上筒子牌,即将南风打出,倘若再进筒子,应考虑舍掉4万较为合适,从而保留1、1、3万的复合面子。

  不过,从一般玩牌者的习惯来看,不少人宁可拆筒子,说什麽也不原打4万。这种舍近求远的打法,仍属下策。不难看出,这副牌的绿发对容易碰出,决不会留在手头作将用,那麽唯一的将头只有1万了。只要进张筒子,拆舍3、4万搭子就比较合理。诚然,对于5、6条搭子而言,因为纯属中心张子,一旦拆舍出去,极易被旁家吃进,所以不如不舍为妙。

  例10:西,5、6筒,2、3、666条,2、3、4、6、7万。

  这是极佳的面子牌。无论是起手配牌或是两三手后的面子牌,只要吃牌或上张,都不应留两个搭子去寻求将头。从实战战况看,应毫不犹豫地将刻子6条舍去一张,既能保留将头,又构成了平和。此系上策保和无疑。相反,如果舍不得6条刻子,很可能会坐失良机,这就是牌谱的胜决所在。

  例11:南南、西西,88条,3、4筒,1、2、3、4、5万。

  此例有3组对子,以要素而言合计6组,故此多余一组要素,在这种情况下,势必要拆舍一组。诚然,两对风牌较易碰出,所以当有人打出其中一张字牌时,不必急于去碰,反而就以该门风对作为拆打对象,以便牵制下家。

  对于8条来说,最佳是进张7条,打出8条,形成搭子牌面,使满铺牌构成较好的和平局面。如果牌桌正好遇上南风圈,自己又坐于第三家,那麽两对风子全应碰出,而拆舍3、4筒。倘使两个搭子均先吃牌,就应拆舍8条对子,以两对风子作为双风子作双碰听和了。

  祝大家逢赌必赢!

posted @ 2010-03-02 09:39 暗夜教父 阅读(379) | 评论 (0)编辑 收藏

“开会”,在现在的商业运转中,这两个字的名声非常不好,因为真正能通过会议这个形式取得什么成果的很少。我记得Dilbert(美国漫画家)曾经有一幅漫画这样画的:几个人围着桌子坐着,会议组织者说“今天会议没什么特别的议程。像往常一样,我们就就抱怨下、做些没什么干系的发言就好了”。

现在会议基本上就是这样的,大部分的会议都是无序的、没有激情的、没有效率的。但我们的会议是可以开的更好的。

当我决定写一篇关于如何开展有效会议的文章,我找到了Marissa Mayer (Google搜索产品的副总裁,see BusinessWeek.com, 6/19/06, “Marissa Mayer: The Talent Scout”),在我所认知的人中,她在会议方面有着最丰富的知识,并且她领导创造了当今一些最有创新意义的产品,这也让我为她在会议组织方面的才能上加了不少分。

Mayer平均每周开差不多70个会议(SweetRiver译注:会霸…囧rz…),并且作为最后一道关卡来把关Google工程师、项目经理向Google创始人Sergey Brin和Larry Page来陈述、推销他们的想法的机会。一共有8个由directors, managers和engineers组成的团队在产品开发的各个阶段,向Mayer汇报。

在Google这样的公司里,大部分的工作都在会议中开展,Mayer的目标就是确保她的团队有明确的工作指令、战略方向以及有足够支撑行动的信息,并且同时让他们感觉有前进的动力并受到了尊重。Mayer她成功开展高效会议的6个秘诀就是:

1. 有一个明确的议程

Mayer要求每个会议都必须有明确的议程,内容包括参会者希望讨论的问题的大纲以及他们将如何最有效地利用自己的时间。当然,议程需要有一定的灵活性,Mayer觉得议程更多地扮演这样一个角色的工具:议程迫使参会者仔细思考自己希望在会议上所达到什么目标以及如何最好地去达成这样的目的。

2. 指定专门的note-taker(SweetRiver注:和我们一般概念上的“会议记录员”还不一样)

Google的会议一大特色就是有很多的投影…..。一面墙上投影现在的presentation,旁边会再有一个投影仪展示当前会议的记要(SweetRiver注:原文想要表达的意思应该是不仅要找一个专门的会议记录员,还要专门的投影实时地展示当前会议的记要,以确保参会人员能在会议上达成真正的一致),可能旁边还会有一个投影显示着一个4英尺高的在走的计时器!!Google高管们相信,通过制作一份官方的记要,可以最大程度地马上消除不准确性和不一致性。

那些没能参加会议的人会收到一份会议的记要。当有人试着回想会议的决定、团队前进的方向、接下来需要做什么工作,他们可以有这样的标准官方记要参考。

3. 钻小会(Carve out micro-meeting)

Mayer留了大量的小块时间段去参加那些有特定议题或者关于特定项目的小会。比如,在她与创始人兼CEO – Eric Schmidt的每周2小时的会议中,她会抽出5-10分钟间隔(或者更长,这根据主题而定),去参加那些特定领域的会议,如关于站点表现的周例会、新产品发布等等。

如果有什么紧急情况发生,这种方式给了Mayer足够在会议前调整议程的灵活性。这也慢慢让会议变得更有重点。Mayer对她的团队成员也是采取同样的策略,更多是5-10分钟的短交流(她的行程安排所允许的最短时间段),而不是30分钟的促膝长谈。通过这样地在一个大块时间段钻出时间参加小会,她可以收获更多。

Mayer有着engineering和computer science方面的背景经验,自嘲地称这些micro-meetings是“降低流水线上的延迟” (reducing latency in the pipeline)。这就是说,如果她的一个员工想跟她讨论一个问题,这位员工可以在Mayer的某一个大的时间块上跟她预约一个10分钟的micro-meeting,而不是等她下一个空闲的30分钟,——这30分钟可能2个星期都等不到。

4. Hold office hours.
SweetRiver译注:Hold office hours的意思可以看下Harvard Business Review的这篇文章。其实就是类似“答疑时间”的这样一个概念,即某人固定时间待在office里,保证你在这段时间的时候能找到他,跟他交流。这样的“答疑时间”可以让你更加亲近您的员工、更加了解公司内的事情、更加有机会听取意见和新的idea、更加有效的处理来自下层的一些问题,特别让你不会变成那种永远看不到的untouchable的神人一样。我没有想出比较好的中文词组来表达这个意思,所以下面都会保留英文。

Mayer的这条秘诀来自她在Stanford做computer science教师的经验,她也是在Stanford遇到了Google的两位创始人。Mayer的office hour每天下午4点开始,每次一个半小时。

员工将他们的名字写在她office外面的一块白板上,然后她按照先进先出的方式对队列进行处理。有时候是PM需要她在一次市场活动上的认同,有时候是一些员工想向她sell(推销)自己的一个想法或者设计 (see BusinessWeek.com, 6/30/06, “Inside Google’s New-Product Process”).

Mayer说: “我们很多有意思的产品都是在这个office hour里捣鼓出来的,Google News, Orkut [Google's social networking site](SweetRiver译注:这里作者居然给Orkut加了一个英文注释,看来Orkut是比较痿,囧~~), Google Reviews, and Google Desktop这些产品的idea都是首先在这种office hour里出现的”。在这短短的一一个半小时的office hour的时间中,Mayer可以开多达15个会议,平均每个人7分钟的时间…….

5. 要数据,不要政治 (Discourage politics, use data)
Mayer曾经谈到的“9个关于创新的意见”(”Nine Notions of Innovation”)中的一条就是“要数据,不要政治”(see BusinessWeek.com, 6/19/06, “9 Notions of Innovation”).

一个公司里,如果老板会根据他对人的喜好而不是他对产品和设计的客观想法来做决定,如果参加会议的人都会觉得老板会给他所喜欢的人所作的设计开绿灯时,那这条意见就非常有必要了。

Mayer相信这样的价值倾向会让员工士气低落,所以她把审批流程(approval process)变成了科学。Google会根据一些明确的度量指标来选择好的设计。选择是基于价值以及事实,而不是个人关系 (Designs are chosen based on merit and evidence, not personal relationships)。

Mayer不希望在设计会议上听到类似“I like”这样的句子,譬如“I like the way the screen looks”。而她会鼓励类似“he experimentation on the site shows that his design performed 10% better”这样的言论。Google是建立在客户反馈数据驱动的企业文化上,而不是建立在内部政治上(现在很多的企业都是),所以对于Google来说,“要数据、不要政治” works。

6. Stick to the clock.
为了给会议增加点压力以保持参会人员的注意力,Google的集会一般都会非常特色地在墙上都投影一个巨大的计时器,给特定的会议或者议题做倒计时…..。这真的真的就是一个网上可以下载的timer,跑在PC上,然后投影到4英尺大小。

想想当从会议室外面来看里面的情况,那一定非常疯狂:墙上同时投影着若干的影像:presentation, transcription(参第2条), 然后还有一个mega-timer!不过,在Google,it makes sense,在创造性的混乱中引入结构!!通过这个Timer给会议带来的轻微的压力感使会议保持on schedule。

Mayer同时对这个timer也有一个忠告:对timer保持健康的幽默感。(同时,我对Mayer的采访的timer也快到到时间了,但是Mayer让timer变成了一个有趣、友善的提醒物,而不是对我们谈话的粗鲁打断。)

请记住,这些会议技巧在Google里用的很好。虽然可能并不适用你们公司,但这六个秘诀应该可以给你一点如何让会议不浪费时间、更加有效的良好的启示。

posted @ 2010-03-01 12:49 暗夜教父 阅读(215) | 评论 (0)编辑 收藏

一、写这个文章的起因:

        经常遇到很多人想学习Flash,但是不知道从何学起,有的朋友甚至对于学会了Flash,能做些什么也很疑惑。

        本人结合若干年Flash学习研究经验,给想学习Flash的朋友一些建议,也欢迎大家访问我的空间,http://hi.baidu.com/billypc给我留言。如转载本文,希望多多宣传本空间,谢谢。

       一般来说,Flash的学习主要有两个方向,一是专攻Flash动画,一是专攻Flash编程,当然也有动画和编程都学习的很到位的人,那是牛人。不过这里我主要分析一下Flash的这两种方向如何开始学习,如何快速掌握。

二、FAQs

问:学习flash做动画需不需要美术基础啊?
答:
        首先,要说明的是,Flash动画也分为几种。

        最重要的应用就是做动画片,比如早期的ShowGood三国,小小,现在的小破孩系列,开心驿站系列,燕尾蝶等。这些都是动画片制作,这一类的flash需要有很好的美术功底,需要有诸如手绘,视觉感,镜头感等相关的专业知识。这一类的动画制作基本上需要美术和动画的专业知识。而Flash只是作为一个动画制作的工具而已,一个动画片在从开始到结束,更多的需要的是美术及动画方面的专业知识。

       另一类应用是Flash广告和Flash特效,这一类Flash大量应用于网络,从网站主页Flash动画,到网站内部的一些广告,一些吸引眼球的效果,都属于这一类应用。一般学习Flash的人,基本上都在做这样的东西。包括一些初学者在内,都认为这就是Flash,其实这只是Flash最简单的应用。制作这一类的Flash一般需要一些创意,有一定的视觉感,有美术基础的人会更加得心应手。有时候会需要掌握一些基础的flash as,比如制作flash菜单,flash跳转效果等。

       Flash在动画的制作过程中,主要扮演的是工具的角色,是目前动画制作中效率比较高的工具之一,而一个好的动画,并不依赖于你用什么工具,而依赖于你的专业程度。专业知识越扎实,创意越新颖,做出的动画就越好。而工具的学习仅仅是第一步。


问:我也不知道应该学习哪个方向,动画和编程哪个好学啊?
答:
       学做动画,和学做编程,这样两个方向,其实不仅仅是做什么的不同,也是思维方式的不同。

       一般来说,做动画受视觉因素影响,而编程主要受逻辑思维影响。从很宽泛的角度上来说,学动画,就是学感觉,学新思维。而学编程,就是学逻辑,学思维方式。美学不仅仅是能感觉到,还是一种创意思维,是感性的。而程序逻辑则完全是一种逆向思维,是理性的。

       一般情况下,逻辑思维可以通过培训等,在短时间内锻炼出来,所以编程应该来说是人人都能学会的,而且是可以通过死记硬背在短时间内速成的。

       而感性思维,或者说创造性思维,是很难一下子就养成的,就像我们学画画,没有个一年半载,根本画不出什么好的东西,而且很多画画好的都是从小开始培养的。所以学动画短时间内很难有一些突破,仅仅只能停留在一个较低的层面上,这也就是为什么很多人只会做flash广告,而做不了大于3分钟的动画,或者说做不出高质量的动画的原因了。

        但是从入门的角度上来看,会用flash的人,一般都能从事简单flash动画的制作,其实这主要是依靠了FLASH这款工具的强大,并非代表着做动画很简单,或者你很聪明,一下子就学会了,入门也许很简单,但是越想提高一个层次就越困难,比如学会FLASH没多久,就会做flash主页,flash广告等,那是因为这个没有什么难度,所以综合看来,我认为,如果想在短时间内,从事flash工作的话,可以先掌握flash的应用,能制作简单flash动画,然后学习编程,短期内会很有效果。从长期来看,学习一些美术基础,对做动画会大有帮助。


问:我最近想去学flash制作,在网上找了找,发现有很多制作软件,如flash MX,flash MX2004和flash cs3 Pro,哪款比较好啊?
答:
       2000年 flash 5.0 
       2002年 flash mx (就是flash 6.0) 
       2004年 flash mx2004 (就是flash 7.0) 
       2005年 flash 8.0 
       2006年 flash cs3 (就是flash 9.0) 
       2008年 flash cs4 (就是flash 10.0)

       目前的最新版本是flash cs4 功能非常强大,不仅支持骨骼动画,还支持3维等等,verycd上有视频教程,可以去学习一下。

      不过初学的话,个人建议你从flash cs3开始,以便今后玩flash cs4,因为他们的操作性很相似,Flash 8现在虽然还是很多人在用,但是已经渐渐被新软件的新功能所取代。

      FLASH CS3的好用之处::

      1.cs3是ADOBE收购micromedia后的大作,无论从动画设计上,还是程序语言上都有质的飞跃。比如钢笔功能更加强大,超级强大的绘图功能,这些都让矢量图制作者提高了效率,使用更方便。

      2.FLASH CS3引入了面向对象的AS3语言,使得AS不在是一个简简单单的脚本语言,而摇身变成一种强大的高级程序语言。另外,FLASH CS3也全面支持AS之前的版本,从AS1到AS2均支持。

     3.作为初学者,因为没有基础,不存在用惯一个版本的软件,用新版本时要重新熟悉的问题,所以应尽量选择最新版本的软件进行学习,因为时代是在进步的,老版本的软件,学完了也就淘汰了,再学新的,还得重新熟悉界面及操作习惯。

     4.目前由于flash cs4 10月份刚刚推出,目前CS4的教材并不多也不系统,所以建议以FLASH CS3作为学习的开始,而且FLASH CS4的界面和CS3差不多,只是加了些新功能。


问:怎样学会flash编程,要有什么基础,要学c语言吗,哪里有教程啊?该怎么学啊??

答:
        如果你只是了解一下,网上的视频教程很多,可以去看一看。

        但是如果你是很想学会,那么我建议你,要学习一门知识,就必须看系统的教材。因此不推荐看视频教程,网上的视频教程虽然很多,但是都很难系统性的教会你代码的结构、编程的思想。所以我的建议是买书学习。最好不要看电子书,个人觉得,看电子书的人,都喜欢跳着看,这样看就失去了意义。这样看下来,好像学会了,其实什么原理都没搞懂。

       要真正的买一本书,一页一页的翻着看,看一遍不够,一本书至少3遍甚至n遍。还要多加练习。学习编程,首先从hello world开始,然后就是要每天写,经常写,这样才有进步。

       很多人也有这样的担心,怕自己没有语言基础,例如没有学习过C等。其实大可不必担心,语言只是一种工具而已,目前的主流语言就好象同素异形体一样,看似有区别,其实都差不多。这就好像你会使用WIN98,升级到了WIN XP,你也不会说,连怎么打开文件都要重头学习一样。学习编程的关键是学习编程的思想,所以好的书教你怎么理解编程思想,差的书只是叫你怎么写代码,其中区别很大。

       AS2的书,这里不做推荐了,我也没看过什么好点的书,我学AS2完全就是看帮助学会的,主要是有JS基础。 
       这里推荐一本AS3的书:《action script3.0殿堂之路》


问:我是老程序员了,对Javascript和Java都比较擅长,现在想学Flex,但不知道有什么经典一点的书籍?
答:
        1.初学者,推荐《action script3.0殿堂之路》,也有人推荐《as3权威宝典》个人觉得那书写的不行。

       2.flex的话,推荐《flex第一步》

       3.as3语言掌握的7788了以后,可以去看以下一些书籍

       4.实用书籍: 
         Action Script3.0 Cook Book —— 类似帮助手册的书籍 
         Action Script3.0 设计模式 —— 一本讲述程序设计思想的书籍,强烈推荐


问:flash as2.0 与 as3.0的本质区别?

答:
       首先说下as2,as2实际上是as1的升级版,引入一面向对象的概念,但并不是完全面向对象的语言,只是在编译过程中支持OOP语法。as2的面向对象虽然不全面,但是却是首次将OOP带到了FLASH,而AS3是一个完全基于OOP的标准化面向对象语言,最重要的就是as3不是as2的简单升级,而完全是两种思想的语言。可以说,as3全面采用了面向对象的思想,而as2则仍然停留在面向过程阶段,举个例子,就像VB和C#的对比。

       所以as3绝不是as2的升级版,在as3里,可以看到java和c#的影子,确实,这三种语言大部分思想都是一致的,只有一些小的区别,比如as3引入了命名空间的概念,但是不支持比如委托,在包封装及外部访问上也引入了一些新概念。

       在编译阶段,as2采用的是AVM1(actionScript vitual machine),而as3采用的是AVM2。新一代虚拟机采用了OOP思想,在执行速度上比起avm1也快了10倍。还提供了异常处理。以前我们在使用AS2时,一旦出错,AVM1选择的是静默失败,让人根本不知道什么地方出错了,会浪费大量的时间去查错,而AVM2与目前主流的编译器一样,会有异常处理,运行出错会输出错误提示,工作效率大大提高。如果做个对比,我想说,AVM1就是大刀长矛,而AVM2就是手枪,大刀和长矛也能杀敌,但是只在面对弱智的敌人才能发挥作用,面对一个大型项目,不用点现代化工具是不行滴。

        as2与as3的部分区别,只说一些大的区别,小的不同太多,就不谈了:

        1.运行时异常机制处理,这个刚才说过了。

        2.事件机制,这也是很多人拿起as3就不知所措的原因,初学者会发现连一个按钮点击的方法都写不出来。实际上as3的事件机制采用的是监听的方式,和as2时代的onClipEvent不同,as3里所有的事件都是需要触发器,监听器,执行器三种结构的,这样做的好处就是使得这个语言非常的坚强,非常的标准化。不像as2,奇形怪状的代码漫天飞,可以这样写,也可以那样写,代码变得繁复难懂,可读性太差,执行效率也大大降低。要特别说明的是,as3的所有事件都直接继承event对象,而event是直接继承自大老板Object类,结构多么完美。所以在as3中,所有的事件都继承自相同的父亲,结构相同,提高了重用性。

        3.封装性,这是as3与as2最大的不同,as3引入了封装的概念,使得程序安全性大大提高,各个对象之间的关系也通过封装,访问控制而得以确定,避免了不可靠的访问给程序带来的意外产生。

       4.XML,我觉得这是最令人激动人心的改变,现在as3程序员可以很轻松也很自豪的说,我们是使用XML人群中最快乐的人。AS2时代对XML的存取仍然需要解析,而AS3则创新的将XML也视作一个对象,存取XML就像存取普通对象的属性一样方便,用点语法就可以,无疑大大提高了效率。

      5.最关键的一点,容器的概念,AS3采用了容器的思想,告别了as2一个MovieClip打天下的局面。对于as2程序员来说,可能不能理解,我mc用的好好的,干嘛不让我用啊。但是当你真正的了解as3的思想的时候,当你真主的体会到OOP的好处的时候,你会觉得as3的容器的思想的完全正确的。as2时代,我们做什么都用mc,而as2时代的mc也是直接继承自object,这给了mc极大的权限,极其多的方法属性,而有时我们只需要放一个背景图,并不需要它动,这样做就造成了极大的浪费。说实在话as2和as3比起来就是浪费之神,所以as2编出的swf绝对比as3编译出来的swf要大上几倍。as3把所有你用到的显示对象都分开,mc的属性方法都被瓜分开来,举个例子,你去水果超市买水果,就肯定比直接去大型超市买要方便,更节约时间,时间就是金钱,那就是很大的节省。

      当然还有许许多多的不同,比如程序执行机制,设计模式,结构框架等等,这里就不在一一赘述。


问:怎么才能成为编程高手?

答:
        可以说,学会编程并不难,怎么才能写出好的程序,这是很多人所困惑的事情,我有时候也是左思右想,觉得自己写出来的东西太在是太垃圾了。那么真正的高手他们在做些什么呢?他们到底因为什么才能成为高手呢?

       其实,我们很多人都仅仅停留在会写程序的阶段,并没有去研究,一个程序怎么写才算是合理的,什么样的结构,才是最完善的,什么样的布局才是可扩展的。什么样的代码才是最高效的。而这正是高手花功夫去研究的事情,也是为什么高手能做的更好的原因。

      我总结了一下,觉得以下才是一个程序员应该思考的路:

     1.第一类人:会写程序,这没什么,人人都能办到。(70%的程序员都在这里)

      2.第二类人:有一定的结构思想,能做设计结构上的调整。能走到这一步,应该可以算真正入门了。(15%的程序员在这里,很不幸,本人也在这里。)

     3.第三类人:熟练应用各种设计模式,到了这里,才算涉足高级编程领域。这样的人才能算高手。(10%左右,我想黑羽同志应该属于这个级别)

     4.第四类人:有算法分析和创意思维,能做到这一步的人,写出来的程序就不叫程序了,叫伟大发明!(5%左右,微软和谷歌的专家们在这里)

     5.第五类人:这一类人是我不敢想象的,已经超出我的思考范畴了。(趋向0%)

最后,欢迎大家百度HI我,和我探讨相关的技术。
或者加入百度HI群:flash知道(1群)1051316、 flash知道(2群)1084144

posted @ 2010-02-24 14:27 暗夜教父 阅读(571) | 评论 (1)编辑 收藏
#include   <winsock2.h>   
//#include   <windows.h>   
#include   <stdio.h>   

#define   PORT   5150   
#define   DATA_BUFSIZE   8192   
    
typedef   struct   
{   
        OVERLAPPED   Overlapped;   
        WSABUF   DataBuf;   
        CHAR   Buffer[DATA_BUFSIZE];   
        DWORD   BytesSEND;   
        DWORD   BytesRECV;   
}   PER_IO_OPERATION_DATA,   *   LPPER_IO_OPERATION_DATA;   
    
    
typedef   struct     
{   
        SOCKET   Socket;   
}   PER_HANDLE_DATA,   *   LPPER_HANDLE_DATA;   
    
    
DWORD   WINAPI   ServerWorkerThread(LPVOID   CompletionPortID);   
    
int main(void)   
{   
        SOCKADDR_IN   InternetAddr;   
        SOCKET   Listen;   
        SOCKET   Accept;   
        HANDLE   CompletionPort;   
        SYSTEM_INFO   SystemInfo;   
        LPPER_HANDLE_DATA   PerHandleData;   
        LPPER_IO_OPERATION_DATA   PerIoData;   
        int   i;   
        DWORD   RecvBytes;   
        DWORD   Flags;   
        DWORD   ThreadID;   
        WSADATA   wsaData;   
        DWORD   Ret;   
    
        if   ((Ret   =   WSAStartup(0x0202,   &wsaData))   !=   0)   
        {   
              printf("WSAStartup失败了,错误信息如下:   %d\n",   Ret);   
              return;   
        }   
    
        // 设置一个I/O完成端口.   
    
        if   ((CompletionPort   =   CreateIoCompletionPort(INVALID_HANDLE_VALUE,   NULL,   0,   0))   ==   NULL)   
        {   
              printf(   "CreateIoCompletionPort 失败了,错误信息如下:   %d\n",   GetLastError());   
              return;   
        }   
    
        // 测试系统中有多少cpu处理器 
    
        GetSystemInfo(&SystemInfo);   
    
        //   基于系统可用的处理器创建工作线程,为每个处理器创建连个线程   
    
        for(i   =   0;   i   <   SystemInfo.dwNumberOfProcessors   *   2;   i++)   
        {   
              HANDLE   ThreadHandle;   
    
              // 创建一个服务端线程并且传递一个完成端口给这个线程.   
    
              if   ((ThreadHandle   =   CreateThread(NULL,   0,   ServerWorkerThread,   CompletionPort,   
                    0,   &ThreadID))   ==   NULL)   
              {   
                    printf("CreateThread()发生了如下错误: %d\n",   GetLastError());   
                    return;   
              }   
              else 
              {printf("创建了一个完成端口.\n");
              }
              //   关闭 thread句柄 
              CloseHandle(ThreadHandle);   
        }   
    
        //   创建一个监听套接字 
    
        if   ((Listen   =WSASocket(AF_INET,   SOCK_STREAM,   0,   NULL,0,WSA_FLAG_OVERLAPPED))   ==   INVALID_SOCKET)   
        {   
              printf("WSASocket() 发生了如下错误: %d\n",   WSAGetLastError());   
              return;   
        }
        else     
        {printf("创建监听套接字成功\n");}
        InternetAddr.sin_family   =   AF_INET;   
        InternetAddr.sin_addr.s_addr   =   htonl(INADDR_ANY);   
        InternetAddr.sin_port   =   htons(PORT);   
    
        if   (bind(Listen,   (PSOCKADDR)   &InternetAddr,   sizeof(InternetAddr))   ==   SOCKET_ERROR)   
        {   
              printf("bind()端口或IP时发生了如下错误: %d\n",   WSAGetLastError());   
              return;   
        }   
        else
        {printf("绑定端口%d成功\n",PORT);} 
        // 准备socket 用来监听   
    
        if   (listen(Listen,   5)   ==   SOCKET_ERROR)   
        {   
              printf("listen() 发生了如下错误   %d\n",   WSAGetLastError());   
              return;   
        }   
         else
        {printf("预处理成功,开始在端口 %d 处监听...\n",PORT);} 
        //接受连接并且交给完成端口处理 
    
        while(TRUE)   
        {   
              if   ((Accept   =   WSAAccept(Listen,   NULL,   NULL,   NULL,   0))   ==   SOCKET_ERROR)   
              {   
                    printf("WSAAccept()   发生了如下错误:   %d\n",   WSAGetLastError());   
                    return;   
              }   
    
              // 创建一个套接字信息结构体去联系起来socket   
              if   ((PerHandleData   =   (LPPER_HANDLE_DATA)   GlobalAlloc(GPTR,     
                    sizeof(PER_HANDLE_DATA)))   ==   NULL)   
              {   
                    printf("GlobalAlloc()   发生了如下错误:   %d\n",   GetLastError());   
                    return;   
              }   
    
              // 将接受到的套接字与原始的完成端口联系起来.   
    
              printf("号码为   %d   的socket连接上了\n",   Accept);   
              PerHandleData->Socket   =   Accept;   
    
              if   (CreateIoCompletionPort((HANDLE)   Accept,   CompletionPort,   (DWORD)   PerHandleData,   
                    0)   ==   NULL)   
              {   
                    printf("CreateIoCompletionPort   发生了如下错误:   %d\n",   GetLastError());   
                    return;   
              }   
    
              //   创建每一个I/O 套接字信息结构体去和下面被调用的 to   associate   with   the     
              //   WSARecv 连接.   
    
              if   ((PerIoData   =   (LPPER_IO_OPERATION_DATA)   GlobalAlloc(GPTR,                     sizeof(PER_IO_OPERATION_DATA)))   ==   NULL)   
              {   
                    printf("GlobalAlloc() 发生了如下错误: %d\n",   GetLastError());   
                    return;   
              }   
              else{printf("接收了一个连接\n");} 
              ZeroMemory(&(PerIoData->Overlapped),   sizeof(OVERLAPPED));   
              PerIoData->BytesSEND   =   0;   
              PerIoData->BytesRECV   =   0;   
              PerIoData->DataBuf.len   =   DATA_BUFSIZE;   
              PerIoData->DataBuf.buf   =   PerIoData->Buffer;   
    
              Flags   =   0;   
              if   (WSARecv(Accept,   &(PerIoData->DataBuf),   1,   &RecvBytes,   &Flags,   
                    &(PerIoData->Overlapped),   NULL)   ==   SOCKET_ERROR)   
              {   
                    if   (WSAGetLastError()   !=   ERROR_IO_PENDING)   
                    {   
                          printf("WSARecv() 发生了如下错误: %d\n",   WSAGetLastError());   
                          return;   
                    }   
              }   
        }   
}   
    
DWORD   WINAPI   ServerWorkerThread(LPVOID   CompletionPortID)   
{   
        HANDLE   CompletionPort   =   (HANDLE)   CompletionPortID;   
        DWORD   BytesTransferred;   
        LPOVERLAPPED   Overlapped;   
        LPPER_HANDLE_DATA   PerHandleData;   
        LPPER_IO_OPERATION_DATA   PerIoData;   
        DWORD   SendBytes,   RecvBytes;   
        DWORD   Flags;   
          
        while(TRUE)   
        {   
    
              if   (GetQueuedCompletionStatus(CompletionPort,   &BytesTransferred,   
                    (LPDWORD)&PerHandleData,   (LPOVERLAPPED   *)   &PerIoData,   INFINITE)   ==   0)   
              {   
                    printf("GetQueuedCompletionStatus   发生了如下错误: %d\n",   GetLastError());   
                    return   0;   
              }   
    
              //首先检查一下去套接字看是否在上发生了错误并且如果发生了错误就关闭套接
              //字并且清除与套接字连接的 SOCKET_INFORMATION结构信息体 
              if   (BytesTransferred   ==   0)   
              {   
                    printf("正在关闭socket   %d\n",   PerHandleData->Socket);   
    
                    if   (closesocket(PerHandleData->Socket)   ==   SOCKET_ERROR)   
                    {   
                          printf("closesocket()   发生了如下错误: %d\n",   WSAGetLastError());   
                          return   0;   
                    }   
    
                    GlobalFree(PerHandleData);   
                    GlobalFree(PerIoData);   
                    continue;   
              }   
    //检查如果 BytesRECV字段等于0,这就意味着一个 WSARecv调用刚刚完成了所以从完成的WSARecv()调用中
    //用BytesTransferred值更新 BytesRECV字段 
              if   (PerIoData->BytesRECV   ==   0)   
              {   
                    PerIoData->BytesRECV   =   BytesTransferred;   
                    PerIoData->BytesSEND   =   0;   
              }   
              else   
              {   
                    PerIoData->BytesSEND   +=   BytesTransferred;   
              }   
    
              if   (PerIoData->BytesRECV   >   PerIoData->BytesSEND)   
              {   
    //发布另外一个 WSASend()请求
    //既然WSASend()不是 gauranteed去发送所有字节的请求
    //继续调用 WSASend()发送直到所有收到的字节被发送 
                    
                    ZeroMemory(&(PerIoData->Overlapped),   sizeof(OVERLAPPED));   
    
                    PerIoData->DataBuf.buf   =   PerIoData->Buffer   +   PerIoData->BytesSEND;   
                    PerIoData->DataBuf.len   =   PerIoData->BytesRECV   -   PerIoData->BytesSEND;   
    
                    if   (WSASend(PerHandleData->Socket,   &(PerIoData->DataBuf),   1,   &SendBytes,   0,   
                          &(PerIoData->Overlapped),   NULL)   ==   SOCKET_ERROR)   
                    {   
                          if   (WSAGetLastError()   !=   ERROR_IO_PENDING)   
                          {   
                                printf("WSASend() 发生了如下错误:   %d\n",   WSAGetLastError());   
                                return   0;   
                          }   
                    }   
              }   
              else   
              {   
                    PerIoData->BytesRECV   =   0;   
    //现在没有更多的字节发送过去用来post另外一个WSARecv()请求 
                    
                    Flags   =   0;   
                    ZeroMemory(&(PerIoData->Overlapped),   sizeof(OVERLAPPED));   
    
                    PerIoData->DataBuf.len   =   DATA_BUFSIZE;   
                    PerIoData->DataBuf.buf   =   PerIoData->Buffer;   
    
                    if   (WSARecv(PerHandleData->Socket,   &(PerIoData->DataBuf),   1,   &RecvBytes,   &Flags,   
                          &(PerIoData->Overlapped),   NULL)   ==   SOCKET_ERROR)   
                    {   
                          if   (WSAGetLastError()   !=   ERROR_IO_PENDING)   
                          {   
                                printf("WSARecv() 发生了如下错误:   %d\n",   WSAGetLastError());   
                                return   0;   
                          }   
                    }   
              }   
        }   
}  
posted @ 2010-02-24 13:34 暗夜教父 阅读(826) | 评论 (0)编辑 收藏
仅列出标题
共9页: 1 2 3 4 5 6 7 8 9 

<2024年3月>
252627282912
3456789
10111213141516
17181920212223
24252627282930
31123456

常用链接

留言簿(2)

随笔分类

随笔档案

文章分类

文章档案

搜索

  •  

最新评论

阅读排行榜

评论排行榜