B-Teck!

お仕事からゲームまで幅広く

【Java】文字列の空白埋め、0埋め

String.formatで桁数を揃えたあとreplaceで空白を任意の文字に置き換えることで、0埋めができる。

   public static void main (String[] args) throws java.lang.Exception {
    
        System.out.println(zeroPadding("12345",10));    // 0000012345
        System.out.println(blankPadding("t e s t",10)); // t e s t
        
        // 先頭の文字列以外の空白も置換してしまうので、
        // 0埋めは空白を含む文字列には使えない
        System.out.println(zeroPadding("t e s t",10));  // 000t0e0s0t
    }
    
    /**
    *  lengthで指定した桁数まで空白埋めした文字列を返却する
    *   @param  input  入力文字列
    *   @param  length 空白埋めする桁数
    *   @return   length分まで空文字を付加したinput
    */
    public static String blankPadding(String input, int length){
        return String.format("%" + length + "s", input);
    }
    /**
    *  lengthで指定した桁数までゼロ埋めした文字列を返却する
    *   @param  input  入力文字列
    *   @param  length ゼロ埋めする桁数
    *   @return   length分まで0を付加したinput
    */
    public static String zeroPadding(String input, int length){
        return String.format("%" + length + "s", input).replace(" ", "0");
    }

もし先頭以外に空白が入りうる文字列を0埋めする場合、
先に必要な文字数分作ってからつなげて返すのが良さそう。

   /**
    *  lengthで指定した桁数までゼロ埋めした文字列を返却する
    *  与えられた文字列よりlengthが短い場合、そのまま返却する
    *   @param  input  入力文字列
    *   @param  length ゼロ埋めする桁数
    *   @return   length分まで0を付加したinput
    */
    public static String zeroPadding(String input, int length){
        int l = length - input.length();
        if (l > 0){
            String pad = String.format("%" + l + "s", "")
                               .replace(" ", "0");
            return pad + input;
        }else{
            return input;
        }
    }

行頭に付加した0を除去する場合は下記で

    public static String zeroSuppress(String input){
        return input.replaceAll("^0{1,}", "");
    }

【JavaScript】JSの配列操作まとめ

配列の操作

配列の作成

// 空の配列を作成
var hoge = [];                
// 値をもった配列を作成
var hoge = [1, 2, 3];      
// 長さ10で値が未定義の配列を作成
var hoge = new Array(10); 

配列の初期化

配列の変数に空の配列を代入するか、長さを0にすることで配列自体の初期化が行える。

// 空の配列を代入する場合
var hoge = [1, 2, 3];
hoge = [];
console.log(hoge);

// 配列の長さを0にする場合
hoge = [1, 2, 3];
hoge.length = 0;
console.log(hoge);

ちなみに、配列の長さを0ではない数に変更した場合は下記のようになる。

// 配列の長さを短くする場合
// 指定した要素数を残して削除される
var hoge = [1, 2, 3];
hoge.length = 1;
console.log(hoge);


// 配列の長さを長くする場合
// 未定義の要素が生成される
hoge = [1, 2, 3];
hoge.length = 5;
console.log(hoge);

配列の要素数を取得

var hoge = [1, 2, 3];
// 3と出力される
console.log(hoge.length);

配列の最初と最後を取得

var hoge = [1, 2, 3];
// 最初
console.log(hoge[0]);
// 最後
// 配列の長さは要素の個数だけど添字は0から始まるので
// 要素数から1を引くと最後の要素の添字になる
console.log(hoge[hoge.length - 1]);  

配列の要素を指定位置で切り出す

var hoge = [1, 2, 3];
// sliceは2個目の引数の添字を含まずに切り出す
// 下記のような場合は0番目の要素から添字が1のものまで
console.log(hoge.slice(0, 2));
// 下記のような場合は1番目の要素から添字が2のものまで
console.log(hoge.slice(1, 3));

配列のループ

