今回は受講生(T氏)作成のお題を掘り下げていこう。
題材は名前を入力すると能力値パラメーターを作成してくれる自己紹介アプリだ。
以下は実行例
実行例
名前を入力してください>山田花子 初期ステータスが決定しました [体力:75 魔力:82 パワー:29 きようさ:22 すばやさ:25 ] 種族を選んでください 0…人間,1…ハイエルフ,2…トロル,3…ノーム>3 ノームのボーナスが適用されました! [体力:85 魔力:82 パワー:29 きようさ:47 すばやさ:45 ] 職業を選んでください 0…戦士,1…盗賊,2…僧侶,3…魔術師>0 戦士のボーナスが適用されました! [体力:136 魔力:82 パワー:40 きようさ:47 すばやさ:45 ] ***作成成功!*** 私は戦士のノーム、山田花子です。 能力値(350)を高い順に並べると 体力:136 魔力:82 きようさ:47 すばやさ:45 パワー:40 です。今後ともよろしく…。
なかなか面白いアプリで、配列やメソッドの学習にもピッタリだ。
今回は乱数にシードを設定して同じ名前は常に同じ初期ステータスが設定されるようにしてみよう。
仕様
○名前を入力すると初期ステータスが決まる。ステータスの種類は以下
{"体力","魔力","パワー","きようさ","すばやさ"}
○各初期ステータスの下限、上限は以下
体力,魔力(1~100) パワー,きようさ,すばやさ(1~50)
○種族を入力すると種族ボーナスが加算される。加算される値は以下
種族 | 体力 | 魔力 | パワー | きようさ | すばやさ |
---|---|---|---|---|---|
人間 | +10 | +10 | +10 | +10 | +10 |
ハイエルフ | 0 | +20 | 0 | +10 | +20 |
トロル | +30 | 0 | +20 | 0 | 0 |
ノーム | +10 | 0 | 0 | +25 | +20 |
○職業を入力すると職業ボーナスが乗算される。乗算される値は以下
職業 | 体力 | 魔力 | パワー | きようさ | すばやさ |
---|---|---|---|---|---|
戦士 | 1.6倍 | 1 | 1.4倍 | 1 | 1 |
盗賊 | 1.1倍 | 1 | 1.2倍 | 1.3倍 | 1.3倍 |
僧侶 | 1.3倍 | 1.5倍 | 1.1倍 | 1 | 1 |
魔術師 | 1 | 1.9倍 | 1 | 1 | 1.1倍 |
作成
まずはいつものようにこのアプリに必要なメソッドを作っていこう。
名前をもとにシード値を作成するメソッド
static int calcSeed(String name){
int seed=0;
for(int i=0;i<name.length();i++){
seed+=name.charAt(i);
}
return seed;
}
シード値というのは乱数生成の際に設定すると生成される値を固定できるものだ。
今回の例に当てはめると同じ名前に対しては同じ初期ステータスを設定することができるようになる。
上記メソッドの内容はユーザーから入力してもらった値を一文字ずつ分解して、加算していくものだ。Javaのchar型はint としての性質も持っているのでこうすると名前に応じたintの値を生成してくれる。
これをシード値にすればよいだろう。
シード値をもとに指定範囲の配列を作成するメソッド
static int[] makeStatus(int seed,int[] maxArr){
int[] vals=new int[maxArr.length];
Random rand=new Random(seed);
for(int i=0;i<vals.length;i++){
vals[i]=rand.nextInt(maxArr[i])+1;
}
return vals;
}
名前を元に生成したseedをもとにして初期パラメーターを生成していこう。
第2引数には{100,100,50,50,50}という各パラメータの上限値が配列で渡されることになる。
Randomインスタンス生成の際にseedを設定しているのでこれで同一の名前に対しては毎回同じステータスを生成することが可能になる。nextIntに上限値が渡されることでそれぞれの範囲が仕様にあるように
[1~100,1~100,1~50,1~50,1~50]
となることも確認しておくこと。
実行例を見ると山田花子という名前の場合
[体力:75 魔力:82 パワー:29 きようさ:22 すばやさ:25 ]
という配列が返却されるようだ。なかなかバランスの良いステータスだ。
種別ボーナスを加算するメソッド
static void raceBonus(int[] status,int[] bonus){
for(int i=0;i<status.length;i++){
status[i]+=bonus[i];
}
}
第1引数に初期パラメータの入った配列を第2引数に種別にあわせた配列、例えばノームだったら{10,0,0,25,20}が渡されることになる。
初期パラメーターにこの値をそれぞれ加えていく処理は難しくないだろう。
参照値渡しなので戻り値は設定しなくていいことも確認しておこう。
[75,82,29,22,25 ]
だった初期パラメーターに
[10,0,0,25,20]
が加算されて、パラメーターは
[85,82,29,47,45]
になっていることが実行例からもわかる。
職業によってパラメーターを乗算させるメソッド
static void classBonus(int[] status,double[] ratio){
for(int i=0;i<status.length;i++){
status[i]=(int)(status[i]*ratio[i]);
}
}
考え方は先程と同じだが、今回第2引数で渡されるのはdouble配列なので乗算を行った後、intでキャストすることを忘れてはいけない。
パラメーターの合計を返却するメソッド
static int sumStatus(int[] status){
int sum=0;
for(int n:status){
sum+=n;
}
return sum;
}
int型配列に入っている要素の合計を求めるとてもシンプルなメソッドだ。
ここまで読み進められているあなたならここは全く問題ないはずだ。
能力値を降順に並び替えるメソッド
static void sortStatus(int[] status,String[] params){
for(int i=0;i<status.length-1;i++){
for(int j=i+1;j<status.length;j++){
if(status[i]<status[j]){
int t1=status[i];
status[i]=status[j];
status[j]=t1;
String t2=params[i];
params[i]=params[j];
params[j]=t2;
}
}
}
}
実行例を見ると、最後にパラメータの大きい順に表示をしている。
配列をソートしていこう。
今回は単純ソートのアルゴリズムでソートを行っている。
その際に{”体力”,”魔力”…}とパラメーター名の配列も一緒に並び替えているのがポイントだ。
配列をつなぎ合わせて表示するメソッド
static void showStatus(int[] status,String[] params){
String str="";
for(int i=0;i<status.length;i++){
str += params[i] + ":" + status[i] +" ";
}
System.out.println("["+str+"]");
}
[体力:75 魔力:82 パワー:29 きようさ:22 すばやさ:25 ]
こういった形式での出力が度々されている。
パラメータ名とパラメータを文字列連結して出力する処理を作成しておいたほうがよいだろう。
処理内容自体はとくに難しいところはないはずだ。
メインメソッドの作成
アプリ作成に必要な主要な処理はメソッドとして作ることができた。あとは実行例を見ながらメインメソッドを作成していこう。
import java.util.*;
public class SelfIntroduction{
public static void main(String[] args){
String[] params={"体力","魔力","パワー","きようさ","すばやさ"};
String[] races={"人間","ハイエルフ","トロル","ノーム"};
String[] classes={"戦士","盗賊","僧侶","魔術師"};
int[][] raceMatrix={
{10,10,10,10,10},
{0,20,0,10,20},
{30,0,20,0,0},
{10,0,0,25,20},
};
double[][] classMatrix={
{1.6,1,1.4,1,1},
{1.1,1,1.2,1.3,1.3},
{1.3,1.5,1.1,1,1},
{1,1.9,1,1,1.1},
};
Scanner sc=new Scanner(System.in);
System.out.print("名前を入力してください>");
String name=sc.nextLine();
int seed=calcSeed(name);
int[] status=makeStatus(seed,new int[]{100,100,50,50,50});
System.out.println("初期ステータスが決定しました");
showStatus(status,params);
System.out.print("種族を選んでください 0...人間,1...ハイエルフ,2...トロル,3...ノーム>");
int race=sc.nextInt();
System.out.println(races[race]+"のボーナスが適用されました!");
raceBonus(status,raceMatrix[race]);
showStatus(status,params);
System.out.print("職業を選んでください 0...戦士,1...盗賊,2...僧侶,3...魔術師>");
int cls=sc.nextInt();
System.out.println(classes[cls]+"のボーナスが適用されました!");
classBonus(status,classMatrix[cls]);
showStatus(status,params);
System.out.println("***作成成功!***");
System.out.printf("私は%sの%s、%sです。%n",classes[cls],races[race],name);
System.out.println("能力値("+sumStatus(status)+")を高い順に並べると");
sortStatus(status,params);
for(int i=0;i<status.length;i++){
System.out.printf("%s:%d%n",params[i],status[i]);
}
System.out.println("です。今後ともよろしく...。");
}
static int calcSeed(String name){
int seed=0;
for(int i=0;i<name.length();i++){
seed+=name.charAt(i);
}
return seed;
}
static int[] makeStatus(int seed,int[] maxArr){
int[] vals=new int[maxArr.length];
Random rand=new Random(seed);
for(int i=0;i<vals.length;i++){
vals[i]=rand.nextInt(maxArr[i])+1;
}
return vals;
}
static void raceBonus(int[] status,int[] bonus){
for(int i=0;i<status.length;i++){
status[i]+=bonus[i];
}
}
static void classBonus(int[] status,double[] ratio){
for(int i=0;i<status.length;i++){
status[i]=(int)(status[i]*ratio[i]);
}
}
static int sumStatus(int[] status){
int sum=0;
for(int n:status){
sum+=n;
}
return sum;
}
static void sortStatus(int[] status,String[] params){
for(int i=0;i<status.length-1;i++){
for(int j=i+1;j<status.length;j++){
if(status[i]<status[j]){
int t1=status[i];
status[i]=status[j];
status[j]=t1;
String t2=params[i];
params[i]=params[j];
params[j]=t2;
}
}
}
}
static void showStatus(int[] status,String[] params){
String str="";
for(int i=0;i<status.length;i++){
str += params[i] + ":" + status[i] +" ";
}
System.out.println("["+str+"]");
}
}
今回のポイントは各ボーナスデータを2次元配列で扱っているところだ。
このようにしておけばもし種族としてハイエルフが選択されたなら
raceMatrix[3] //->{20,0,0,25,20}
とすることでノームの補正値を1次元配列で取り出すことができる。
アプリ制作では非常によく出てくるテクニックなので覚えておくとよいだろう。
終わりに
今回のこの内容が理解できてコーディングできれば配列とメソッドの理解は大丈夫といってよいだろう。
余談だが、このアプリをリアルネームでやってみたところ以下の結果となった
***作成成功!***
私は僧侶のノーム、XXXXです。
能力値(304)を高い順に並べると
魔力:123
体力:70
きようさ:51
パワー:30
すばやさ:30
です。今後ともよろしく...。
ステータスを極振りせずに使いやすい回復役を目指してみた。
さて、あなたは使えるキャラになっただろうか?
コメント