東京工業大学
デジタル創作同好会

2016年1月29日 | メンバーブログ

traPプログラミング入門講習会2016

Namazu

皆さんtraPの新歓講習会へようこそ!
今日はプログラミング初心者に向けたプログラミング講習会(初級)を行います。
初級では競技プログラミングの形式に沿ってJavaによるプログラミングの基本を修得することを目指します。
講習会ではコードの書き方、演算について、基本的な構文、メソッドについて扱ったのちチャレンジ問題を扱います。

1.Eclipseの準備

EclipseはJavaでプログラムを書くためのツールです。 演習室のPCには初めからインストールされていますので、Launch Padから起動してください。 workspaceの場所を聞かれますが、そのまま進んで構いません。 これでEclipseが起動出来ればOKです。

Eclipseがインストールされていない場合 こちらから、Eclipse 4.5 Mars Pleiades All in one のJava Full Editonを、OSに対応するbitのバージョンをダウンロードしてください。 出てくるダイアログを全て肯定し、フォルダ作成位置もデフォルトのままで構いませんので進めていくとEclipseのインストールが完了します。

Eclipseの導入

Eclipseを起動したら、[ファイル](①)→[新規]→[新規Javaプロジェクト]を選択し、lectureと名前を付けてください。 今度は新規パッケージのアイコン(②)をクリックし、新しいパッケージにlecture0425(今日の日付を後ろに付ける)と名前を付けてください。 その後新規Javaクラス(③)をクリックし、Mainと名前を付けてください。これでプログラムを書く環境が整います。

2.競プロ型のコードの基本的構造のおおまかな説明

早速ですがプログラムを書いてみましょう。これはHello,Worldというプログラマの通過儀礼です。 ※この時、package lecture0425;という記述は消さないでください。

public class Main {
	public static void main(String[] args){
		System.out.println("Hello,World");
	}
}

プログラムを実行するには画面の④のボタンを押してください。 このプログラムを実行し、コンソールにHello,Worldと表示されれば成功です。 さて、皆さんに本日書いていただくプログラムの基本的構造は以下の通りです。これも書いてみましょう。

import java.util.Scanner;

public class Main {
	public static void main(String[] args){
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		System.out.println(n);
	}
}

このプログラムを実行したら、先ほどHello,Worldと出力されたところ(コンソール)に何か小さな整数を半角で入力してEnterを押してみてください。 すると、再度自分の入力した数字が表示されたかと思います。それはこのプログラムによって出力されたものです。

まず、プログラムにはクラスという概念があり、プログラムの最小単位のことを言います。今回は一つのクラスでプログラムが出来ていますが、ゲーム開発においてはクラスがいくつも集まって一つのプログラムを形作っているのが普通です。 そしてクラスには名前があり、名前は英数字で頭文字は大文字であるというルールがあります。上記のプログラムの名前は"Main"です。そう、3行目に書いてありますね。Eclipseでは、新しいクラスを作成するとき同時にクラスの名前を決めることになっています。ですから自分でこの部分(3行目)を記述することはありませんが、基本知識として覚えておきましょう。

4行目を見てください。これはmain関数といって、プログラムはこの関数に記述された流れに沿って動くようになっています。publicとかstaticとかvoidとかString[] argsは今は無視して構いません。 また、関数などは、その関数を記述している範囲を{}で囲む必要があります。上のコードを見るだけでも二重に{}が囲われているのが分かりますね。{と}の数はしっかり合わせるように気を付けてください。

そして5行目。これは入力されたデータを読み取るためのものです。おまじないだと思って置いてください。

6行目、7行目に書かれている内容は、簡単には 6行目「入力された整数をnとする」 7行目「nを表示する」 ということです。7行目は()の中身を表示する命令だと思ってください。6行目のことは以下で解説しますが、まずは練習問題でここまでの流れをおさらいしましょう。

[練習問題] 1. 実行すると「Welcome!」と出力するプログラムを書いてください。 2. 入力した整数nを二回出力するプログラムを書いてください。

3.データ型と変数

データ型 プログラムは様々なデータを扱いますが、そのデータには数字や文字など様々な種類があります。 そこで、Javaではデータに「型」を定めることにより「機械がプログラムを読みやすく」しています。

それぞれのデータは正しい型で宣言し、使わなければエラーになってしまいます。気を付けましょう。

変数 皆さん数学でお馴染みの変数です。しかし、プログラムを書く上での変数は数字に限らず、上に示した型に入る全てのデータを扱うことが出来ます。 ところで、数学の解答で問題に指定されていない変数を扱いたいとき、例えば「tを0

