1.����Դ��
2.x,红心y 都是int, x++=y++ 为什么错?
3.å¦ä½å¦ä¹ Kotlinç¼ç¨è¯è¨
4.有没有靠谱的公司能定制红心大战扑克牌棋牌游戏?需要多少钱?
����Դ��
众所周知?扑克牌可谓是居家旅行、桌面交友的源码必备道具,今天我们用 Python 来实现一个类似炸金花的小红心代扑克牌小游戏,先来看一下基本的红心游戏规则。炸(诈)金花又叫三张牌,源码是小红心代xuter64源码在全国广泛流传的一种民间多人纸牌游戏。游戏使用一副除去大小王的红心扑克牌,共 4 个花色 张牌,源码各个玩家从中抽取 3 张牌,小红心代比较大小。红心各种牌型的源码大小顺序如下(按照全排列组合中出现的概率越小,牌型分数奖励越大):1、小红心代同花顺:三张同样花色且点数连续的红心牌,如红心2、源码红心3、小红心代红心4;2、豹子:三张点数一样的牌,如 AAA、;3、顺子:三张点数连续的牌,如红心2、黑桃3、方块4;4、金花:三张同样花色的牌,如红心2、红心5、红心8;5、对子:两张点数一样的牌,如红心2、黑桃2;6、单张:2~ < J < Q < K < A。以下概率截自百度百科: 注:本文所述游戏规则与实际有所不同,主要基于对不同牌型的拉新做单源码比较进行设计
一、游戏流程实现
1、准备扑克牌 开始游戏前,需要先生成一副满足要求的扑克牌,牌友们都知道,扑克牌有以下四种花色,每种花色有 A、2~、J、Q、K 等 张牌。
suit = ["黑桃", "红心", "方块", "梅花"]num = [str(i) for i in range(2, )] + ["J", "Q", "K", "A"]为了便于后续算分,先给每一个单张赋予相应的点数。
score_map = { }# 单张点数映射表for s in suit:count = 2for n in num:score_map[f"{ s}{ n}"] = countcount += 1扑克牌点数预览如下:
score_map = { '黑桃2': 2, '黑桃3': 3, '黑桃4': 4, '黑桃5': 5, '黑桃6': 6, '黑桃7': 7, '黑桃8': 8, '黑桃9': 9, '黑桃': , '黑桃J': , '黑桃Q': , '黑桃K': , '黑桃A': , '红心2': 2, ... }
2、玩家入场 以 p1、p2 等名称对玩家进行区分,我们先邀请 5 个玩家入场。
players = [f"p{ i}" for i in range(1, 6)]3、发牌 将玩家和扑克牌列表作为参数,传入发牌器。发牌器在扑克牌中进行不放回抽取,为每个玩家随机抽取 3 张牌,并记下玩家名称及其对应牌组。
def get_pk_lst(pls, pks):result = []for p in pls:pk = sample(pks, 3)for _pk in pk:pks.remove(_pk)result.append({ "name": p, "poker": pk})return resultpokers = list(score_map.keys())# 去掉大小王的一幅扑克poker_grp = get_pk_lst(players, pokers)# 发牌发牌预览如下:
result = [{ 'name': 'p1', 'poker': ['方块5', '梅花3', '方块A']}, { 'name': 'p2', 'poker': ['黑桃4', '方块8', '黑桃J']}, { 'name': 'p3', 'poker': ['红心', '红心K', '方块7']}, { 'name': 'p4', 'poker': ['方块4', '梅花6', '方块J']}, { 'name': 'p5', 'poker': ['红心5', '梅花', '黑桃A']}]
4、判断牌型及算分 在算分之前先按之前的映射字典,将 pk_lst 里的 3 张扑克牌转换成对应的点数。
n_lst = list(map(lambda x: score_map[x], pk_lst))# 点数映射接下来截取花色部分的文本,利用集合去重后判断是否为三张同花。
same_suit = len(set([pk[:2] for pk in pk_lst])) == 1# 是否同花色再对点数部分进行排序,与依靠点数的最值生成的顺序列表进行比较,判断是否为连续的点数。要注意的是,A 与 QKA 一样被视作顺子。相亲小程序 源码
continuity = sorted(n_lst) == [i for i in range(min(n_lst), max(n_lst) + 1)] or set(n_lst) == { , 2, 3}# 是否连续别忘了考虑对子和豹子的检查方式。
check = len(set(n_lst)) # 重复情况
那么正式开始判断牌型和算分吧!首先是单张,非同花、非顺子、三张点数不一。得分以 3 个单张点数相加。
if not same_suit and not continuity and check == 3:return sum(n_lst), "单张"其次是对子,非同花,有且仅有两张点数一致。得分中对于构成对子的部分给予 2 倍奖励。
if not same_suit and check == 2:w = [i for i in n_lst if n_lst.count(i) == 2][0]single = [i for i in n_lst if i != w][0]return w*2*2 + single, "对子"金花,即同花而非顺子,给予 9 倍奖励。
if same_suit and not continuity:return sum(n_lst)*9, "金花"顺子,即点数连续而非同花,给予 倍奖励。
score_map = { }# 单张点数映射表for s in suit:count = 2for n in num:score_map[f"{ s}{ n}"] = countcount +=豹子,即三张点数一致,这不得刷个 嘛。
score_map = { }# 单张点数映射表for s in suit:count = 2for n in num:score_map[f"{ s}{ n}"] = countcount +=同花顺,同花色且点数连续,绝了,赌神一个技能 伤害。
score_map = { }# 单张点数映射表for s in suit:count = 2for n in num:score_map[f"{ s}{ n}"] = countcount +=5、决出胜负 一组玩家、抽牌、算分、牌型记录如下:
pk_grp = [{ 'name': 'p1', 'poker': ['方块5', '梅花3', '方块A'], 'score': , 'type': '单张'}, { 'name': 'p2', 'poker': ['黑桃4', '方块8', '黑桃J'], 'score': , 'type': '单张'}, { 'name': 'p3', 'poker': ['红心', '红心K', '方块7'], 'score': , 'type': '单张'}, { 'name': 'p4', 'poker': ['方块4', '梅花6', '方块J'], 'score': , 'type': '单张'}, { 'name': 'p5', 'poker': ['红心5', '梅花', '黑桃A'], 'score': , 'type': '单张'}]
利用 max 函数找出来谁是最棒的,公布名字!
score_map = { }# 单张点数映射表for s in suit:count = 2for n in num:score_map[f"{ s}{ n}"] = countcount +=赢家是------ p3
好啦,又可以开始下一场愉快的游戏GM平台源码游戏了~
二、统计及源码
1、牌型统计 进行了 万场游戏并对各类牌型进行频率统计,可见与前述排列组合的计算所得概率基本一致。
score_map = { }# 单张点数映射表for s in suit:count = 2for n in num:score_map[f"{ s}{ n}"] = countcount +=2、牌局案例 各类牌型的局面和结果如下:
score_map = { }# 单张点数映射表for s in suit:count = 2for n in num:score_map[f"{ s}{ n}"] = countcount +=3、完整代码
# 炸金花from random import samplefrom collections import Counterdef get_pk_lst(pls, pks):# 发牌result = []for p in pls:pk = sample(pks, 3)for _pk in pk:pks.remove(_pk)result.append({ "name": p, "poker": pk})return resultdef calculate(_score_map, pk_lst):# 返回得分和牌型n_lst = list(map(lambda x: _score_map[x], pk_lst))# 点数映射same_suit = len(set([pk[:2] for pk in pk_lst])) == 1# 是否同花色continuity = sorted(n_lst) == [i for i in range(min(n_lst), max(n_lst) + 1)] or set(n_lst) == { , 2, 3}# 是否连续check = len(set(n_lst))# 重复情况if not same_suit and not continuity and check == 3:return sum(n_lst), "单张"if not same_suit and check == 2:w = [i for i in n_lst if n_lst.count(i) == 2][0]single = [i for i in n_lst if i != w][0]return w*2*2 + single, "对子"if same_suit and not continuity:return sum(n_lst)*9, "金花"if continuity and not same_suit:return sum(n_lst)*, "顺子"if check == 1:return sum(n_lst)*, "豹子"if continuity and same_suit:return sum(n_lst)*, "同花顺"def compare(_score_map, pk_grp):# 比大小for p in pk_grp:p["score"], p["type"] = calculate(_score_map, p["poker"])print("开牌结果------")for p in pk_grp:print(p)print("赢家是------")score_map = { }# 单张点数映射表for s in suit:count = 2for n in num:score_map[f"{ s}{ n}"] = countcount += print(best)return pk_grpdef show(_score_map, _players): # 开局pokers = list(_score_map.keys())poker_grp = get_pk_lst(_players, pokers)return compare(_score_map, poker_grp)def start_game(_score_map, _players, freq=1): # 游戏和统计type_lst = []for i in range(freq):grp = show(_score_map, _players)type_lst = type_lst + [t["type"] for t in grp]c = Counter(type_lst)print(c)total = sum(c.values())for item in c.items():print(f"{ item[0]}频率:{ item[1]/total:.2%}")if __name__ == '__main__':# 准备扑克牌suit = ["黑桃", "红心", "方块", "梅花"]num = [str(i) for i in range(2, )] + ["J", "Q", "K", "A"]score_map = { }# 单张点数映射表for s in suit:count = 2for n in num:score_map[f"{ s}{ n}"] = countcount += 1# 5个玩家入场players = [f"p{ i}" for i in range(1, 6)]# 开始游戏start_game(score_map, players, freq=)以上就是本次分享的所有内容,想要了解更多欢迎前往公众号:Python 编程学习圈,每日干货分享
原文:/post/x,y 都是int, x++=y++ 为什么错?
赋值运算需要左值,而x++不是左值。x++的本意是使用x的值,在使用后将x自加1,那么如果把x++用在赋值运算的左边的话,赋值时是赋给原先的x还是自加后的x呢?显然是未定义的,所以这种操作是错误的。
下面转一篇关于左值和右值的文章,相信会对你帮助很大的。
左值(lvalue)和右值(rvalue)是编程中两个非常基本的概念,但是也非常容易让人误解,看了很多文章,自我感觉真正将这个问题讲的很透彻的文章还没有看见,所以自告奋勇来尝试一下。如果左值右值的概念不是非常清楚的话,它们迟早会像拦路虎一样跳出来,让你烦心不已,就像玩电脑游戏的时候每隔一段时间总有那么几个地雷考验你的耐性,如果一次把所有地雷扫尽就好了。:)
左值(lvalue)和右值(rvalue)最先来源于编译理论(感谢南大小百合的programs)。在C语言中表示位于赋值运算符两侧的两个值,左边的就叫左值,右边的就叫右值。比如:
int ii = 5;//ii是左值,5是2022算命源码下载右值
int jj = ii;//jj是左值,ii是右值
上面表明,左值肯定可以作为右值使用,但反之则不然。左值和右值的最早区别就在于能否改变。左值是可以变的,右值不能变。注1
注1:这一点在C++中已经猪羊变色,不再成立。拱猪游戏还是挺好玩的,我还真抓过好几次全红心,不过真的好险。:)
在很多文章中提到,在C++中,左值更多的指的是可以定位,即有地址的值,而右值没有地址。注2
注2:这一点仍然不准确,我在程序中生成一个临时右值std::vector(),你能够说它没有地址吗?难道它是没有肉体的鬼魂或幽灵?它是有地址的,而且它也是绝对的右值。
在现代C++中,现在左值和右值基本上已经失去它们原本所具有的意义,对于左值表达式,通过具体名字和引用(pointer or reference)来指定一个对象。非左值就是右值。我来下一个定义:
左值表示程序中必须有一个特定的名字引用到这个值。
右值表示程序中没有一个特定的名字引用到这个值。
跟它们是否可以改变,是否在栈或堆(stack or heap)中有地址毫无关系。
1.左值
在下面的代码中:
int ii = 5;
int const jj = ii;
int a[5];
a[0] = ;
*(a+3) = ;
int const& max( int const& a, int const& b ) //call by reference
{
return a > b ? a : b;
}
int& fun(int& a) //call by reference
{
a += 5;
return a;
}
ii,jj,a[0],*(a+3),还有函数max的返回值比如max(ii, jj),注3函数fun的返回值fun(ii)都是左值。,它们都是有特定的引用名字的值。ii,jj,a[0],*(a+3),max(ii, jj),fun(ii)分别就是它们的名字。
注3:在这里有一个不太容易分清楚的盲点。那就是有人会问max(8, 9)到达是左值还是右值,C++标准规定常量引用(reference to const)可以引用到右值,所以max(8, 9)似乎应该是右值,不过不管它是左值,还是右值,我们都不能试图去改变它。为了与前面的概念一致,我认为它是左值,不可改变的常量左值。
左值有不能改变的,即被const所修饰的左值,比如上面的jj,max(ii, jj)都是被常量(const)魔咒所困住的左值。
没有被const困住的左值当然是可以改变的,比如下面的代码都是成立的:
ii = ;
a[0] = ;
fun(ii) = ; //OK!
我们的眼睛没有问题,fun(ii) = ;完全正确,因为它是可以改变的左值。所以我们看STL的源码,就会理解std::vector中的重载operator[]运算符的返回值为什么要写成引用,因为operator[]必须返回左值。
2.右值
没有特定名字的值是右值。先看下面的代码:
std::list();
std::string(“It is a rvalue!”);
int fun1() //call by value
{
…
}
int* fun2() //call by reference
{
…
}
其中std::list(),std::string(“It is a rvalue!”),函数fun1的返回值fun1(),函数fun2的返回值fun2()都是右值,它们的值都没有特定的名字去引用。也许有人会奇怪,fun2()也是右值?最前面的max(a,b)不是左值吗?
请看清楚,函数fun2的返回值是pointer,pointer也是call by value,而函数max的返回值是reference,reference是call by reference。所以说C++中引入reference不仅仅是为了方便,它也是一种必须。注4
注4:Scott Meyer写的《More Effective C++》的条款1专门讲了pointer和reference的区别,写的很好,辨别的非常清楚。
fun2()是右值,但 *fun2()却是左值,就跟经常看到的*p一样,所以看C++库代码的时候,会发现重载operator*的函数返回值是reference。
当然我还遗漏了一种右值,那就是字面上的(literal)值,比如5,8.,’a’等等理所当然的都是右值。
右值最初出现的时候,一个最大的特征就是不可改变。但就跟我们的道德标准一样,时代不同了,标准也变化了,以前的三纲五常早已经被扔到历史的垃圾堆里面了。
C++中有可以改变的右值,而且这个特性还非常有用。那就是用户自定义的类(class)的构造函数生成的临时对象。比如:
std::vector(9),std::deque(),……都是可以改变的右值。在Herb Sutter的《More Exceptional C++》中的条款7的page页有这样几行代码:
// Example 7-2(b): The right way to shrink-to-fit a vector.
vector<Customer> c( );
// ...now c.capacity() >= ...
// erase all but the first elements
c.erase( c.begin()+, c.end() );
// the following line does shrink c's
// internal buffer to fit (or close)
vector<Customer>( c ).swap( c );
// ...now c.capacity() == c.size(), or
// perhaps a little more than c.size()
认真看几遍,你会发现但vector的大小增大到一定程度,你又用不着这么多空间的时候,你会想办法把它收缩到最合适的大小,但利用别的办法比如调用成员函数reserve()都无法办到,这个时候就必须利用右值可以改变这个性质了。
vector<Customer>( c ).swap( c );这行代码就是点睛之处。
首先使用复制构造函数生成临时右值vector<Customer>( c ),这个右值正好是合适大小,然后和c交换注5,c就变成合适大小了,最后在整个表达式结束的时候,这个临时右值析构归还内存空间。真是绅士一般的优雅!
注5:这个时候这个临时右值就发生了改变。
如果还不理解,可以看看书,或者直接看库的源代码。
至于为什么会这样?我思考了一下,我想是这样的,我们看类(class)的数据布置结构,会发现它的每一个数据成员都是有名字的,我想编译器在编译的过程中,都会生成一个外部不所知的对这个临时对象右值的名字引用,但需要改变这个临时对象的时候,这个名字就用上了。比如:
class Point
{
public: //纯粹为了方便,我把数据成员公开,现实中尽量不要这样用
int x, y ,z;
……//其他各种成员函数
};
我们现在就可以改变右值,用到了匿名的引用名字。
Point().x = 6;//改变了右值
Point().y = 6;//同意改变了右值,不过注意,这个右值跟上面的不是同一个。
总结
左值和右值的真正区别我想就是这些了,左值表示有特定的名字引用,而右值没有特定的名字引用。当然我仍然会有疏忽,希望大家能够提醒我,指正我的不足。
前两天看Herb Sutter从邮件中寄来的新文章(我订阅他的新文章邮件通知),一篇是讲Tuple数据结构的,没有什么新意,以前好像看过,还有一篇名字是:(Mostly)Private,地址为/documents/s=/cujcexpsutter/ 内容本身并不深,但看完文章,发现随处可见C++的波诡云谲,又会对什么叫袖里乾坤,滴水藏海多一份感性认识。
在下一篇文章我想从不同于一般的角度,从自己的经历谈谈在校毕业生在IT行业怎样找工作,我想会让所有读者都有一些思考,不仅仅是求职者。题目我已经想好了,就叫《扮虎吃猪》,不过现在我有一些别的事情要忙,所以可能会让大家等几天。
转载请注明来源,谢谢!
å¦ä½å¦ä¹ Kotlinç¼ç¨è¯è¨
为ä»ä¹è¯´ Kotlin æ¯ä¼ç§ç
æ¬æä¸ä¼åä¸è¬ä»ç»è¯è¨çæç« é£æ ·ï¼ä¸å¼å¤´å°±ç½ååºè¯è¨é£äºé ·ç«çç¹æ§ï¼æ们ç¨ååæ¥æ¢è®¨è¿äºå 容ã
é¦å æå°ä»ç»ä¸äºå ¶å®çä¿¡æ¯ï¼å 为 å¹´ä¸é¡¹ç 究æ¾ç¤ºï¼å½å¼åè è¯ä¼°ä¸ç§ç¼ç¨è¯è¨æ¶çæç³»ç»è¦æ¯è¯è¨ç¹æ§æ´éè¦ãè¿ç¬¦åæ个人çç»éªï¼ä¸é¢å°±è®©æå¼å§ä»ç»å§ï¼
Kotlin 被ç¼è¯æ JVM åèç æè JavaScript 代ç ãJava å¼åè å°ä¼æ¯å¯¹å®ææå ´è¶£ç人ï¼ä¸è¿å¯¹äºä½¿ç¨åå¾æ¶éè¿è¡æ¶è¯è¨çå¼åè èè¨å®ä¹å ·æä¸å®çå¸å¼åï¼æ¯å¦ ScalaãGoãPythonãRuby å JavaScript çè¯è¨ã
Kotlin æ¥èªä¸çï¼èä¸æ¯å¦æ¯çãå®è§£å³äºå¼åè ç°ä»é¢ä¸´çå®é é®é¢ãä¾å¦å®çç±»åç³»ç»å¯ä»¥å¸®å©ä½ é¿å 空æéå¼å¸¸ã
åæ¢å° Kotlin æ éææ¬ï¼å®æ¯å¼æºçä½è¿ä¸æ¯éç¹ï¼éç¹æ¯å®æä¾äºä¸ä¸ªé«è´¨éçä¸é®ä» Java 转æ¢å° Kotlin çå·¥å ·ï¼å¹¶ä¸ååå ³æ³¨ Java äºè¿å¶æ件çå ¼å®¹æ§ãä½ å¯ä»¥å°ç°æ Java 项ç®çä¸æ¬¡æ§è½¬æ¢æ Kotlin 项ç®ï¼è该项ç®ä»å°å¯ä»¥æ£å¸¸ç¼è¯ï¼å³ä½¿è¿æ¯ä¸ä¸ªå å«ä¸ç¾ä¸è¡ä»£ç çå¤æç¨åºã
æ¾ç¶ä½ å¯ä»¥ä»ä¸æå¾ç¥ï¼Kotlin ç¨åºè½å¤ä½¿ç¨ææç°åç Java æ¡æ¶ååºï¼çè³é£äºä¾èµæ³¨è§£å¤ççé«çº§æ¡æ¶ãå®ä»¬ä¹é´ç交äºæ¯æ ç¼çï¼ä¸éè¦å è£ æè éé å±ãKotlin å¯ä»¥æ´å Mavenï¼Gradle 以åå ¶å®æ建系ç»ã
å®ååå¹³æè¿äººï¼è¯æ³ç²¾ç¼ç´è§ï¼ä» ä» æ¯é 读è¯è¨åèææ¡£å 个å°æ¶å°±è½å¦ä¼ä½¿ç¨ãKotlin çèµ·æ¥ååå Scala ä½æ¯æ´å ç®æ´å¹¶ä¸å ¼é¡¾äºå¯è¯»æ§ã
å®ä¸éµå¾ªç¹å®çç¼ç¨å²å¦ï¼ä¾å¦æ度çå½æ°å¼ç¼ç¨æè é¢å对象ç¼ç¨é£æ ¼ã
å®ä¸ä¼å¢å è¿è¡æ¶çå¼éãKotlin çæ ååºååå°å·§ç´§åï¼ä¸æ³¨äºæ©å± Java æ ååºï¼ç¼è¯é¶æ®µç大éå èæä½æå³å map/filter/reduce ç管éç»æå½æ°å°è¢«ç¼è¯æ类似äºå½ä»¤å¼è¯è¨ç代ç ã
Anko ä¸ Kovenant çæ¡æ¶çåºç°æå³çå¨ Android å¼åè ä¸ Kotlin å¼å§åå¾æµè¡èµ·æ¥ãå¦æä½ æ£å¨ä»äº Android ç¸å ³çå·¥ä½ï¼ç¸ä¿¡ä½ å¾å¿«å°±ä¼è·å¾å¥½çå·¥ä½ãä½ å¯ä»¥é 读è¿ä»½ Square å ¬å¸å¼åè JakeWharton çæ¥åï¼äºè§£ç¨ Kotlin è¿è¡ Android å¼åçä½éªã
Kotlin å è®¸ä½ ç»§ç»ä½¿ç¨ä½ çå·¥ä½æçæåå·¥å ·ãIntelliJ ç IDE 对 Kotlin çæ¯æååå®åï¼ä½ å¯ä»¥å¯¹ä»£ç è¿è¡éæãæç´¢ã导èªä»¥å使ç¨èªå¨å®æï¼èä¸ IDE å åæ¯æè°è¯ãåå æµè¯ãæ§è½åæççåè½ã
é¤äº Androidï¼æ认为 Kotlin è¿é常éç¨äºä¼ä¸ä¸ Java çåºç¨åºæ¯ãå¦æä½ çå·¥ä½æ¯æ´å¤©å头äºå¤§å ¬å¸ç代ç åºä¸ï¼é£ä¹å½ Kotlin 1.0 çæ¬æ£å¼åå¸æ¶ä½ åºè¯¥å°½å¿«å»äºè§£ä¸ä¸ï¼
ç±ç¥åå ¬å¸ä¸ºå®æä¾å¼ºå¤§çåä¸æ¯æã JetBrains è¿å®¶å ¬å¸ æä¸ä¸ªé«åº¦ç§°èç大å¢éè´åäºè¯¥é¡¹ç®ï¼æ稳å®çåä¸æ¨¡å¼çè³å¨èªå·±çé¨åæè°äº§åä¸ä½¿ç¨ Kotlinï¼è¿è¡¨æçæå Kotlin ä¸ä¼è¢«æ¾å¼ã
ä½¿ç¨ Kotlin é£é©è¾ä½ï¼å¯ä»¥ç±ä¸ä¸¤ä¸ªæå ´è¶£çå¢éæåå¨é¡¹ç®ä¸å°èå´çè¯éª Kotlinï¼è¿å¹¶ä¸ä¼æ°ä¹±ä½ ç项ç®ï¼å 为 Kotlin ç类对å¤æä¾ç Java API çèµ·æ¥å°±ä¸æ®éç Java 代ç ä¸æ ·ã
å 为 Kotlin åå注éè¯æ³çå¯è¯»æ§ï¼ä»£ç 审æ¥ä¸ä¼æ为é®é¢ï¼å¯¹ Kotlin ä¸çæçå¢éæåä»ç¶è½å¤å®æ该工ä½ã
Kotlin åºäº Java 6ï¼æ以åå¦ä½ é¾ä»¥å¨é¡¹ç®ä¸å级使ç¨æ°çæ¬ç JVMï¼ä½ å¯ä»¥ä½¿ç¨ Kotlinã
ä»å¹´æ©äºæ¶åæå Swiss Re è¿å®¶ç士åä¿é©å ¬å¸çå¢éï¼ä»ä»¬ä½¿ç¨ Java å .NETï¼å±ç¤ºäº Kotlinãé¦å æå®ä¹äºä¸ä¸ªç®åç Java ç±»å å«ä¸äºå段以å toStringãequalsãhashCode çæ¹æ³ï¼å¤§æ¦æ è¡ä»£ç ãç¶åæå°å®è½¬æ¢æ Kotlin 代ç ï¼å¤§é¨åæ¯èªå¨å®æçï¼ï¼ç»æä» å© 1 è¡ä»£ç ï¼æ¥çæè¿æ¼ç¤ºäºå ¶å®èçæ¶é´çç¹æ§ãä»ä»¬çè¿å对 Kotlin å 满äºçæ 并ä¸è®¤ä¸º Kotlin æ¯å®ä»¬é¡¹ç®ä¸ C# è¯è¨çä¸ä¸ªæ½å¨ç«äºå¯¹æã
æ认为 Kotlin æ£ä¸ä¼ä¸ Java å¼åè ç红å¿ï¼æ以尽管 Kotlin æ¯å è´¹çï¼JetBrains è¿æ¯è½å¤éè¿å®å¢å åä¸çæ¬ IDE çéå®æ¥èµå¤§é±ãè¿å°æ¿å±ä»ä»¬æ ¹æ®ç¨æ·çææ¿æç»æ¹è¿å®ã
ä¸æ¤ç¸æ¯ï¼å¯¹äºé£äºç±ä¸ç¸å ³äº§åèµå©çè¯è¨å¼åè æ¥è¯´ï¼å½ç¨æ·éæ±ä¸ä¹åç设计ç念å²çªæ¶ï¼ä»ä»¬å¾å°ä¼å æ¤ä½åºè°æ´ã
ç¹æ§
Kotlin ä½ä¸ºä¸é¨æ°çç¼ç¨è¯è¨è½å¤è±é¢èåºï¼æ¯å 为å®å ³æ³¨çæç³»ç»ï¼JetBrains æå¾ç产åçé«ä½æ´å¤çåå³äºçæç³»ç»èä¸æ¯ä¾¿æ·çè¯æ³ã
尽快å¦æ¤ï¼Kotlin è¿æ¯æ许å¤æç¨çç¹æ§è½è®©ä½ ç¼ç çè¿ç¨åå¾æå¿«ï¼
æ们已ç»æè¿ null å®å ¨ï¼å¯éï¼ï¼å®è½å¤è®©ç¼è¯å¨ç³»ç»çæ è®°æ½å¨ç空æéå¼ç¨ãä¸ä¸äºè¯è¨ä¸åçæ¯å®ä¸æ¶å option ç±»ï¼å æ¤æ¯é¶å¼éçï¼å¹¶ä¸è¿æå ¶å®è¯è¨ç¹æ§ç¡®ä¿å®ä¸ä¼é æä¸ä¾¿ã
ç²¾ç¼çè¯æ³ï¼æ å¤ä¸å¨çç±»åæ¨æãç®åçå½æ°åªéè¦ä¸è¡ãç®åçç»æ以å JavaBeans ä¹åªéè¦ä¸è¡å°±è½å£°æãçæ£çå±æ§ââå¯ä»¥å¨èåèªå¨çæ getFoo/setFoo æ¹æ³ç¨äºä¸ Java è¿è¡äº¤äºãå½æ°å¯ä»¥ç¬ç«åå¨äºç±»ä¹å¤ã
å¼å¸¸å为éæ£æ¥åãï¼è¯è 注ï¼æå ´è¶£çå¯ä»¥é 读ä¸ä¸Java ç论ä¸å®è·µ: å ³äºå¼å¸¸çäºè®ºï¼
ä½¿ç¨ data class å ³é®åå建æ°æ®ç±»ä¼èªå¨çæéç¨æ¹æ³ï¼ä¾å¦ equalsãhashCodeãtoString 以å copy å componentNï¼åæ¶å£°æå¤ä¸ªåéæ¶ä¼è°ç¨è¯¥æ¹æ³ï¼ãè¿å°å¸®å©ä½ å¨ä¸ä½¿ç¨æ建å¨çæ åµä¸ä¾¿æ·çè·å¾ä¸åç±»ï¼immutable classesï¼ã
ä½å¦æä½ éè¦æé å¤æçç»æä½ï¼åå©ç±»åå®å ¨çæ建å¨è¿ä¸ªç¹æ§å¯ä»¥ç®æ´çå®ç°ãå¦æä½ ä½¿ç¨ Google Protocol Buffers æ¥åå¨ç»æåæ°æ®ï¼ éè¿ KBuilders è¿ä¸ªåºä¹è½å¾è½»æåå°ã
æ¯æå½æ°å¼ç¼ç¨ä»¥åé¶å¼éç lambda 表达å¼ï¼è½å¤å¨ Java çéåä¸å MapãFilterãFolder çå¤çãKotlin çç±»åç³»ç»è½å¤èªå¨è¯å«å¯åæè ä¸å¯åçéåã
æ©å±å½æ°ç¹æ§è½å¤è®©ä½ å¨ä¸æ¹å¨æºç çæ åµä¸ä¸ºç±»æ·»å æ¹æ³ãä¹ç¼ä¸ç以为æ¯ä¸ºäºé¿å ååºå FooUtils è¿ç§é£æ ¼å·¥å ·ç±»çè¯æ³ç³ï¼ä¸è¿éç使ç¨çå æ·±ï¼ä½ ä¼è®¤è¯å°å®ä¸ä» è½å¸®ä½ æ´å 容æçéè¿èªå¨å®æ使ç¨æ¹æ³ï¼è¿è½åå©ä½ éæç°æç Java API 以ååå©å ¶å® Kotlin ç¹æ§æ建åè½å¼ºå¤§çæ©å±ã
æ¯æè¿ç®ç¬¦éè½½ï¼ä½æ¯ä¸ä¼å Scala æè Perl é£æ ·åºç°é¾ä»¥ç解ç代ç ãè¿ç®ç¬¦è¢«æ å°æç¸åºååçæ¹æ³ï¼éè¿éåè¿äºæ¹æ³æ¹åè¿ç®ç¬¦çè¡ä¸ºï¼å æ¬å½æ°è°ç¨ï¼ï¼ä½æ¯ä¸è½å®ä¹æ°çè¿ç®ç¬¦ãè¿ä½¿å¾ç¨åºè½å¤å ¼é¡¾åè½ä¸å¯è¯»æ§ã
Kotlin 没æå®æè å ¶å®çæ¹å¼æ¥éå®ä¹è¯è¨ï¼ä½æ¯éè¿è¿äºç²¾å¿è®¾è®¡çç¹æ§è½å¤ä½¿ç¬¬ä¸æ¹åºèªç±ç对å®è¿è¡æ©å±ï¼å®æ¹å¯¹éåç±»è¿è¡çæ©å±ä¹åªæ¯å°è¯çåèå·²ï¼è¯·ç以ä¸ä¾åã
æ³ä½¿ç¨ fibersãactors å Go é£æ ¼ç channelsï¼ä¸ä¸ªå为 Quasar çåºå·²ç»ä¸ºä½ å®ç°äºã
ä½¿ç¨ Markdown æ¿ä»£ HTML æ¥ç¼å API ææ¡£ï¼è¿æ ·ç¼å JavaDocs å¯æ¯ä»¥åèéå¤äºãï¼è¯è 注ï¼JetBrains æä¾äºç¸åºçææ¡£çæå¨ Dokkaï¼
æ´å¥½ç¨çæ³åãå¦æä½ æ²¡æå®å ¨ææ¡æ³ååæ°ä¸ super 以å extends çå«ä¹ï¼å«æ å¿ï¼è¿ä¸æ¯ä½ çéãJava çæ³åç确令人费解ï¼Kotlin 解å³äºè¿ä¸ªé®é¢ã
å§ææ¯ä¸ä¸ªå¤§å®¶é½ç¥éç设计模å¼ï¼Kotlin åçæ¯æå®ã
== è¿ç®ç¬¦çè¡ä¸ºç¬¦åé¢æï¼è¯è 注ï¼ç®åæ¥è¯´ a == b ç¸å½äº a.equals(b)ï¼æ°å¢äº === è¿ç®ç¬¦ï¼ç¨æ¥å¤æè¿ç®ç¬¦ä¸¤è¾¹æ¯å¦æååä¸ä¸ªå¯¹è±¡ï¼
æ³å¿«é便æ·çè¿è¡å¼æ¥ç¼ç¨åï¼å½ç¶ï¼
å符串æå¼âå¯ä»¥ä½¿ç¨è¿æ ·çåæ³å¨å符åä¸ç´æ¥å¼ç¨åé { this.example}â
å½æ°ä¸çåæ°å¯ä»¥æå®é»è®¤å¼ã使ç¨å¯åé¿åº¦ä»¥åéè¿åæ°åä¼ åã
è¿æ许å¤çè°æ´ä¸ä¼åãåå¦ Java ä¸ææäºè®©ä½ è§å¾å°æ°çé®é¢ï¼æç¸ä¿¡ Kotlin ä¸å®å·²ç»æå®å¤ç好äºã
ç°å¨å°±æ¥è¯ç¨ä¸ä¸ï¼
è·å¾å¤ç°ä»£ç¼ç¨è¯è¨ä¸æ ·ï¼Kotlin å¯ä»¥éè¿ç½é¡µæµè§å¨æ¥è¿è¡ä½éªãä¸è¿è·å ¶ä»è¯è¨ä¸ä¸æ ·çæ¯ï¼Kotlin çå®éªç½ç«æä¾äºä¸ä¸ªæçç IDEï¼å æ¬ååºå¾å¿«çèªå¨å®æï¼å®æ¶çåå°ç¼è¯ï¼çè³è¿æå¨çº¿çéæåæï¼
å¨çº¿è¯ç¨ä¸ä¸å§
好äºï¼è®©æ们继ç»æ¥ä¸æ¥çå 容
ç®ååå¨åªäºé®é¢ï¼
çæ´»ä¸æ²¡æä»ä¹æ¯å®ç¾çï¼å æ¬ Kotlinã以ä¸æ¯æå°è¯è¿é¨è¯è¨æ¶éå°çä¸äºé®é¢ã
æ大çé®é¢æ¯ä¸å¤æçï¼å 为 Kotlin ç®åè¿å¤äº Beta é¶æ®µï¼è¿æå³çï¼
æ¯æ´æ°ä¸ä¸ªçæ¬ï¼è¯æ³ãABI 以åæ ååºå°±åä¸æ¬¡ã好æ¶æ¯æ¯è¿äºååé常æ¯è¾å¾®å°ï¼å¯ä»¥åå© IntelliJ IDE æ¥èªå¨åçº§ä½ ç代ç ï¼æ以è¿ä¸ªè¿ç¨å¹¶ä¸ä¼å¤ªéº»ç¦ã
Java-to-Kotlin ç转æ¢å·¥å ·ï¼J2Kï¼è¿æ²¡æå®æãå®å¶å°ä¼å¤§è§æ¨¡çç ´ååé»é»å°æ¦é¤ Java 8 ä¸ç Lambdasï¼ä¿®æ¹ï¼ å¹´ æï¼M çæ¬ç转æ¢å·¥å ·å·²ç»å¯ä»¥æ£ç¡®å°å¤ç Java 8 çç¹æ§äºï¼ãç±å®è½¬æ¢èæç代ç 并ä¸æ»æ¯æ好çåæ³ï¼ä½æ¯ JetBrains 为è¿ä¸ªå·¥å ·ä»åºäºå¤§éåªåï¼å®å·²ç»æ¯æç¨è¿çè¯è¨è½¬æ¢å·¥å ·ä¸æ好çäºãæ以æ并ä¸å¤ªæ å¿è¿ä¸ªé®é¢ï¼è¿ä¸ªè½¬æ¢å¨æ£å¨è¿ éçæ¹è¿ä¸ï¼åå¾è¶æ¥è¶æçã
ä½ ä¼éå°ç¼è¯å¨é误ã尽管æçç¨åºå¹¶ä¸å¤§ï¼ä½è¿æ¯ä¼åçæ æ³ç¼è¯çæ åµï¼çè³é误çç¼è¯ç»æãè¯æè¿äºé®é¢å¹¶ä¸é¾ï¼ä½ç»å½è¿æ¯å½±åäºå¼åçä½éªã
ä½ ä¼éå° IDE å é¨é误ãå½è¿ä¸ªé误åçæ¶ï¼IntelliJ IDE ä¼å¼¹åºä¸ä¸ªæ¬æµ®çªå£ï¼é带å JetBrains æ¥åçé项ã大é¨åé误æ éçä¼ï¼ä¸è¿ä¾ç¶ä¼ä½¿äººåç¦ã
å¶å°ä¼åºç°æ æ³å è½½æ示ææ¡£çé误ï¼ä¿®æ¹ï¼M çæ¬åå¸åï¼è¿ä¸ªé®é¢å·²è¢«ä¿®å¤ï¼
ç®å JetBrains æ£è´åäºå®ååå¸ 1.0 çæ¬èä¸æ¯æ·»å æ°çåè½ï¼æå¾ è¿äºé®é¢è½å¤å¾å°ä¿®å¤ã
第äºä¸ªæéå°çæ¯è¾å¤§çé®é¢æ¯ï¼ææ¶ä¸ Java ç交äºä¼åå°å±éã
ä¸ä¸ªå ¸åç Bug æ¯ Java çç±»åç³»ç»æ æ³é²æ¢ä½ æ¹å Map ä¸ Key çç±»åãæçæ¥è¯´ï¼è¿æ ·æä½åºè¯¥å¯¼è´ç¼è¯å¨æ¥éï¼ä¾å¦ä½¿ç¨ç±»åé误ç Key å é¤å ç´ ãæäº JDK ä¸çéå使ç¨äºæ³åï¼å®ä»¬æäºéè¦æ¹æ³çæ³ååæ°æ¯ Obejctï¼æ以ç¼è¯å¨ä¸ä¼æ示ãå½å¨ IntelliJ IDE ä¸ç¼å Java 代ç æ¶ä¼æéæåæçè¦åï¼ä½æ¯ç®å Kotlin ç¯å¢è¿æ²¡æè¿ä¸ªåè½ãå 为 Kotlin 使ç¨çæ¯ Java çéåæ¡æ¶æ²¡æèªå·±å®ç°ï¼æ以è¿å¯¼è´äºä¸äºç±»åå®å ¨æ¹é¢çé®é¢ï¼æå·²ç»éå°å¥½å 次äºã
ï¼ä¿®æ¹ï¼1.0 Beta çæ¬ä¸è¿ä¸ªé®é¢å·²ç»è§£å³äºï¼Java ä¸éåæ¡æ¶çç±»åå®å ¨ç¼ºé·å¨ Kotlin å·²ç»ä¸å¤åå¨ãååµï¼ï¼
å¦ä¸ä¸ªä¾åæ¯ï¼å½è°ç¨æä½¿ç¨ Java 代ç æ¶ Kotlin ç Null å®å ¨ç¹æ§æ æ³åæ¥ä½ç¨ï¼å¯ä»¥åå©æ³¨è§£å¼¥è¡¥ï¼ãä½ä¸º Kotlin çåå¦è ï¼åå¼å§ä½ å¯è½ä¼å许å¤è°ç¨ Java åºç代ç ï¼ä½æ¯å 为以ä¸çé®é¢å®ä»¬å¹¶æ²¡æä½ æ³è±¡ä¸é£ä¹å¥½ç¨ãè¿ç§æ åµçæ¹ååªè½çå¾ Kotlin 使ç¨äººæ°çå¢é¿ãJetBrains ä¸ç´å¨å°è¯ä½¿ Null å®å ¨ç¹æ§è½ä½ç°å¨ Java 交äºä¸ï¼è¿ç§æ³æ³æ¯å¥½çï¼ä½ææ¶èè并太å¨å ¨ãï¼ä¿®æ¹: ä» M çæ¬å¼å§ï¼å¨ Java 代ç ä¸å°èªå¨ä»¥ @NotNull @Nullable ç注解å®ç° Kotlin ç Null å®å ¨ç¹æ§ï¼
è½ç¶æ以ä¸çé®é¢åå¨ï¼ä½åæ¶ä¹ä½¿å¾æ们è½æ´æµç çä½¿ç¨ Java APIï¼æè§å¾è¿ç§æè¡¡æ¯å¼å¾çï¼åªæ¯å¨å¼åä¸è¦æ³¨æã
å ¶å®éè¦èèçé®é¢:
Kotlin ç社åºè¿æ¯è¾å°ãè½ç¶ç®å没æå¤å° Kotlin çåºå¯ä»¥ä½¿ç¨ï¼ä½æ¯ååä¼ç§ç Java 交äºè½åï¼Kotlin å¯ä»¥ä½¿ç¨ç°ææçç Java åºã
å¦æä½ å欢ç书æ¥å¦ä¹ ï¼é£ä¹ä½ éè¦çå°ä»å¹´æäºæ¶åæè½çå° Kotlin å¼åè åç书ï¼è¯è 注ï¼Kotlin in Actionï¼
纯粹çå½æ°ç¼ç¨é£æ ¼å¼åè å¯è½ä¼è§å¾ç±»åç³»ç»ä¸ç¼ºä¹ä¸äº Scala æ Haskell æ¥æçé«çº§åè½ãå¦æä½ å¯¹ç±»åç³»ç»ä¸äºåè½æ¯è¾çéï¼é£ä¹ Kotlin å¯è½ä¸éåä½ ã
Kotlin è¿è½ç¼è¯æ Javascript 代ç ï¼ä½æ¯æ¯è¾å°ç¨ï¼æ以å¯è½ä¼éå°æ´å¤çé®é¢ï¼è¿æ¯æä»è®ºåä¸å¾å°çå°è±¡ãï¼ä¿®æ¹: ç®å Kotlin çå¼åéå¿å¨äºå®æ 1.0 çæ¬å¹¶ä½¿å ¶ç¨³å®è¿è¡å¨ JVM ä¸ï¼Javascript æ¹é¢çé®é¢å°ä¼å¨ 1.0 åå¸åçæ解å³ï¼
没ææ åçç¼ç¨é£æ ¼æåï¼ç®å Kotlin æä¾äºå¤ç§è¯æ³å¯ä¾éæ©ãä¸å人ååºæ¥ç Kotlin 代ç å¾å¯è½å®å ¨ä¸ä¸æ ·ãè¿ä¸ Go ä¸¥æ ¼çé£æ ¼å½¢æäºé²æç对æ¯ãï¼ä¿®æ¹: Kotlin 1.0 çæ¬å¼å§ï¼ä¸äºçµæ´»çè¯æ³å·²ç»è¢«ç§»é¤äºï¼ä¾å¦ç°å¨éè½½è¿ç®ç¬¦ä»¥åå®ä¹ä¸ç¼å½æ°æ¶å¿ é¡»åå«ä½¿ç¨ operator å infix å ³é®åè¿è¡æ è®°ï¼
Kotlin çç¼è¯é度ç¨ç¨æ ¢äº Javaï¼ä»¥å IntelliJ IDE çæºè½æ示ååºæç¹ç¼æ ¢ï¼ä¸ç®ä¸¥éèä¸æ¯ Scala å¿«å¤äºãï¼ä¿®æ¹ï¼Kotlin 1.0 å¼å§ç¼è¯é度æäºææ¾æåï¼
Kotlin æä¸ä¸ª Eclipse æ件ï¼ä½æ¯å¾ææ¾æ²¡æ IntelliJ ç好ç¨ã
Kotlin å¨æäºæ¹é¢æ¯ Java è¦ä¸¥æ ¼ãå®ä¸ä¼èªå¨å° Int 转æ¢ä¸º Long ç±»åï¼éè¦å¼åè æ¾ç¤ºç转æ¢ãè¿æ¯å 为 Kotlin å ³æ³¨æ£ç¡®æ§åè¯å¾è§£å³ãJava Puzzlersãä¸ä¹¦ä¸æåºçé®é¢ãJetBrains 声称ä»ä»¬å·²ç»æå®ä¸åäºã
Kotlin åºäº Java 6ï¼å æ¤ä¼åå°å®çå±éãKotlin ä¸ C# å¨å¾å¤é¢åé½å¾ç¸ä¼¼çè³æ¯ C# åå¾æ´å¥½ï¼ä½æ¯å®ç¼ºå°ä¸äºåè½ï¼ä¾å¦ Java å¹³å°å°æªæ¯æçæäºæ°æ®ç±»åã
为ä»ä¹åºè¯¥å¼å§èèä½¿ç¨ JVM
æè¿ä¸æ®µæ¶é´æéå°äºå¾å¤ä½¿ç¨å¨æèæ¬è¯è¨ï¼JavaScript æè Go ââ è¯è 注ï¼Go åºè¯¥æ¯éæç¼è¯åè¯è¨ï¼çåä¸å ¬å¸ã
æå¨ Bitcoin Space å·¥ä½çæ¶åï¼ä½¿ç¨å¨æè¯è¨æ¯é常çè¦çäºæ ãå¨è¿äºè¯è¨é没æå®å ¨æ§çç±»åï¼è¿å·²ç»å¯¼è´äºå·¨å¤§çè´§å¸æ失ãGo æ¯è¾å°åºéï¼ä½æ¯å¨åºç¡å±é¢ä¸ç»äººçä½éªä¾ç¶å¾å·®ï¼æ¯å¦è¯´ç¼ºå°å¥½çè°è¯å·¥å ·ï¼å¿«é GC æºå¶ï¼ç¨³å¥ç管çå¨ä»¥åå¯é çåæå·¥å ·ã
è¿å» å¹´æè æ´é¿æ¶é´éï¼Java åå¾è¶æ¥è¶å¥å£®ï¼è¶æ¥è¶åé¿ï¼çè³æè¿åº¦è®¾è®¡ç迹象ï¼è¿äºååå¾å¤§ç¨åº¦ä¸æºäºå®ç声èªãä¼ä¸çº§ Java ç±»çåå PathVariableMapMethodArgumentResolver å°±æ¯ä¾è¯ãå¨å¾é¿ä¸æ®µæ¶é´éæ没æèè JVMï¼æ确信è¿ç§ç¯å¢å¹¶ä¸éåæã
æç»æå 为 Android 被迫åå° Javaï¼åç° Java çå¼åç¯å¢å·²ç»æ¹åäºãè½ç¶ XML ä»ç¶ä¸åæ¶å®çé¢ç¹åºç°å¨åç§åºåï¼ä½æ¯ä¸äºåºç¡åè½ååå®åï¼ä»¤äººå°è±¡æ·±å»ã IntelliJ æ¯æ¯ Eclipse æ´å¿«å¹¶ä¸æ´æºè½ç IDEãMaven ä¸åºç°å°±å¾å°äºè¿ éçåå±ï¼æ¥æ许å¤åæ¬ææ³è¦å ¶å®æ建 / ä¾èµç³»ç»å¢å çåè½ãè¾æ°ç Web æ¡æ¶å Ninja å Play ä»ç±»ä¼¼ Ruby on Rails çæ¡æ¶ä¸å¦å°äºè½»éç®æ´ãæ大éçåºå¯ä¾ä½¿ç¨ã硬件æ§è½åå¾æ´é«ä»¥å JVM åå¾æ´ææçï¼çç转åã
没æçæ£æ¹åçæ¯è¯è¨æ¬èº«ï¼Java 代ç åèµ·æ¥ä¾ç¶æ¯ä»¤äººä¸å¿«çåé¿ã
ç°å¨æäº Kotlinï¼å®å ¨æ éæ¿åç¦»å¼ Java ç°æççæç³»ç»çç¼è¦ãä½ å¯ä»¥ç¼åæ´å¯æ表ç°åç代ç ï¼ä½æ¯å´æ¯èæ¬è¯è¨æ´ç®æ´ï¼åæ¶æ¥ææ´å¥½çæ§è½åæ´å°çé误ã
å¦æä½ å欢 JavaScriptï¼å¯ä»¥å°è¯ Kotlin ç JS å端ï¼æè å¨ Nashorn JS å¼æéè¿è¡ä½ ç°æç代ç ã
æåï¼å¦æä½ å欢 Go è¯è¨æ¯å 为å®å¯ä»¥ç¼è¯ç¬ç«è¿è¡çç¨åºï¼é£ä¹è¯è¯ javapackager å·¥å ·ãKotlin å¨æ¬å°ä¸ºæ¯ä¸ªå¹³å°å建äºæç»å ï¼è¿æå³çå¨ linux ä¸ä¸éè¦ JRE çä¾èµå°±å¯ä»¥ç¬ç«èªä¸»çè·å DEBsï¼linux çå®è£ å ï¼æè å缩å ãå½ç¶ï¼å®æå ä¹åä¸æ¯å个æ件èæ¯å个ç®å½ï¼ä»é¨ç½²çè§åº¦æ¥ç并ä¸é¾æä½ã
ç®èè¨ä¹ï¼å¦æä½ ä¹åå 为ç Java ä¸é¡ºç¼è忽ç¥äº JVM ççæç³»ç»ï¼é£ä¹ä½ åºè¯¥åç Kotlin è¿é¨æ°è¯è¨è¿å ¥è¿ä¸ªä¸çç§ç§ã
有没有靠谱的公司能定制红心大战扑克牌棋牌游戏?需要多少钱?
开发定制红心大战扑克牌棋牌游戏,需考虑游戏需求、界面、功能与种类,成本与价格因需求差异而异。一般而言,基础款游戏起步价约在万左右。定制开发确保源码所有权,利于后期系统升级与维护。部分不专业公司提供的游戏可能漏洞百出,维护问题不予理会。
推荐一家值得信赖的公司:大游网络科技,位于湖南。专注于棋牌游戏开发多年,拥有强大的公司实力与专业团队。提供一对一服务,根据客户需求与玩家习惯,定制专属棋牌游戏。游戏功能全面,包含地方风俗、方言特色与亲友圈等,成品游戏多达数百款,确保游戏体验与安全性。如有兴趣,可深入了解。