質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

3回答

4837閲覧

[Java]ゲームでよくあるアイテム生産の仕組みが分かりません

amane

総合スコア13

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

1クリップ

投稿2015/10/09 11:46

編集2015/10/09 11:47

Java・プログラミングともに初心者です。
Swingで簡単なボードゲームの盤を作ったことがあるくらいです。(オセロや五目並べのような)

ゲームでよくあるアイテム生産のような仕組みを作りたいのですが、どう考えたらいいのか分かりません。
イメージとしては、冷蔵庫に入っている食材をもとに、レシピ本を見て料理を作るような感じです。

食材…食材クラスのオブジェクト(食材ID(int)、食材名、食材の説明文を持っている)
食材リスト…(食材ID=indexのArrayListの要素に、IDに対応した食材オブジェクトが入っている)
冷蔵庫…食材が入っている。(食材IDをkey、所持数をvalueとしたMapで管理している)
レシピ本…料理に必要な複数の食材とその個数が書いてある。(簡単に考えるため、料理法は考慮に入れない)

レシピ本を見て料理するところのイメージがうまくつかめません。
必要な食材の種類、個数は料理によって違うだろうし、それをどうやって冷蔵庫の在庫と照らし合わせたらいいのか、たくさんのレシピの中から今持っている在庫で作れる料理を検索したりするのもイメージできません。

漠然とした質問で申し訳ないですが、考え方のヒントだけでもいただけると嬉しいです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

冷蔵庫 := Map<食材ID, 所持数>
レシピ := Map<食材ID, 必要数>
レシピ本 := Array<レシピ>

ここまではよろしいですよね。
(ここではJavaではなく、アイディアを疑似言語で書いています。以下も同様。)

冷蔵庫をクラスとして、こんな動きのメソッドを作り付けていきましょうか。

// このレシピを最大何皿作れるか int HowManyCanMakeProductFrom(レシピ) { int result = int.max for ( [食材ID, 必要数] in レシピ) { int div = map.get(食材ID) / 必要数 result = min(result, div); } return result; }

レシピの各食材について必要数の何倍持っているかを判定して、その最小値が最大皿数です。
これが0なら、作れません。
そしたら、レシピ本の料理すべてについて試してみるメソッドが書けます。

// すべての料理について最大何皿作れるかまとめて回答する Map<食材ID, 最大皿数> HowManyCanMakeProductFrom(レシピ本) { Map result; for ([レシピID, レシピ] in レシピ本) result.put(レシピID, HowManyCanMakeProductFrom(レシピ)); return result; }

プレーヤーが作りたいアイテムと個数を選んで実行したときには