public class Main {
	public static void main(String[] args){
		int a = 10;
		double b = 3.141592;
		String c = "Hello,World"; // String c = Hello,World としてはいけません
		char d = 'd';             // char d = d や char d = "d" としてはいけません。
		boolean e = false;        // ここに書けるのは、true か false のみ
		System.out.println(a);
		System.out.println(b);
		System.out.println(c);
		System.out.println(d);
		System.out.println(e);
	}
}

出力結果は以下の通りです。

10
3.141592
Hello,World
d
false

最初のHello,Worldと見比べて分かるように、最後の出力で直接"Hello,World"と入力せずcと入力するだけで"Hello,World"と出力することが出来ます。 まだ、これは変数の使い方のほんの一部です。この記事を読み進めていくうちに更に変数の良さが分かってくるでしょう。

ところで、変数を扱うときに注意しなければいけないのは、宣言と初期化の違いです。 宣言とは「int型の変数nを使う」というだけで、nがいくつかまでは言及していません。 初期化とは「宣言した変数nに、はじめ10という値を入れる」ということです。 実は、先ほどのコードでは宣言と初期化を同時に行っていたのです。初期化を行わずに変数を用いるとコンパイルエラーになってしまいます。

4. 四則演算

四則演算 変数に数字を入れてそのまま使うだけでは味気ないですね。そこで、四則演算のやり方を修得しましょう。 見ていただいた方が速いと思うのでコードを載せます。

public class Main {
	public static void main(String[] args){
		int a = 8;
		int b = a + 2; //bはa+2を計算した結果
		int c = a - 4; //cはa-4を計算した結果
		int d = a * 3; //dはa×3を計算した結果
		int e = a / 2; //eはa÷2を計算した結果
		int f = a % 3; //fはaを3で割った余りを計算した結果
		System.out.println(a);
		System.out.println(b);
		System.out.println(c);
		System.out.println(d);
		System.out.println(e);
		System.out.println(f);
	}
}

出力結果は以下の通りです。

8
10
4
24
4
2

×と÷の表記が異なるのとmodが%で表せるというだけなので、ここまでは特に問題ないと思います。

代入 ここでいう代入とは、数学での代入とは大きく意味が異なります。 「A = B」と記述することで、AをBと同じ値にするという意味をなします。実際にコードに一部を見てみましょう。

int a,b;
b = 3;
a = b;

このように記述したとき、「aにbを代入する」という意味になります。つまり、右辺の値を左辺に代入するということです。ですから、上の例ではaに3が入ります。 よって、実は先ほどの四則演算の4行目(足し算)は、 「変数bを宣言し、bにa+2を代入することで初期化する」 という意味だったのです。 プログラムを書くとき、基本的には常に等式の左辺と右辺は「右辺の値を左辺に代入する」という関係です。

さて、それを踏まえたうえで以下のコードを見てください。

int a = 3;
a = a+3;
System.out.println(a); //a+3=6
a = a+4;
System.out.println(a); //a+4=10
a = a*3;
System.out.println(a); //a×3=30
a = a/2;
System.out.println(a); //a÷2=15

出力結果は以下の通りになります。

6
10
30
15

同じaを出力しているはずなのに出てくる値は違います。これこそまさにプログラムでの代入というものです。 2行目、これを先ほどのルールに従って読み替えると「aにa+3を代入する」という意味になります。 もう少し噛み砕いた表現すると、「a+3を計算し、aの値をその和に書き換える」ということです。このように同じ変数でもその中に入っている値はどんどん更新されていきます。一見面倒くさいようですが、これはプログラムを書く上で非常に都合がいいのです。 ちなみに、「a = a+4」は「a += 4」と書くことも出来ます。「*=」「/=」「-=」についても同様です。

また、出力には文字列を加えることも可能で、

System.out.println("a+2="+ (a+2)); //("a+2=" + a+2)ではないので注意

と書くと

a+2=10

と出力されます。ここで、「a+2=」は文字列で10はa+2の演算結果です。これらを続けて表示する、ということです。

[練習問題] 入力した数字に2を足した結果、2を掛けた結果、2を引いた結果をそれぞれ表示するプログラムを作成してください。 その際、この記事冒頭のプログラム、Practiceを参考にしてください。

5.条件式

