トランプ52枚を使ったゲームを作りたい。とのことですが52は数は多く私には難易度が高いため12枚にします。
プログラム全体はまだかけていませんが部分的なプログラムは何とか考えられています。
12枚のカード(すべてハート)なので
1人に配る場合余りなし
2人に配る場合余りなし
3人に配る場合余りなし
4人に配る場合余りなし
5人に配る場合あまり2枚になります。
そこで2枚の余りを5人にどう配るかで考えています。5人の内の1人に2枚配る場合と、5人の内の2人に一枚ずつ配る場合の二つがあります。
余りが2と言ところまでは作れました。問題はこの余り2を5人にどう渡すかです。
#include<stdio.h> int main() { int hito ; hito=5; int card ; card=12; printf("%d\n",card/hito); }
改良後がこちらです。A,B,C,D,Eの5人の手札と余りを表示するソースです。
#include<stdio.h> int main() { int hito; hito=5; int a; a=1; int b; b=1; int c; c=1; int d; d=1; int e; e=1; int A; int B; int C; int D; int E; int card ; card=12; A=card%(a+b+c+d+e); B=card%(a+b+c+d+e); C=card%(a+b+c+d+e); D=card%(a+b+c+d+e); E=card%(a+b+c+d+e); printf("Aのカードの枚数は%d\n",A); printf("Bのカードの枚数は%d\n",B); printf("Cのカードの枚数は%d\n",C); printf("Dのカードの枚数は%d\n",D); printf("Eのカードの枚数は%d\n",E); printf("カードの余りは%d\n",card/hito);
そのあと変数Aに余りの1か2のいずれかを加算させた際のプログラムを作りました。
変数Aに1か2が加算され、1の場合は1が余るので、その1がA以外のB~Dに入ります。
そこでランダム関数を使ってプログラムを書きました。途中までしかできなかったかというか詰まってしまい途中まで書いたようなプログラムになってしまいました。途中までではありますが実行は出来ます。しかし間違った結果が出ます。
もっとスマートに読みやすいように書くにはどうしたらよりでしょうか?
やはりif文などの分岐を使って長いコードを書くのでしょうか?
アドバイスと間違いを指摘していただければと思います。
またわがままながらできる限りプログラムの原型をとどめた状態で編集していただけると大変ありがたいです。どうかよろしくお願いいたします。
書いたソースはこちらです。
#include<stdio.h> #include <stdlib.h> #include <time.h> int main() { int hito; hito=5; int a; a=1; int b; b=1; int c; c=1; int d; d=1; int e; e=1; int A; int B; int C; int D; int E; int card ; card=12; A=card%(a+b+c+d+e); B=card%(a+b+c+d+e); C=card%(a+b+c+d+e); D=card%(a+b+c+d+e); E=card%(a+b+c+d+e); printf("Aのカードの枚数は%d\n",A); printf("Bのカードの枚数は%d\n",B); printf("Cのカードの枚数は%d\n",C); printf("Dのカードの枚数は%d\n",D); printf("Eのカードの枚数は%d\n",E); printf("カードの余りは%d\n",card/hito); srand(time(NULL)); int amari; amari = rand() % 2 + 1; printf("Aのカードの枚数は余りを足されて%d\n", A+amari); int x; amari-1; x=amari-1; printf("Bのカードの枚数は余りを足されて%d\n", B+x); return 0; }
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/04/25 13:39