for of または foreachを使うのがベター?

  • for
var fruits = ["りんご", "バナナ"];
for(let i = 0; i < fruits.length; i++) {
    console.log(fruits[i])
}
  • foreach
var fruits = ["りんご", "バナナ"];
fruits.forEach(function (item, index, array) {
    console.log(item, index);
});
  • for in
    for inはprototypeで設定されたプロパティも参照してしまうので、hasOwnPropertyを使わないと予期しないデータが混ざる場合がある。
var fruits = ["りんご", "バナナ"];
for (var key in fruits) {
    if (fruits.hasOwnProperty(key)){
        console.log(key + ' is property of fruits!');
    }
}
  • for of
var fruits = ["りんご", "バナナ"];
// 値を取り出す
for(let v of fruits) {
    console.log(v);
}
// キーを取り出す
for(let k of Object.keys(fruits)) {
    console.log(k);
}
// キーと値を取り出す
for(let k of Object.keys(fruits)) {
    console.log(k);
    console.log(fruits[k]);
}

配列の先頭に要素を追加する

var fruits = ["りんご", "バナナ"];
fruits.unshift("いちご");
console.log(fruits); 

配列の末尾に要素を追加する

var fruits = ["りんご", "バナナ"];
fruits.push("みかん");
console.log(fruits); 

配列の値を削除する

delete演算子は、削除したインデックスを詰めないので注意。

var fruits = ["いちご","りんご", "バナナ", "みかん"];
delete fruits[2];
// Array [ "いちご", "りんご", <1 empty slot>, "みかん" ]のような形になる
console.log(fruits);

配列の先頭の要素を取り出して元の配列から削除する

var fruits = ["りんご", "バナナ"];
// shiftの戻り値は削除した値なので、"りんご"が出力される
console.log(fruits.shift());
console.log(fruits);

配列の末尾の要素を取り出して元の配列から削除する

var fruits = ["りんご", "バナナ"];
// popの戻り値は削除した値なので、"バナナ"が出力される
console.log(fruits.pop());
console.log(fruits);

指定した要素に最初に合致した要素のインデックスを返す

var fruits = ["りんご", "バナナ", "りんご","りんご","バナナ"];
// 1と出力される
console.log(fruits.indexOf("バナナ"));

指定した要素に最後に合致した要素のインデックスを返す

var fruits = ["りんご", "バナナ", "りんご","りんご","バナナ"];
// 4と出力される
console.log(fruits.lastIndexOf("バナナ"));

インデックス位置を指定して要素を取り出し、元の配列から削除する

取り出した分のインデックスは詰められる

var fruits = ["いちご","りんご", "バナナ", "みかん"];
// 添字0から3個取り出す
// Array [ "いちご", "りんご", "バナナ" ]
console.log(fruits.splice(0, 3));
// Array [ "みかん" ]
console.log(fruits);


fruits = ["いちご","りんご", "バナナ", "みかん"];
// 添字1から2個取り出す
// Array [ "りんご", "バナナ" ]
console.log(fruits.splice(1, 2));
// Array ["いちご", "みかん"]
console.log(fruits);

インデックス位置を指定して要素を取り出し・削除し、新しい要素を追加する

上の処理の延長。
取り出す要素を指定したあと、引数に配列要素を入れることで元の配列を変更できる。

var fruits = ["いちご","りんご", "バナナ", "みかん"];
// 添字0から3個取り出して,取り出した部分に1個追加する
// Array [ "いちご", "りんご", "バナナ" ]
console.log(fruits.splice(0, 3,"ざくろ"));
// Array ["ざくろ" , "みかん"]
console.log(fruits);


fruits = ["いちご","りんご", "バナナ", "みかん"];
// 添字1から2個取り出して,取り出した部分に3個追加する
// Array [ "りんご", "バナナ" ]
console.log(fruits.splice(1, 2, "パイナップル", "マンゴー", "アセロラ"));
// Array [ "いちご", "パイナップル", "マンゴー", "アセロラ", "みかん" ]
console.log(fruits);