高校数学で、命題と論理という分野がありましたね。「~~は○○である」という命題は真か偽か、というものです。 この考えはプログラムにも応用され、主に場合分けをする時に便利なのでよく使われます。 プログラムの場合、いわゆる命題は式の形で表され、条件式と呼ばれます。条件式は必ずtrueかfalseの値を持ちます。 その種類を見ていきましょう。

int a = 3;

a == 3        // true
a >  2        // true
a != 2        // true
a == 2        // false
a >  4        // false
a != 3        // false

String str = "traP"

str == "traP"  // true
str != "kbtit" // true

boolean bln = true;

bln == true   // true
bln != false  // true

bln = false   // blnの値をfalseに変更

bln == false  // true(左辺はfalse、右辺もfalseなのでこの条件式が持つ値はtrue)

また、boolean型の変数は元から真偽値を持ちますので単独で条件式と同じ役割を果たすことができます。 さらに、否定の「!」も組み合わせることができ、blnがtrueのとき「!bln」はfalseとなります。 それでは、この条件式はどのように使われるのでしょうか。続けてお読みください。

6.if文

if文の構造は以下の通りです。

if(条件式){
     (条件式の値がtrueの時に実行する処理);
} else {
     (条件式の値がfalseの時に実行する処理);
}

例えば、入力した整数の値の偶奇を判定するプログラムを書いてみましょう。

import java.util.Scanner;

public class Main {
	public static void main(String[] args){
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		if(n%2 == 0){
			System.out.println("nは偶数"); //処理1
		} else {
			System.out.println("nは奇数"); //処理2
		}
	}

}

ここで書かれている条件式は「n%2 == 0」ですね。 偶数の時、入力した値nを2で割った余りは0ですから条件式はtrueになりますので処理1が実行されます。 奇数の時、入力した値nを2で割った余りは0ではないので条件式はfalseになりますので処理2が実行されます。

また、if文は続けて書くことも出来ます。

import java.util.Scanner;

public class Main {
	public static void main(String[] args){
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		if(n%3 == 0){
			if(n%2 == 0){
				System.out.println(n+"は6の倍数"); //処理1
			} else {
				System.out.println(n+"は3の倍数"); //処理2
			}
		} else if(n%3 == 1){
			System.out.println(n+"を3で割った余りは1"); //処理3
		} else {
			System.out.println(n+"を3で割った余りは2"); //処理4
		}
	}

}

処理の流れを追ってみると分かると思いますが、例えばnが6の時「n%3==0」はtrueなので処理1か処理2が実行されることになります。 さらに、「n%2 == 0」はtrueですからこの時は処理1が実行されることになります。 また、例えばnが5の時「n%3==0」はfalseで、「n%3==1」もfalseなので処理4が実行されることになります。

7.while文

while文の構造は以下の通りです。

while(条件式){
    (条件式がtrueの間実行し続ける処理);
}

ここで注意していただきたいのが、例えば

int a = 3;

while(a>2){
    System.out.println("aは2より大きい");
}

とすると、「a>2」は常にtrueですのでこの処理が実行され続けてしまいます。いわゆる無限ループです。 これを回避しなければならないので、例えばこのように書きます。

int a = 0;

while(a<10){
    System.out.println(a);
    a = a+1;
}

こうするとaはwhile文の処理が一回実行されるたびに値が1大きくなり、10回目の処理でwhile文を抜けることが出来ます。 while文を用いると何度も繰り返したい同様の処理を手軽に記述することが出来ます。

8.for文

for文の構造は以下の通りです。

for(int i=0;(条件式);i = i+1){
    (条件式がtrueの時実行する処理)
}

これでは分かりにくいと思うので、while文とfor文で全く同じ処理を記述してみます。

// while文の場合

int i = 0;
while(i<10){
    System.out.println("Hello,World");
    i = i+1;
}

// for文の場合

for(int i=0;i<10;i=i+1){
    System.out.println("Hello,World");
}

どちらも10回「Hello,World」を出力するプログラムです。 for文はwhile文でバラバラに書いていた変数iについての記述をまとめて書いています。 for文は反復回数の決まった処理を行うのに便利ですね。一方、while文は反復回数が定まらない処理を行うのに便利です。 場合によって上手く使い分けましょう。

それでは、if文、for文、while文を組み合わせた処理を実行してみましょう。

import java.util.Scanner;