回答10件
0
たぶん普通にトランプのカードを配る処理を作りたいだけなんだと思いますが、アルゴリズムの立て方がまずいので非常にややこしい話になっているのでしょう。
- カードをシャフルする。
- カードに1から順番に番号を振る。
- カードの順番を人数で整数除算して、余りを求める。
- 余りの数字がすなわちそのカードを手にするべき人の番号。
こういうことではないのでしょうか。ifとか出番はないんじゃないかと思いますね。
にっちもさっちもいかなくなったときは、思い切って方針を最初から考え直すことも大切だと思います。
投稿2018/04/25 13:49
総合スコア13727
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
A: 4, B: 2, C: 2, D:2, E: 2
でゲーム開始させられる可能性のあるAさんは親みたいなロールなのでしょうか?
問題点
配列
カードゲームのような
同列に扱っていい要素(プレイヤー,山札,手札)がたくさん出る場合
配列の知識が必須です。
逆に配列さえ理解していれば12枚だろうが52枚だろうが大差ありません。
アルゴリズム
それぞれに配る枚数を計算し、生成してまわる事も不可能ではありませんが
その場合、重複に気をつけなければいけません。
そして、重複をどうにかしようとすると結局山札として生成した後にシャッフルするのが楽になります。
というわけで、人の手でやるのと同様に
山札を用意して、シャッフルして、1枚ずつ配っていくのが楽です。
手札の枚数が分からんと手札領域を作れないというのなら、単純に**(山札枚数+人数-1)/人数**
で全員に最大1枚の余剰札が来ても大丈夫にしておいても実用上問題はないでしょう。
投稿2018/04/26 10:03
総合スコア15149
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
シャッフルしたカードを、n人のプレイヤーにすべて配るプログラムを書きたいです。
ごめんなさい先に書いちゃいました。
C++
1#include <iostream> 2#include <string> 3#include <array> 4#include <vector> 5#include <algorithm> 6#include <numeric> 7#include <random> 8 9std::string to_card(int n) { 10 static const std::string suit = "SHDC"; 11 static const std::string rank = "A23456789TJQK"; 12 return std::string(1,suit[n/13])+rank[n%13]; 13} 14 15int main() { 16 using namespace std; 17 18 // 52枚のcardからなるdeck 19 array<int,52> deck; 20 // card #0 ~ #51で埋める 21 iota(deck.begin(), deck.end(), 0); 22 // deckをシャッフル 23 shuffle(deck.begin(), deck.end(), mt19937(random_device()())); 24 25 // N人のplayer 26 const int N = 5; 27 vector<int> players[N]; 28 29 // deck内の各cardを playerに配る 30 int c = 0; 31 for ( int card : deck ) { 32 players[c].push_back(card); 33 if ( ++c == N ) c = 0; 34 } 35 36 // 各playerの手札を公開 37 for ( auto& hand : players ) { 38 cout << hand.size() << " cards: "; 39 for ( int id : hand ) { 40 cout << to_card(id) << ' '; 41 } 42 cout << endl; 43 } 44} 45 46/* 実行結果 4711 cards: C5 C8 H8 CQ C4 HA D8 C6 CA D2 S6 4811 cards: HK S5 S4 H7 S7 HT D9 S9 D4 H4 S8 4910 cards: S3 H2 CJ D6 DK H6 CT D3 H9 D5 5010 cards: HJ SA D7 DA C2 SJ HQ DJ CK H3 5110 cards: C7 S2 DT ST SQ C9 H5 DQ C3 SK 52*/
[追記] こっちの方がイケてるかな。
C++
1#include <iostream> // cout, endl 2#include <string> // string 3#include <vector> // vector 4#include <algorithm> // sort 5#include <numeric> // iota 6#include <random> // mt19937, random_device 7#include <utility> // pair, make_pair 8#include <cassert> // assert 9 10class card { 11private: 12 int id_; 13 explicit card(int id) : id_(id) { 14 assert( id >= 0 && id < 52 ); 15 } 16 17public: 18 card() = delete; 19 int suit() const { return id_ % 4; } 20 int rank() const { return id_ / 4; } 21 std::string suit_str() const { return std::string(1,"CDHS"[suit()]); } 22 std::string rank_str() const { return std::string(1,"A23456789TJQK"[rank()]); } 23 std::string str() const { return suit_str() + rank_str(); } 24 25 static card make(int id) { return card(id); } 26}; 27 28inline bool operator<(const card& a, const card& b) { 29 return std::make_pair(a.rank(),a.suit()) < std::make_pair(b.rank(),b.suit()); 30} 31 32inline std::ostream& operator<<(std::ostream& stream, const card& c) { 33 return stream << c.str(); 34} 35 36int main() { 37 using namespace std; 38 39 // N人のplayer 40 const int N = 5; 41 vector<vector<card>> players(N); 42 43 // 52枚のcardからなるdeck 44 vector<card> deck; 45 for ( int id = 0; id < 52; ++id ) { 46 deck.emplace_back(card::make(id)); 47 } 48 // deckをシャッフル 49 shuffle(deck.begin(), deck.end(), mt19937(random_device()())); 50 51 // deckが空になるまで、cardを各playerに配る 52 for ( int c = 0; !deck.empty(); ++c %= N ) { 53 players[c].emplace_back(deck.back()); 54 deck.pop_back(); 55 } 56 57 // 各playerに対し 58 for ( vector<card>& hand : players ) { 59 // 手札を(ソートして)公開 60 cout << hand.size() << " cards: "; 61 sort(hand.begin(), hand.end()); 62 for ( const card& c : hand ) { 63 cout << c << ' '; 64 } 65 cout << endl; 66 } 67}
投稿2018/04/26 10:01
編集2018/04/27 10:01総合スコア16612
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/04/27 04:40

