本文主要是介绍新形态C语言程序设计游戏化任务教程:第6章17关-20关,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
前言:
题目链接
进入链接后,点击实践项目,以下题目为6.8.17到6.8.20,
古老的纸牌游戏
任务描述:
本题所述的麻将纸牌只包括3大类别的牌:条、饼、万(不包括老千、红花和白花)。每大类的牌点数都有从1至9,共27种牌,每种牌有4张,一副牌只取108张。
和牌规则:
5张牌和(音:胡)牌的规则如下:
1.必须有一个对子,即两张相同的牌,称为“掌”,比如:两个2饼做掌,两个4条做掌等。
2.剩余的3张牌,如果正好形成“哈子”(3个一样的牌,如3个2饼,麻将中称为一刻)或者“一趟副”(同种类点数连续,如1条、2条、3条),就可以和牌了。
3.输入的牌肯定是4张。
4.条用T表示,饼用B表示,万用W表示。
也可以理解为和牌类型有以下几种(11表示一对,123表示一副、111表示一刻):
(1)11、123(1副1对)
(2)11、111(1哈1对)
假设你手中有4张牌,如果加上别人打出手的1张牌或你自己再摸1张牌,就构成和牌,则称“有叫儿”(麻将称为听牌)。
给你4张牌,你知道自己是否“有叫儿”并和什么牌吗?
输入格式:
输入共一行,代表一组数据(一手牌)。
在一行中包含以1个空格分隔的4个数据,每个数据由1个数字加1个大写字母构成,代表1张纸牌,4个数据代表一手牌。(例如:1T代表1条、2W代表2万、9B代表9饼)。
输出格式:
该组数据如果“有叫儿”,则依次输出可以和的牌(叫儿),如果有多个“叫儿”,按“条、饼、万”的顺序输出,同一种类的牌,按点数从小到大输出,每个“叫儿”之后输出一个圆点句号。
该组数据如果“没有叫儿”,则输出:No jiaor。
输入样例(平和2张):
4B 4B 3T 4T
输出样例:
2T.5T.
输入样例(和对倒2张):
1T 6W 6W 1T
输出样例:
1T.6W.
输入样例:(和边张)
1T 2T 6B 6B
输出样例:
3T.
输入样例(和卡):
4T 2T 6W 6W
输出样例:
3T.
输入样例(和单吊1张):
4T 2T 6W 3T
输出样例:
6W.
输入样例(和单吊或和卡):
4T 2T 3T 3T
输出样例:
3T.
输入样例(平和、单吊):
4T 4T 4T 3T
输出样例:
2T.3T.5T.
输入样例(没和):
4T 4T 4T 4T
输出样例:
No jiaor
输入样例(没和):
4T 4T 4W 8B
输出样例:
No jiaor
解题思路:
还记得上次写扑克,这次是写麻将,麻将的规则比起扑克要麻烦一些,从题目给出了很多的样例也可以看出
-
使用结构体对麻将卡牌进行拆分
-
输出是要按牌型排序的,用一个数组type存储牌型,用序号表示优先级
-
记住一副牌里一种卡牌只有四张,如果手上卡牌4张一样的话是没法有叫儿的
-
可以分析一下,一共有4张牌,对于牌型,若三种牌型卡牌分布为1 1 2是不可能有叫儿的,
-
不论顺序,要有叫儿的话,只有三种牌型分布4 0 0,2 2 0,3 1 0
-
先分析4 0 0的情况,也就是手上4张牌牌型一样,这种是情况最复杂的,按我写的代码的思路按顺序说情况,
先是4张牌点数连一起,那可以和的牌只有牌只有两张,中间的不能动,与最小点数或最大点数凑成对子
三张牌点数连一起,以实例展示吧,比如4T 2T 3T 3T,这种情况只能再给一张与那张对子一样的牌,还有就是4T 2T 3T 7T,与剩下那张凑个对子
三张卡牌相同,那就要判断剩下那张卡牌与这三张的点数关系,还要判断边界关系,比如 1T 2T 2T 2T,这种卡在边界的,就只有两种,一种自身,还有组成一个顺子,不在边界且差为1,比如4T 4T 4T 3T,除了自身,还可以组两种顺子,还有差为2的,比如4T 4T 4T 2T,一种自身,一种顺子,当差大于2时,就只有自身了 -
3 1 0的情况,只有那三张牌凑成了顺子或一样的,才行,只有一种就剩下那张牌再来一张才能和
-
2 2 0的情况,只有两两为对子或一为对子,另两张点数相连才行,若为对子就输出对子的牌,注意按从小到大输出,有对子就只能凑对子了
参考代码:
#include<stdio.h>char type[3] = {'T', 'B', 'W'};//表示牌型优先级
struct node {char model;//牌型int number[10];//存储该牌型对应的点数的牌,比如若有点数为1的牌,则number[1]++int flag;//表示在该牌型有几张牌
} card[3];//三种牌型void print() {//没有叫儿printf("No jiaor");
}void flag_1() {//处理当其他三张牌凑成了顺子或一样时的情况,且牌型与那三张牌不同for (int i = 0; i < 3; i++) {if (card[i].flag == 1) {for (int j = 1; j <= 9; j++) {if (card[i].number[j]) {//找出那张牌,再给一张一样的牌就是一个对子,就和了printf("%d%c.", j, card[i].model);return;}}}}
}int same_card(int i) {//三张牌凑成了顺子或一样的for (int j = 1; j <= 7; j++) {if ((card[i].number[j] && card[i].number[j + 1] && card[i].number[j + 2]) || card[i].number[j] == 3) {flag_1();return 1;}}return 0;
}
int Straight(int i)//4张卡牌顺子
{for(int j=1;j<=6;j++){if(card[i].number[j] && card[i].number[j + 1] && card[i].number[j + 2]&&card[i].number[j + 3]){printf("%d%c.%d%c.",j,card[i].model,j+3,card[i].model);return 1;}}return 0;
}
int _Straight(int i)//三张顺
{int vis[10]={0};int j;for(j=1;j<=7;j++){if((card[i].number[j] && card[i].number[j + 1] && card[i].number[j + 2])){vis[j]=vis[j+1]=vis[j+2]=1;break;}}if(j==8)//j==8意味着没有顺子return 0;for(j=1;j<=9;j++){if(vis[j]&&card[i].number[j]==2)//情况例:4T 2T 3T 3T{printf("%d%c.", j, card[i].model);return 1;}if(!vis[j]&&card[i].number[j]){printf("%d%c.", j, card[i].model);return 1;}}return 0;
}
void same_card_4(int i,int j)
{int k;for(k=1;k<j;k++){if(card[i].number[k]){break;}}if(k<j){if(j-k==1)//情况例:4T 4T 4T 3T{if(k>1)printf("%d%c.",k-1,card[i].model);printf("%d%c.",k,card[i].model);printf("%d%c.",k+2,card[i].model);return;}else if(j-k==2)//情况例:4T 4T 4T 2T{printf("%d%c.",k,card[i].model);printf("%d%c.",k+1,card[i].model);return;}printf("%d%c.",k,card[i].model);//差大于2return;}for(k=j+1;k<=9;k++){if(card[i].number[k]){break;}}if(k<=9){if(k-j==1)//情况例:4T 4T 4T 3T{printf("%d%c.",k-2,card[i].model);printf("%d%c.",k,card[i].model);if(k<9)printf("%d%c.",k+1,card[i].model);return;}else if(j-k==2)//情况例:4T 4T 4T 2T{printf("%d%c.",k-1,card[i].model);printf("%d%c.",k,card[i].model);return;}printf("%d%c.",k,card[i].model);//差大于2return;}
}
void flag_2()
{int count=0;int number_2[2];int Pairs[2]={0};int count_i;int Pairs_i;for(int i=0;i<3;i++){if(card[i].flag==2){for(int j=1;j<=9;j++){if(card[i].number[j]==2){number_2[count++]=j;if(count==2){printf("%d%c.",number_2[0],card[count_i].model);printf("%d%c.",number_2[1],card[i].model);return;}count_i=i;break;}else if(j<9&&card[i].number[j]&&card[i].number[j+1]){if(j>1)Pairs[0]=j-1;if(j<8)Pairs[1]=j+2;Pairs_i=i;break;}else if(j<8&&card[i].number[j]&&card[i].number[j+2]){Pairs[0]=j+1;Pairs_i=i;break;}}}}if(count==1){if(Pairs[0])printf("%d%c.",Pairs[0],card[Pairs_i].model);if(Pairs[1])printf("%d%c.",Pairs[1],card[Pairs_i].model);if(!(Pairs[0]||Pairs[1]))print();return;}print();
}
void solve() {for (int i = 0; i < 3; i++) {if (card[i].flag == 4) {if(Straight(i))return;if(_Straight(i))return;for(int j=1;j<=9;j++){if(card[i].number[j]==3)//三张卡牌相同{same_card_4(i,j);//传入j,从j开始往两头找剩下那张牌,也便于判断剩下那张牌与这三张卡牌的点数关系return;}}}if (card[i].flag == 3) {if(!same_card(i)){print();}return;}}flag_2();
}int main() {for (int i = 0; i < 3; i++)card[i].model = type[i];char model;int number;while (~scanf("%d%c", &number, &model)) {//获取输入的卡牌for (int i = 0; i < 3; i++) {if (card[i].model == model) {card[i].number[number]++;if (card[i].number[number] == 4) {//当有4张卡牌一样时,则不可能有叫儿print();return 0;}card[i].flag++;break;}}}solve();return 0;
}
餐饮服务质量调查打分
任务描述
在商业和科学研究中,人们经常需要对数据进行分析并将结果以直方图的形式显示出来,这会大大增加这些数据的直观性,也便于数据的分析与对比。下面以顾客对餐饮服务打分为例,输入一个正整数repeat (0<repeat<10),做repeat次下列运算:
输入一个正整数n(1≤n≤20),表示有n个学生被邀请来给自助餐厅的食品和服务质量打分,分数划分为1~5这5个等级(1表示最低分,5表示最高分),试统计调查结果,并用*打印出如下形式的统计结果直方图。
输入格式:
第1个整数repeat为数据组数,一共有repeat组数据,请分别处理每组数据,每组数据输出一个直方图。
接下来为repeat组数据,每组数据的第1个数为打分人数n,接下来为这n个人的n个打分。
输出格式:
按输出样例的样式输出结果。
输入样例:
1
10
1 2 2 3 3 5 2 2 3 5
输出样例:
** ** * *
* * * *
1 2 3 4 5
输入样例:
2
10
1 1 1 1 1 2 3 4 5 5
20
1 1 1 2 2 2 3 3 3 4 5 1 2 3 4 2 2 3 5 2
输出样例:
*
*
*
* *
* * * * *
1 2 3 4 5*** *
* * *
* * *
* * * * *
* * * * *
1 2 3 4 5
解题思路:
这题比起前面的纸牌游戏就简单不少了,就是画图
- 仍然是用结构体处理,number和score像构成了坐标一样,嘿嘿
参考代码:
#include<stdio.h>
struct node
{int number;//打该分的人数int score;//分数
}student[6];
int max=0;//打分最多,也就是图里的最高纵坐标
void solve()
{for(int i=max;i>0;i--){int flag=0;//统计图中空的地方int t=0;for(int j=1;j<=5;j++){if(student[j].number>=i){for(int i=0;i<flag;i++){printf(" ");}flag=0;if(t)printf(" ");printf("*");t++;}elseflag++;}printf("\n");}
}
int main()
{int repeat;scanf("%d",&repeat);int n,a;for(int i=1;i<=5;i++){student[i].score=i;}while(repeat--){scanf("%d",&n);for(int i=1;i<=5;i++)student[i].number=0;for(int i=0;i<n;i++){scanf("%d",&a); for(int j=1;j<=5;j++){if(a==student[j].score){student[j].number++;if(max<student[j].number)max=student[j].number;break;}}}solve();printf("1 2 3 4 5\n");}return 0;
}
月历
任务描述
X想知道某年某月的日历,你能为他编程输出吗?
输入格式:
输入一行,两个正整数,分别代表年份和月份。
输出格式:
严格按样例格式输出一个月的日历。
第1行输出月份简称和年份,中间有个圆点和空格。
第2行输出表头,为星期一至星期日的缩写,每个单词之间一个空格。
第3行为28个减号。
接下来的几行是日历内容,每个日期输出时占3列,日期前后之间再加1个空格,保证与相对应的星期名称右对齐。
输入样例:
2019 9
输出样例:
SEP. 2019
Mon Tue Wed Thu Fri Sat Sun
---------------------------12 3 4 5 6 7 89 10 11 12 13 14 1516 17 18 19 20 21 2223 24 25 26 27 28 2930
提示
重要提示:1900年1月1日是星期一。
星期一:Monday 缩写:Mon.
星期二:Tuesday 缩写:Tue.
星期三:Wednesday 缩写:Wed.
星期四:Thursday 缩写:Thu.
星期五:Friday 缩写:Fri.
星期六:Saturday 缩写:Sat.
星期日:Sunday 缩写:Sun.
一月份JAN.
二月份FEB.
三月份MAR.
四月份APR.
五月份MAY.
六月份JUN.
七月份JUL.
八月份AUG.
九月份SEP.
十月份OCT.
十一月份NOV.
十二月份DEC.
解题思路:
还是画图,不过这个感觉有意思些,
不过我一开始没有看到提示里的1900年1月1日是星期一。用了蔡勒公式
蔡勒公式:
int h = (day + 2 * month + 3 * (month + 1) / 5 + year + year / 4 - year / 100 + year / 400 + 1) % 7;
day为日,month为月份,year为年份
h的值是几,即为星期几,
为0时,星期天
参考代码:
使用蔡勒公式版:
//请在此输入你的代码,复杂程序可先在Dev C++中运行调试后再提交
#include<stdio.h>
void print_month(int year,int month)
{switch(month){case 1:printf("JAN. ");break;case 2:printf("FEB. ");break;case 3:printf("MAR. ");break;case 4:printf("APR. ");break;case 5:printf("MAY. ");break;case 6:printf("JUN. ");break;case 7:printf("JUL. ");break;case 8:printf("AUG. ");break;case 9:printf("SEP. ");break;case 10:printf("OCT. ");break;case 11:printf("NOV. ");break;case 12:printf("DEC. ");break;}printf("%d\n",year);
}
void print_week()
{printf("Mon Tue Wed Thu Fri Sat Sun\n");
}
int getWeek(int year,int month,int day)//蔡勒公式
{if(month<3)//如果给定日期在1月或2月(即month1为1或2),则需要将年份减1,将月份增加12。这是为了将这两个月视为前一年的13月和14月{month+=12;year--;}//int h=(sun+(13*(month1+1)/5)+year%100+(year%100/4)+(year/400)-2*(year/100))%7;int h=(day+2*month+3*(month+1)/5+year+year/4-year/100+year/400+1)%7;return h;
}
int main()
{int year,month;scanf("%d%d",&year,&month);print_month(year,month);print_week();for(int i=0;i<27;i++)printf("-");printf("\n");int k=year%100?year%4?0:1:year%400?0:1;int m[13]={0,31,28+k,31,30,31,30,31,31,30,31,30,31};int h=getWeek(year,month,1);int count=h;if(h==0){for(int i=0;i<6;i++)printf(" ");count=7;}for(int i=1;i<h;i++)printf(" ");int t=0;for(int i=1;i<=m[month];i++){if(t)printf(" ");printf("%3d",i);t++;if(count==7){printf("\n");count=0;t=0;}count++;}return 0;
}
利用题目中的提示:
//请在此输入你的代码,复杂程序可先在Dev C++中运行调试后再提交
#include<stdio.h>
void print_month(int year,int month)
{switch(month){case 1:printf("JAN. ");break;case 2:printf("FEB. ");break;case 3:printf("MAR. ");break;case 4:printf("APR. ");break;case 5:printf("MAY. ");break;case 6:printf("JUN. ");break;case 7:printf("JUL. ");break;case 8:printf("AUG. ");break;case 9:printf("SEP. ");break;case 10:printf("OCT. ");break;case 11:printf("NOV. ");break;case 12:printf("DEC. ");break;}printf("%d\n",year);
}
void print_week()
{printf("Mon Tue Wed Thu Fri Sat Sun\n");
}
int getWeek(int year,int month,int day)//蔡勒公式
{if(month<3)//如果给定日期在1月或2月(即month1为1或2),则需要将年份减1,将月份增加12。这是为了将这两个月视为前一年的13月和14月{month+=12;year--;}//int h=(sun+(13*(month1+1)/5)+year%100+(year%100/4)+(year/400)-2*(year/100))%7;int h=(day+2*month+3*(month+1)/5+year+year/4-year/100+year/400+1)%7;return h;
}
int fun(int year)//获取从1900到输入的年份的天数
{int days=0;for (int a = 1900; a < year; a++){if (a % 400 == 0 || a % 4 == 0 && a % 100 != 0){days+=366;}elsedays+=365;}return days;
}
int funweek(int year,int days)//判断星期几
{days+=fun(year);//总天数int h=days%7;return h;
}
int main()
{int year,month;scanf("%d%d",&year,&month);print_month(year,month);print_week();for(int i=0;i<27;i++)printf("-");printf("\n");int k=year%100?year%4?0:1:year%400?0:1;int m[13]={0,31,28+k,31,30,31,30,31,31,30,31,30,31};//int h=getWeek(year,month,1);int days=1;for(int i=1;i<month;i++){days+=m[i];}int h=funweek(year,days);int count=h;if(h==0){for(int i=0;i<6;i++)printf(" ");count=7;}for(int i=1;i<h;i++)printf(" ");int t=0;for(int i=1;i<=m[month];i++){if(t)printf(" ");printf("%3d",i);t++;if(count==7){printf("\n");count=0;t=0;}count++;}return 0;
}
鲜花数
任务描述
鲜花数是指一个N位正整数(7≥N≥3),它的每个位上的数字的N次幂之和等于它本身。
例如:
153=13+53+33 ,1634=14+64+34+44 。
当N=3时,花朵数又称为水仙花数;
当N=4时,花朵数又称为四叶玫瑰数;
当N=5时,花朵数又称为五角星数;
当N=6时,花朵数又称为六合数;
当N=7时,花朵数又称为北斗数,等等。
要求编写程序,输出所有N位花朵数。
输入格式:
一个整数N(7≥N≥3)
输出格式:
从小到大输出所有N位鲜花数,一个数一行。
输入样例:
3
输出样例:
153
370
371
407
输入样例:
4
输出样例:
1634
8208
9474
解题思路:
这题没什么好说的,就是N为几,就去遍历10N-1到10N的数,就是拓展了下那道经典的水仙花的题目
参考代码:
#include <stdio.h>
#include <math.h>// 函数声明,
int isFlower(int number, int N);
void findFlower(int N);int main() {int N;scanf("%d", &N);findFlower(N);return 0;
}// 检查一个数是否为鲜花数
int isFlower(int number, int N) {int originalNumber = number;int sum = 0;while (number > 0) {int digit = number % 10;sum += pow(digit, N);number /= 10;}return sum == originalNumber;
}// 找到并打印所有N位鲜花数
void findFlower(int N) {int lower = pow(10, N - 1);int upper = pow(10, N);for (int i = lower; i < upper; i++) {if (isFlower(i, N)) {printf("%d\n", i);}}
}
这篇关于新形态C语言程序设计游戏化任务教程:第6章17关-20关的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!