「#プログラミング」タグアーカイブ

【プログラミング】プログラミングスキル習得にC言語をオススメする理由。

正直、これを言うと賛否両論あると思いますが、

そもそも自分がC言語が最初に触ったプログラミング言語だからです。

自分は高専で本格的にC言語を学ぶ前に、

中学生時代に友人から無料コンパイラを手に入れて、

少しだけコードを書いて動かしていたことがあります。

まぁ、そんな自分でしたけど、最終的にポインタを理解できたのは会社に入ってからでしたけどね。

確かに他の言語と比べると、C言語は難しいです。

というか、みんな使っている言語は全てC言語の後に開発されたもので、

C言語の欠点を補う形で開発されました。

なので、ポインタやメモリの概念は意識しなくて済みましたが、

そこに大きな落とし穴があります。

メモリを意識することの重要性

メモリを意識しなくても良くなりましたが、メモリ自体は存在するからです。

これまで経験したのは、

Javaでガベージコレクションが働かない状態でオブジェクトが残ってて、動かしているとメモリを消費していく設計になっていたり、

AWSのLambdaを実行するとき、Pythonで大きなファイルを開こうとしたらメモリが足りなかったとか。

関数コール時にオブジェクトは参照型という話もありますが、

これもポインタによる参照渡しを、ポインタを使わずに利用できるようにしたもの。

参照渡しの場合、データがあるメモリアドレスを渡すだけなので、通常のデータ渡しよりも処理が早くなります。

CPUの動きが理解できる

プログラミング言語には3種類ありまして