0
最初のコードでいきなり間違えています。
余りが2と言ところまでは作れました。
c
1printf("%d\n",card/hito);
card / hito
で求められるのは一人あたりの配った枚数です。
余りを求めたいならcard % hito
が正解です。
今回、たまたま両方とも2
だったので気付かなかったのでしょうか?
カードを10枚とか11枚にしてみれば間違いに気が付くと思います。
投稿2018/04/26 00:46
総合スコア16733
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/04/26 23:09

0
可能な限り原型を残しました。
C
1#include <stdio.h> 2#include <stdlib.h> 3 4#define hito 5 5#define card 52 6 7char getName(int i) 8{ 9 return 'A' + i; 10} 11 12void swapInt(int *buffer, int a, int b) 13{ 14 int t = buffer[a]; 15 buffer[a] = buffer[b]; 16 buffer[b] = t; 17} 18 19void shuffleInt(int *buffer, int size) 20{ 21 srand(time(NULL)); 22 for (int i = 0; i < size; i++) 23 { 24 swapInt(buffer, i, rand() % size); 25 } 26} 27 28void dealRemainder(int remainders[], int size, int remainder) 29{ 30 for (int i = 0; i < size; i++) 31 { 32 remainders[i] = i < remainder ? 1 : 0; 33 } 34 shuffleInt(remainders, size); 35} 36 37int main() 38{ 39 int hands[hito]; 40 for (int i = 0; i < hito; i++) 41 { 42 hands[i] = card / hito; 43 printf("%cのカードの枚数は%d\n", getName(i), hands[i]); 44 } 45 int remainder = card % hito; 46 printf("カードの余りは%d\n", remainder); 47 int remainders[hito]; 48 dealRemainder(remainders, hito, remainder); 49 for (int i = 0; i < hito; i++) 50 { 51 if (remainders[i] == 0) 52 continue; 53 printf("%cのカードの枚数は余りを入れて%d\n", getName(i), hands[i] + remainders[i]); 54 } 55 return 0; 56}
投稿2018/04/25 14:44
総合スコア28673
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
実際にカードを配るときのことを考えてください。自分を含めた5人で配ることを考えましょうか。
親(カードを配る人)が、自分、子1、子2、子3、子4 の順に、1枚ずつ配っていきませんか?
つまり、
- 渡す人の配列 player[5] を作る。とりあえず、player[0]は自分自身、以下[1]が子1、[2]が子2…とする
- n枚のカードをシャッフルして、配列 card[n] に並べる
- card[x] (ただし x は 0 ~ n-1 までのループを行う)を、
x を5で割ったあまり(x % 5) の番号の人に渡す
ということをやっているのです。
この手順(アルゴリズム)さえ理解できれば、それをプログラミング言語で書き直すだけです。
投稿2018/04/26 01:36
総合スコア13707
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
ベストアンサー
なるべく質問者さんの意図に沿ったもののつもり
c
1#include <stdio.h> 2#include <stdbool.h> 3#include <stdint.h> 4#include <stdlib.h> 5#include <time.h> 6 7void swap(int8_t *b1, int8_t *b2){ 8 if(b1 == b2) return; 9 int8_t tmp = *b1; 10 *b1 = *b2; 11 *b2 = tmp; 12} 13 14// バイト単位でシャッフル 15void shuffle(int8_t *buf, size_t size){ 16 for(;size > 1;){ 17 int pos = rand() % size; 18 size--; 19 swap(buf+size, buf+pos); 20 } 21} 22// C言語にもconstexprください 23#define TRUMP_SUIT 4 24#define TRUMP_JOKER_ENABLE 0 25#define TRUMP_JOKER_AMOUNT 1 26#define TRUMP_MAX_RANK 13 27#define TRUMP_SUIT_OFFSET 6 28#define TRUMP_RANK_MASK 63 29const int TRUMPS = TRUMP_SUIT * TRUMP_MAX_RANK + TRUMP_JOKER_ENABLE * TRUMP_JOKER_AMOUNT; 30typedef uint8_t CARD; 31// xxyyyyyy 32// xx : suit 33// yyyyyy: rank(0 は joker) 34const char* SUIT_DISPLAY[] = { 35 "♤","♥","♣","♦" 36}; 37const char* RANK_DISPLAY[] ={ 38 "JK", 39 "A","2", "3", "4", "5", "6", "7", 40 "8","9","10", "J", "Q", "K" 41}; 42#define PLAYERS 5 43 44bool deck_build(CARD* deck, size_t size){ 45 if(size < TRUMPS) return false; 46 int i = 0; 47 for(int j = 0; j < TRUMP_SUIT; j++) 48 for(int k = 1; k <= TRUMP_MAX_RANK; k++) 49 deck[i++] = (j << TRUMP_SUIT_OFFSET) | k; 50 // ジョーカーの挿入 51 for(int j = 0; j < TRUMP_JOKER_AMOUNT; j++) 52 deck[i++] = (j << TRUMP_SUIT_OFFSET); 53 return true; 54} 55void display_cards(CARD* cards, size_t size){ 56 for(int i = 0; i < size; i++){ 57 int suit = cards[i] >> TRUMP_SUIT_OFFSET; 58 int rank = cards[i] & TRUMP_RANK_MASK; 59 if(rank == 0){ 60 printf(" %s", RANK_DISPLAY[rank]); 61 continue; 62 } 63 printf(" %s%s", SUIT_DISPLAY[suit],RANK_DISPLAY[rank]); 64 } 65 puts(""); 66} 67int main(){ 68 srand(time(NULL)); 69 CARD deck[TRUMPS]; 70 deck_build(deck, TRUMPS); 71 shuffle(deck, TRUMPS); 72 display_cards(deck, TRUMPS); 73 74 CARD* player_hand[PLAYERS]; 75 int player_hand_size[PLAYERS]={0}; 76 // プレイヤーの並び順 77 // めんどくさいからバイトシャッフル使うためにint8_t型 78 // 真面目にやる時はint型のshuffle関数を作る 79 int8_t player_order[PLAYERS]; 80 for(int8_t i = 0; i < PLAYERS;i++) player_order[i] = i; 81 shuffle(player_order, PLAYERS); 82 83 // それぞれの手札の枚数を求める 84 for(int i = 0, amari = TRUMPS % PLAYERS; i < PLAYERS; i++){ 85 player_hand_size[i] = TRUMPS / PLAYERS; 86 if(amari > player_order[i]) 87 player_hand_size[i]++; 88 printf("%c hand size = %d\n", 'A' + i, player_hand_size[i]); 89 } 90 91 // 配る 92 CARD *current = deck; 93 for(int i = 0; i < PLAYERS; i++){ 94 player_hand[i] = current; 95 current += player_hand_size[i]; 96 } 97 98 // 表示 99 for(int i = 0; i < PLAYERS; i++){ 100 printf("%c hand:", 'A' + i); 101 display_cards(player_hand[i],player_hand_size[i]); 102 } 103}
出力 =>
A hand size = 10 B hand size = 11 C hand size = 10 D hand size = 10 E hand size = 11 A hand: ♤Q ♤3 ♥2 ♥3 ♥K ♥5 ♤10 ♥9 ♣6 ♦10 B hand: ♦K ♥A ♥6 ♤4 ♦7 ♣J ♦3 ♣3 ♤J ♣5 ♦Q C hand: ♤K ♤2 ♦9 ♦4 ♦5 ♣7 ♣K ♥J ♣Q ♣9 D hand: ♦6 ♦J ♤A ♣10 ♥Q ♣2 ♤9 ♤7 ♥4 ♥7 E hand: ♣8 ♥8 ♤8 ♦A ♣A ♦2 ♥10 ♣4 ♤6 ♤5 ♦8
ラムダ式とconstexprがCにも欲しいですね
投稿2018/04/28 04:54
編集2018/04/28 08:29総合スコア15149
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/04/28 06:59
2018/04/28 07:37