配列のコピー

fruits2 = fruitsのようにすると参照のコピーとなってしまうので、配列のコピーとならない。
コピーするときはArray.concat()Array.slice()を使う。

var fruits = ["いちご","りんご", "バナナ", "みかん"];
var fruits2 = fruits .concat();
var fruits3 = fruits.slice();
console.log(fruits);
console.log(fruits2);
console.log(fruits3);

配列の結合

破壊的な配列の結合

var fruits = ["いちご","りんご"];
var fruits2 = ["バナナ","みかん"];

Array.prototype.push.apply(fruits, fruits2);
// 一つ目の配列が直接変更される
console.log(fruits);
console.log(fruits2);

非破壊的な配列の結合

var fruits = ["いちご","りんご"];
var fruits2 = ["バナナ","みかん"];
var fruits3 = fruits.concat(fruits2);
// 元の配列を維持したまま、2つを結合した新しい配列が出来ている
console.log(fruits);
console.log(fruits2);
console.log(fruits3);

数値配列から最大値と最小値を取り出す

var array = [1234,15, 9999, 324, 78536];
// 最大値の取得
console.log(Math.max.apply(null, array));
// 最小値の取得
console.log(Math.min.apply(null, array));

配列に指定した値が含まれているかを確認する

var foods = ['りんご', 'バナナ', 'オレンジ'];
if (foods.includes('りんご')) {
    console.log("りんごは配列に含まれています。");
}
if (!foods.includes('キウイ')) {
    console.log("キウイは配列に含まれていません。");
}

配列のソート

//配列のソート
var a = [6,9,1,22,7,1,3,2,15,83];
//Array [ 6, 9, 1, 22, 7, 1, 3, 2, 15, 83 ]
console.log(a);
//昇順
a.sort(function(a,b){
    if( a < b ) return -1;
    if( a > b ) return 1;
    return 0;
});
//Array [ 1, 1, 2, 3, 6, 7, 9, 15, 22, 83 ]
console.log(a);
//降順
a.sort(function(a,b){
    if( a > b ) return -1;
    if( a < b ) return 1;
    return 0;
});
//Array [ 1, 1, 2, 3, 6, 7, 9, 15, 22, 83 ]
console.log(a);

参考 https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array#Specifications

【ゲーム】バトルフィールド1で普段心がけていること

はじめに

f:id:beatdjam:20170523230103p:plain
昨年発売されたバトルフィールド1(PS4版)を未だにがっつりプレイしている。
基本オペ・コンクエ(たまにフロントライン)専門。
プレイ時間は100時間を超え、ランクも90台。そろそろ中堅を名乗っても良い頃だと思う。
今作は前作に比べて新規プレイヤーの数が多いという話を聞いた。
実際のところはどうだかは知らないけれど、もったいないなぁと思うプレイヤーをちょいちょい見る。
最適な行動かは別として、自分がゲーム中に心がけている行動をまとめてみた。

戦績は勝てば勝つほど良くなる

f:id:beatdjam:20170326030603j:plain
自身のスコアを少しでも伸ばすために、戦局にあまり影響の無い拠点を攻撃したり、
有利ポジションに居座って敵をキルし続けるプレイヤーをよく見かける。
そういうプレイヤーを否定するわけではないけど、
マッチ終了時に勝利チームへスコアボーナスが有ることを知ってほしい。
瞬間瞬間ではスコア的に美味しくない行動でも、
チームの勝利に貢献することでトータルではより高いスコアを得られる。
(とは言え、結局マッチングのバランスで左右されるので、
チーム移動をしなければ勝率は50%前後に落ち着く。)

兵科の強みを活かそう