(自分が高専時代は2種類と学びました)

  • コンパイル系(C、C++、Rust等)
  • 中間言語系(Java、C#等)
  • インタプリタ系(Python、PHP、Javascript等)

の3つです。

インタプリタ系は実行する度にプログラムコード読み込み、処理を行います。

扱いやすい言語ですが、動作は比較的遅いと言われています。

中間言語系はプログラムコードをビルドし、実行できる形に加工するのですが、

それを実行するためには別途仮想マシンというプログラムが必要になります。

これはビルドしたファイルがあれば、仮想マシンがある環境どこでも動作できるという特徴を持ちます。

コンパイル系はソースコードを機械語に翻訳し、そのままCPUが理解できる形に変換されます。

直接CPUが理解できる形式であるため、実行速度は速いとされています。

そして、もう一つ特徴があって、

機械語は逆アセンブルできるのです。

アセンブラは機械語の内容を人間が理解できる文字列に置き換えたもので、

これを読んでいけばCPUやプログラムがどんな動きをするのか?というのを理解できます。

CPUには独自の記憶領域「レジスタ」がありまして、

  • メモリからレジスタに値を読み出す
  • レジスタの値に対して計算する
  • レジスタにある計算結果をメモリに戻す

と言う動きを繰り返しています。

こういったCPU周りでどんなふうにプログラムが動いているか、というのが見えちゃいます。

C言語が出来れば他の言語の習得も早い

これは、

他のメジャーな言語がC言語以降に生まれたもの

ということと、

プログラミングに関する基本的な知識がC言語に詰まっている

ということから、

C言語が出来れば他の言語の習得も早いと言われています。

C言語の需要はまだありまして、

組み込みプログラミングの世界では未だにC言語が主流です。

OS周りはRustに置き換えるという話もありますけどね。

他の言語はフレームワークが発達しているので

フレームワークの習得の方が大変かもしれない。

まぁ、これは他の言語を学んでいたとしても必ず出てくる壁なので。

しかも今は昔と違ってコンパイラが簡単に手に入るので、

学習のためのハードルがかなり下がりました。

みんなも余力があればC言語に挑戦してみましょう。

【プログラミング】勇者と魔王の戦い

Tech commitの課題で、面白そうなテーマだったので、挑戦してみました。

https://github.com/takishita2nd/battle_rpg

  • 勇者と魔王が交互に攻撃する
  • 一定確率で攻撃を回避する
  • 一定確率でクリティカルヒット(ダメージ1.5倍)になる
  • どっちが勝利したかを表示する
using System;

namespace battle_rpg
{
    public static class Common
    {
        public static bool roleJudge(int rate)
        {
            bool judge = false;
            Random r = new Random();
            int value = r.Next(0, 100);
            if(value < rate) {
                judge = true;
            }
            return judge;
        }
    }
}

これは乱数を使って、命中やクリティカル判定などの確率判定を行うメソッドです。

引数に確率(%)を受け取り、乱数を0〜100の範囲で発生させて、その値が確率以下ならばtrueを返します。

using System;

namespace battle_rpg
{
    public class Charactor
    {
        private const String Statusformat = "{0}:HP{1} 攻撃力{2}";
        private const String AttackFormat = "{0}の攻撃!{1}に{2}のダメージ";
        private const String CriticalAttackFormat = "{0}の攻撃!クリティカルヒット!{1}に{2}のダメージ";
        private const String EvasionFormat = "{0}の攻撃!{1}は攻撃をかわした";
        public string Name {get;}
        public int Hp {get; set;}
        public int Attack {get;}
        public int evasionRate { get;}
        public int criticalRate { get;}

        public Charactor(string _name, int _hp, int _attack)
        {
            this.Name = _name;
            this.Hp = _hp;
            this.Attack = _attack;
            this.evasionRate = 5;
            this.criticalRate = 5;
        }

        /**
         * ターゲットを攻撃
         * <param>  _target 攻撃対象
         * <return> 与えたダメージ
         */
        public String doAttack(Charactor _target)
        {
            String message = String.Empty;
            if(isHit(_target)) {
                int damage = this.Attack;
                if(isCritical()) {
                    damage = (int)(damage * 1.5);
                    message = String.Format(CriticalAttackFormat, this.Name, _target.Name, damage);
                } else {
                    message = String.Format(AttackFormat, this.Name, _target.Name, damage);
                }
                _target.Hp -= damage;
            } else {
                message = String.Format(EvasionFormat, this.Name, _target.Name);
            }

            return message;
        }

        /**
         * 命中判定
         * <param>  _target 攻撃対象
         * <return> true:命中
         */
        private bool isHit(Charactor _target)
        {
            bool hit = true;
            if(Common.roleJudge(_target.evasionRate)) {
                hit = false;
            }
            return hit;
        }

        /**
         * クリティカル判定
         * <return> true:クリティカル
         */
        private bool isCritical()
        {
            bool critical = false;
            if(Common.roleJudge(this.criticalRate)) {
                critical = true;
            }
            return critical;
        }

        /**
         * 死亡判定
         * <return> true:死亡
         */
        public bool isDie()
        {
            bool die = false;
            if(this.Hp <= 0) {
                die = true;
            }
            return die;
        }

        public String showStatus()
        {
            return String.Format(Statusformat, this.Name, this.Hp, this.Attack);
        }
    }
}

勇者や魔王を扱うクラスです。

このクラスの中でHPや攻撃力などを保持します。

メインはdoAttack()メソッド。この中で命中判定やクリティカル判定をおこない、攻撃対象(引数)のHPを減らしていきます。

using System;

namespace battle_rpg
{
    public class Battle
    {
        private Charactor yusha;
        private Charactor maou;
        private const String DieFormat = "{0}は倒れた。";
        public Battle()
        {
            yusha = new Charactor("勇者", 300, 15);
            maou = new Charactor("魔王", 400, 9);
        }

        public void execute()
        {
            bool nowBattle = true;
            while(nowBattle) {
                // HP表示
                Console.WriteLine(yusha.showStatus());
                Console.WriteLine(maou.showStatus());
                Console.WriteLine();

                // 勇者の攻撃
                Console.WriteLine(yusha.doAttack(maou));

                // 魔王死亡判定
                if(maou.isDie()) {
                    Console.WriteLine();
                    Console.WriteLine(DieFormat, maou.Name);
                    nowBattle = false;
                    Console.WriteLine("世界に平和が訪れた。");
                }

                if(nowBattle == false) {
                    return;
                }

                // 魔王の攻撃
                Console.WriteLine(maou.doAttack(yusha));

                // 勇者死亡判定
                if(yusha.isDie()) {
                    Console.WriteLine();
                    Console.WriteLine(DieFormat, yusha.Name);
                    nowBattle = false;
                    Console.WriteLine("世界は征服された。");
                }
                Console.WriteLine();
            }
        }
    } 
}

実際にバトルを行うクラスです。

コンストラクタで勇者と魔王のステータスを設定、execute()でどちらかが負けるまでループを行います。

using System;

namespace battle_rpg
{
    class Program
    {
        static void Main(string[] args)
        {
            Battle battle = new Battle();
            battle.execute();
        }
    }
}

メイン関数。Battleクラスをインスタンス化してexecute()を実行しているだけです。

とりあえず、こんな感じで要求されている処理はできました。

カスタマイズすれば色々と拡張できそうですね。