bool CreateProduct(レシピ, 個数) { if (HowManyCanMakeProductFrom(レシピ) < 個数) return false; // 材料が足りてません! for ([食材ID, 必要数] in レシピ) { 現在数 = map.get(食材ID); 現在数 -= 必要数 * 個数; map.set(食材ID, 現在数); } return true; // 成功したから、アイテムリストに生成物を加えていいですよ! }

なんてメソッドを呼ぶことになります。

投稿2015/10/09 12:48

yuba

総合スコア5568

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

amane

2015/10/10 12:06

1回分の判定のみならず、レシピ本すべてを試行する仕組みなども書いていただいて、ありがとうございました。 メソッドの中身もシンプルで、まさにこんな風に書きたいと思ったものでした。 教えていただいた内容を参考に、続きを作りたいと思います。
guest

0

「食材」と「食材リスト」の関係のように,「レシピ」とその集合である「レシピ本」という考え方をするべきではないでしょうか.
レシピは料理の名前と,それに必要な食材と必要数の組み合わせを持たせます.これもMapの管理がいいのではないでしょうか.
各レシピで料理が作れるかは,レシピに載っている食材をkeyに冷蔵庫Mapから値を取り出し,数が足りているか判定.すべての食材について足りていれば「作れる」と判定できます.MapからはそのMapが保持している組み合わせを取り出すためのSet<Map.Entry<K, V>>をentrySet()メソッドで取り出して,forループで回せます.
メソッドのイメージとしてはこんな感じ…

java

1boolean canCook(Map<Integer, Integer> recipe, Map<Integer, Integer> stock){ 2 for(Map.Entry<Integer, Integer> e : recipe.entrySet()){ 3 int need = e.getValue(); 4 Integer temp = stock.get(e.getKey()); 5 int have = temp != null ? temp.intValue() : 0; 6 if(need > have) return false; 7 } 8 return true; 9}

本題とは関係ないですが,冷蔵庫にKeyの食材が無かった場合にnullが返ってくるのは何かと面倒なので,get()をオーバーライドしてnullを0のIntegerにする手続きをするといいかもしれません.

java

1Map<Integer, Integer> fridge = new HashMap<Integer, Integer>(){ 2 @Override 3 public Integer get(Object key){ 4 Integer temp = super.get(key); 5 return temp != null ? temp : new Integer(0); 6 } 7};

投稿2015/10/09 12:42

編集2015/10/11 08:13
swordone

総合スコア20651

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

amane

2015/10/10 12:06

ご回答ありがとうございます。 仰るとおり、レシピ本はレシピの集合体ですね。クラスで食材の種類や個数を管理すればいいんですね。 entrySet()を使ってfor文を書くのもとてもすっきりとして分かりやすかったです。
guest

0

こんな感じに実装できます。
食べ物という変数はクラスを使うとうまい具合に実装できますね。

調理するときは、レシピを入れて冷蔵庫にある食べ物で足りるか
どうかを判別するようなメソッドを立てて、
大丈夫なら冷蔵庫の中身を消費、ダメなら冷蔵庫の中身は消費しない。

というような実装が良いと思います。

java

1//食材 2class food{ 3 int foodID; 4 String foodName; 5 String foodDescription; 6 food(int id, String name, String description){ 7 //コンストラクタで値を格納 8 foodID = id; 9 foodName = name; 10 foodDescription = description; 11 } 12} 13 14//食材リスト 15ArrayList<Integer> foodID = new ArrayList<Integer>(); 16ArrayList<food> foodInstance = new ArrayList<food>(); 17foodID.add(0); 18foodInstance.add(new food(0, "トマト", "赤くておいしいトマト。リコピンたっぷり!")); 19foodID.add(1); 20foodInstance.add(new food(1, "きゅうり", "サクサク食感が癖になるきゅうり。あまり栄養は無いらしい。")); 21 22//冷蔵庫 ID, 持ってる数 23HashMap<Integer, Integer> refrage = new HashMap<Integer, Integer>(); 24refrage.put(0,10); 25refrage.put(1,10); 26 27//レシピ本 28//複数のfoodIDと消費数が書いてある。 29ArrayList recipe = new ArrayList(); //Object型で保存 30int[] spendTomato = {0,3}; 31int[] cucumber = {1,2}; 32recipe.add(tomato); 33recipe.add(cucumber); 34 35//作る時 36boolean makeDish(recipe){ 37 //冷蔵庫の中にレシピの数だけ食材があるかどうか確認する。 38 //冷蔵庫の中はクラス変数として扱ってる前提 39 boolean isSuccess = false; 40 for(int i=0; i<recipe.size(); i++){ 41 int[] recipeElement = (int[]) recipe.get(i); //id,数の順 42 HashMap<Integer, Integer> refrageCopy = refrage.clone(); //配列系は参照代入なのでシャローコピーを作成 43 if(refrageCopy.get(recipeElement[0]) >= recipeElement[1]){ 44 //例えば、IDが0だとしたら、 refrage.get(recipeElement[0]) は、 トマトの数を示します。 45 //recipeElement[1] も、トマトの数を示します。 46 //leftAmount は、 冷蔵庫の中身から、レシピの数だけ値を引いたものです。(残り) 47 int leftAmount = refrageCopy.get(recipeElement[0]) - recipeElement[1]; 48 refrageCopy.put(recipeElement[0], leftAmount) 49 } else { 50 //どっかで足りない数があったら、ここまでの操作を取り消します。 51 refrage = refrageCopy; 52 } 53 if(i == recipe.size()-1){ 54 //レシピ全部の調理ができたら、Copyに操作していた処理を本物に移し替えます。 55 refrage = refrageCopy; 56 //で、調理成功フラグを呼び出し元に返します。 57 isSuccess = true; 58 } 59 } 60 return isSuccess; 61} 62 63//呼び出す時 64if (makeDish(recipe)){ 65 System.out.println("もぐもぐ。トマトキューリはおいしいなぁ"); 66} else { 67 System.out.println("冷蔵庫に食材が足りなくて料理ができなかった・・"); 68}

それと、よくある失敗例として新しく宣言した配列やMapの変数に既存の配列を
代入したりすると、参照代入となってしまいます。

参照代入した変数に値を入れると、元の配列も一緒に変更されてしまうので、
(入れる場所が2箇所になった。みたいな感覚です。)
clone()メソッドを使ってシャローコピーを作ってあげるとちゃんとコピーが作れます。

データストラクチャーは上手に考えられているので、
ロジックは書けばなれますよ。

という感じです。

参考:
クラス ArrayList<E>
https://docs.oracle.com/javase/jp/6/api/java/util/ArrayList.html
要素の格納と取り出し
http://www.javadrive.jp/start/hashmap/index2.html

投稿2015/10/09 12:33

SKYYFISH

総合スコア654

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

amane

2015/10/10 12:05

最初から最後まで、詳しくありがとうございました。 Mapのコピーを作っておいて、とりあえずそちらで処理をした後、全部の数が足りていたら本物に移し替えるというのは考えていなかったので、とても参考になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問