public class Main {
	public static void main(String[] args){
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		for(int i=0;i

これはHelloとWorldを交互に表示するプログラムです。このように変数iをfor文の中で使うこともできます。

[練習問題] 上記のプログラムを、iを3で割った余りが0ならば「Hop」、1ならば「Step」、2ならば「Jump!!」と表示するように書き換えてください。

[補足] for文やwhile文に記述した処理を途中で終了するには、break;という記述を入れてください。 例えば以下のプログラムは10から1までを続けて表示するプログラムです。

public class Main {
	public void main(String[] args){
		int n = 10;
		while(true){
			if(n < 1) break;
			System.out.println(n);
			n = n-1;
		}
	}
}

もちろんこの処理をしたい場合はbreak文を使わなくてもwhile(n>0)のように記述すればいいのですが、 いつかbreak文が必要になるときが来るでしょうから一応覚えておいてください。

9.配列

さて、ここまでの話から少し逸れるようですが実際にプログラムを書くときたくさんの変数が必要になることがあります。 例えば、あるクラス全員の英語と数学の成績から平均値や偏差値を計算するとしましょう。 もし、それをそのまま計算するプログラムを書くとすると以下のようになります。

import java.util.Scanner;

public class Main {
	public static void main(String[] args){
		Scanner sc = new Scanner(System.in);
		double taroEnglishScore = sc.nextDouble();
		double taroMathScore = sc.nextDouble();
		double hanakoEnglishScore = sc.nextDouble();
		double hanakoMathScore = sc.nextDouble();
		double namazuEnglishScore = sc.nextDouble();
		double namazuMathScore = sc.nextDouble();
		double averageEnglish = (taroEnglishScore+hanakoEnglishScore+namazuEnglishScore)/3;
		double averageMath = (taroMathScore+hanakoMathScore+namazuMathScore)/3;
		System.out.println(averageEnglish);
		System.out.println(averageMath);
	}
}

たった3人でもこれほど大変なことになります。見やすさ、わかりやすさ、効率どれをとってもダメですね。 そこで、同様の性質をもつ変数をひとまとめにすることができます。それが配列です。 それでは早速配列の定義の仕方をみてみましょう。

int[] a = {1,2,3,4,5};

このように「型名[] 変数名 = {要素,要素,…,要素}」という形の宣言をします。変数のときとほぼ同じですね。 ここで、要素は変数と同様のはたらきをします。 また、このとき

a[0] == 1
a[1] == 2
a[2] == 3
a[3] == 4
a[4] == 5

//これらの値は全てtrue

となっています。はじめからn番目の要素を変数のように指定したいときはa[n-1]とすればOKです。 一般的にプログラム上では自然数は0から始まると考えてください。慣れないと気持ち悪いですね。 一応、ここで配列の中身を表示するプログラムを載せておきましょう。

public class Main {
	public static void main(String[] args){
		int[] a = {1,2,3,4,5};
		System.out.println(a[2]); //3が出力される
	}

}

さて、それでは配列の別の定義の仕方をご紹介します。それは以下の通りです。

int[] a = new int[5];
a[0] = 1;
a[1] = 2;
a[2] = 3;
a[3] = 4;
a[4] = 5;

果たしてこの定義の仕方は存在する意味があるのか、そう思われる方もいらっしゃるでしょう。 しかしながら、実は配列の定義はこの方法を用いることがほとんどです。何故でしょうか?

そう、for文やwhile文を用いて定義ができるからですね。 すると先ほどのクラス全員の英語と数学の点数の管理も簡単です。

import java.util.Scanner;

public class Main {
	public static void main(String[] args){
		int member = 40;
		int[] scoreEnglish = new int[member];
		int[] scoreMath = new int[member];
		
		Scanner sc = new Scanner(System.in);
		for(int i=0;i

なんとこのコードだけで、それぞれ値を入力することにより80個分の変数を定義することが出来てしまいます。 この配列は全ての型の変数で使うことが出来ます。是非使いこなしてください。

10.メソッド

ついに最後の項目です。頑張りましょう。 たくさんの処理をしなければならないプログラムを書くとき、すべての処理をだらだらと書くのはあまり良くありません。 main関数はプログラムにとっての行動予定表のようなものです。行動予定表にそれぞれのイベントでの動きの詳細までは書きませんよね。 そこで、イベントごとに処理を別の場所に書いてそのイベント名だけmain関数で記述すればいいような仕組みにするとぐっと見やすくなります。 それがメソッドです。メソッドは数学の関数のように入力した値に対して何かしらの値を返すことも出来ます。

public class Main {
	public static void main(String[] args){
		int n = 100;
		System.out.println(sum(n));
		fiveTimeSayHello();
	}
	public static int sum(int a){
		int total = 0;
		for(int i=1;i

メソッドの定義は、「public static 返り値の型名 メソッド名(引数){処理}」という形で行います。 ここで、返り値を持たない場合は型名をvoid、引数を持たない場合は()の中は何も書かない、というように記述します。 (上の例で、FiveTimeSayHelloは型名を持たず、さらに引数も持たない)

さて、説明が前後しますが引数と返り値の説明をします。 引数とはメソッドに渡す値のことで、引数はメソッドの中で使うことが出来ます。実際、上の例でsumではaという引数をメソッド内で使用しています。 返り値(戻り値とも言います)とはメソッドから戻される値のことです。 高校数学でのy=f(x)において、xが引数、f(x)が返り値だとイメージしてください。 また、例えば上の例におけるsum(x)は単なる数値として扱うことができますので、int y=sum(x)のような使い方が出来ます。 もちろん、x=f(x)という使い方も出来ます。何かに使えるかもしれませんね。

[練習問題] 以下のコードは入力された整数nの階乗(n!)を求めるプログラムですが、メソッドの中身が一部書かれていません。 必要な部分を埋めて、このプログラムを完成させてください。

import java.util.Scanner;

public class Main {
	public static void main(String args[]){
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		System.out.println(factorial(n));
	}
	public static int factorial(int a){
		
		
		return result;
	}
}

11.チャレンジ問題

今回の講習会で学んだことを活かして、実際に自分でプログラムを組んでみましょう。 もちろん、この記事に書いてあるコードは参考にしていただいて構いません。 いかに記述したサンプル問題で正しい答えが出ることを確認したら、前のホワイトボードで与えられた入力に対して正しい答えが出るか確かめてみましょう。 この際、eclipse以外を用いて計算してはいけません。 それでは早速挑戦してみましょう。

[Easy] 与えられた整数n(n≧2)に対して、1からnまでの各項の二乗の和(1^2+2^2+…+n^2)squareSum(n)を求めるプログラムを書いてください。 ※10.メソッドのsumという関数を参考にして、squareSumという関数を作ってみましょう。

入力例1

2

出力例1

5

入力例2

4

出力例2

30

[Normal] 与えられた整数nの約数(1,nを含む)を全て列挙するプログラムを書いてください。

入力例1

4

出力例1

1
2
4

入力例2

13

出力例2

1
13

[Hard] 与えられた整数が素数であるか否かをするプログラムを書いてください。答えはyesまたはnoで一行で出力してください。 ただし、与えられる数は1より大きい整数であるとします。 以下、入力例と出力例を2つ載せます。 ※方法はいくらかあります。Normalのプログラムを応用する方法、boolean関数を使う方法、for文のbreakを使う方法など…

入力例1

30

出力例1

no

入力例2

13

出力例2

yes

[Lunatic] 素因数分解をするプログラムを書いてください。答えは素因数を小さいほうから順に一行ずつ出力してください。 ただし、与えられる数は必ず3つの素数の積であるとします。 また、例えばnがn=a^2*bと分解されるような数だった場合、答えはa,a,bと出力されれば正解とします。 以下、問題例と解答例を3つ載せます。 ※メソッドを使ってみましょう。

入力例1

30

出力例1

2
3
5

入力例2

98

出力例2

2
7
7

入力例3

320311

出力例3

59
61
89

[Extra] 素因数分解をするプログラムを書いてください。答えは以下の出力例に従って小さい素因数から順に書きだしてください。 ただし、与えられる数の素因数の数は定められていません。 以下、問題例と解答例を3つ載せます。 ※Lunaticで使用したメソッドを応用してみましょう。

入力例1

30

出力例1

30=2^1*3^1*5^1

入力例2

13

出力例2

13=13^1

入力例3

3780

出力例3

3780=2^2*3^3*5^1*7^1

この記事を書いた人
Namazu

Namazuです。 今まで制作に携わったゲームはTypingWar、EccentricEscape、進捗どうですか?等です。 現在進行中のプロジェクトでMonoGameを使っており、それにまつわる記事も書いています。

この記事をシェア

このエントリーをはてなブックマークに追加

関連する記事

2017年12月24日
ネタがないので迷路を自動生成してみた
tsukatomo
2017年12月14日
Project Eulerのすすめ
Ark
2017年12月12日
非ノベルゲームにおけるシナリオシーンの知見
long_long_float

活動の紹介

カテゴリ

タグ