0
人と機械
目的が次のどちらなのか、をはっきりさせた方が良いと思います。
- 「人」がトランプを配る(動作を模倣する)プログラムを作りたい
- 「機械」がトランプを配るプログラムを作りたい
「人」と「機械」では配り方(アルゴリズム)が異なります。
スネ夫
C言語で作りたい、とのことですが、私には難易度が高い為、JavaScriptにします。
JavaScript
1'use strict'; 2function suneo (total, players, unit) { 3 const hands = Array(players).fill(0); 4 5 play: { 6 while (total) { 7 for (let i of hands.keys()) { 8 if (total <= unit) { 9 hands[i] += total; 10 break play; 11 } 12 13 total -= unit; 14 hands[i] += unit; 15 } 16 } 17 } 18 19 const length = hands.filter(hand => hand > 0).length; 20 21 if (length !== players) { 22 console.log('悪いな、のび太。このゲームは' + length + '人用なんだ。'); 23 } 24 25 return JSON.stringify(hands); // debug code 26} 27 28console.log(suneo(12, 5, 1)); 29console.log(suneo(12, 5, 2)); 30console.log(suneo(12, 5, 4));
スネ夫は優しくないので、余剰分も規定通りの枚数で配ります。
しずかちゃんなら公平に近い配り方をするでしょう。
あなたは誰派ですか。
Re: carnage0216 さん
投稿2018/04/25 15:05
総合スコア18194
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
C
1int amari; 2 amari = card%hito - rand() % 2; 3 printf("Aのカードの枚数は余りを足されて%d\n", A+amari); 4int x; 5x=card%hito - amari; 6printf("Bのカードの枚数は余りを足されて%d\n", B+x);
投稿2018/04/25 15:19
編集2018/04/26 01:09総合スコア514
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
自然に考えれば余った2枚は二人に一枚づつ配るのが適切だと思います。
この場合、カード枚数が52枚と決まっているので先に配列を用意しておくと良いです。この配列をシャッフルして一枚ずつplayerに配布するとかすれば確実です。余った二枚をどうするかという本題についてですが、これはダミーを使うという方法があります。最後に余った2枚に加えて無効カードを3枚用意して1枚ずつ配布し、これを無効分を除外するといった考え方です。
投稿2018/04/27 15:51
総合スコア4853
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。