Java・プログラミングともに初心者です。
Swingで簡単なボードゲームの盤を作ったことがあるくらいです。(オセロや五目並べのような)
ゲームでよくあるアイテム生産のような仕組みを作りたいのですが、どう考えたらいいのか分かりません。
イメージとしては、冷蔵庫に入っている食材をもとに、レシピ本を見て料理を作るような感じです。
食材…食材クラスのオブジェクト(食材ID(int)、食材名、食材の説明文を持っている)
食材リスト…(食材ID=indexのArrayListの要素に、IDに対応した食材オブジェクトが入っている)
冷蔵庫…食材が入っている。(食材IDをkey、所持数をvalueとしたMapで管理している)
レシピ本…料理に必要な複数の食材とその個数が書いてある。(簡単に考えるため、料理法は考慮に入れない)
レシピ本を見て料理するところのイメージがうまくつかめません。
必要な食材の種類、個数は料理によって違うだろうし、それをどうやって冷蔵庫の在庫と照らし合わせたらいいのか、たくさんのレシピの中から今持っている在庫で作れる料理を検索したりするのもイメージできません。
漠然とした質問で申し訳ないですが、考え方のヒントだけでもいただけると嬉しいです。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答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
総合スコア5568
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総合スコア20651
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
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
総合スコア654
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2015/10/10 12:06