各兵科は差別化されている。
敵の戦車が暴れて手をつけられないときに対戦車兵装を持った突撃兵でリスポーンしたり。
前線を抑えてデスを重ねていく味方に対して看護兵が足りない時に注射とパックで医者プレイをしたり。
長く膠着する拠点や巨大兵器へ攻撃を仕掛ける味方に弾を配る援護兵になったり。
味方が攻めあぐねている拠点をフレアスポットで援護して攻撃のきっかけを作る偵察兵になったり。
局面によって必要な兵科、ガジェット、武器は違う。
今使っている兵科がその時に最大限活かせる立ち回りを心がけよう。

マップや環境音に注意しよう

戦場で大事なのは情報だ。
マップの作りや銃声、足音…情報を得られる要素はいくらでもある。
マップを見れば地形や拠点、スポットされた敵に死んだ味方の位置が得られ、
次にどこに向かうべきか、どこを注意するべきかがわかる。
足音や銃声を聞いて、近くに味方のマークがなければそれは敵だ。
敵より先に敵の存在を知ること、敵が集中しているところを知ることは、
そのまま自分を優位に持っていくことにつながる。

オブジェクトに絡もう

f:id:beatdjam:20170523205651j:plain
電信施設の爆破や拠点の占領が必要なルールでは、
オブジェクトに絡むことが基本的に何よりも優先される行為だと思う。
自分自身が爆弾の設置や制圧、防衛を完了できない場合でも、
わずかでも自分に敵を引きつけることで味方の進軍経路や他拠点の優勢を作り出せる可能性がある。
特にオペレーションの攻撃側では、進軍側に旗に絡む人がどれだけいるかで勝敗が決まる。
旗を踏んでくれ!!

敵側拠点は負けてるとき以外基本的に不要

コンクエストは、個数的に敵味方対称となる形で拠点が配置されている。
つまり常に敵よりも多く拠点を保持し、確実に防衛することができれば勝利できるルールだ。
敵よりも多く拠点を確保していればしているほどゲージの蓄積は早くなるが、
よほどの戦力差が見られる場合以外は中央拠点より奥を攻めるべきではない。
過半数より多い拠点を保持しているということは、守るべき拠点が増えるということであり、
前線が流動的になるということでもある。
伸び切った前線はカウンターを容易にし、
敵拠点どころか本来守るべき中央拠点すら奪取される場合もある。

ただし、中央拠点から手前を制圧されて戦線の打破を目指している場合には、
裏取りで前線の兵士を剥がすことは戦略的な意味が十二分にある。
腕に自信があれば、負けているときには裏取りで前線の支援をしてみよう。

拠点制圧ルールでは中央拠点を先行して取る

前述のように、中央の拠点を先に取れるかで勝利の可能性が大きく変わってくる。
開幕でビークルや拠点の乗り物に乗れた場合は、手前の拠点から順番に攻めるのではなく、
中央の拠点制圧に向かうと序盤の有利を勝ち取れる可能性が高まる。
歩兵でも、なるべく走ってひとつふたつ先の拠点を目指して制圧することで、
より早く前線を上げることができる。

ビークルは有効に使おう

f:id:beatdjam:20170304022324j:plain
今作のビークルは、戦況を大きく左右する重要な要素だ。
拠点制圧に、前線の押し上げに、遊撃に、様々な状況で戦局を動かすことができる。
ただしそれは戦場の中で有効に活用してこそだ。
高台や後方でたまに主砲を撃っていたり、
目の前の制圧中の拠点を援護しに来なかったりするのはもってのほかだ。
芋っているビークルが高KDなのはなんの自慢にもならない。
戦闘で活躍することで自分の力を示そう。
※ 基本的に自走砲トラックを使うのは避けよう。リスポーン地点にもならず戦局に影響を与えづらい。

おわりに

ここで書いたことが全て正しいわけではないと思うけど、
それぞれが自分なりのプレイスタイルを考える切っ掛けにでもなればと思う。
戦場で会いましょう。