はじめに
今回は初めて構造化プラグラムの問題を解いてみる。面白かったけど難しかった(-_-;)!!
問1.たてH cm よこ W cm の長方形を描くプログラムを作成して下さい。
1 cm × 1cm の長方形を '#'で表します。
- 入力は複数のデータセットから構成されています。各データセットの形式は H W
- H,Wがともに0のとき入力を終了
- 各データセットについて、H × W 個の '#' で描かれた長方形を出力して下さい。各データセットの後に、1つの空行を入れて下さい。
PHP
AOJ.php
<?php
while (true) {
fscanf(STDIN, "%d %d", $h, $w);
if ($h == 0 && $w == 0) break;
for ($j = 0; $j < $h; $j++) {
for ($i = 0; $i < $w; $i++) {
echo "#";
}
echo "\n"; // 各行の後に改行
}
echo "\n"; // データセットの後に空行を入れる
}
?>
別解
other.php
<?php
while (true) {
list($H, $W) = array_map("intval", explode(' ', trim(fgets(STDIN))));
if ($H == 0 && $W == 0) {
break;
}
$line = str_repeat('#', $W) . "\n";
$rectangle = str_repeat($line, $H);
print($rectangle . "\n");
}
?>
- str_repeat→指定した回数分繰り返した文字列を返す。第一引数に繰り返す文字列、第二引数にその回数
Java
AOJ.java
import java.util.Scanner;
public class Main{
public static void main(String[]args){
Scanner sc = new Scanner(System.in);
while(true){
int h = sc.nextInt();
int w = sc.nextInt();
if(h==0&&w==0)break;
for(int j=0;j<h;j++){
for(int i=0;i<w;i++){
System.out.print("#");
}
System.out.println();
}
System.out.println();
}
sc.close();
}
}
問2.フレームの描画
以下のような、たてH cm よこ W cm の枠を描くプログラムを作成して下さい。
##########
#........#
#........#
#........#
#........#
##########
- 入力は複数のデータセットから構成されています。各データセットの形式は H W
- H, W がともに 0 のとき、入力の終わりとします。
- 各データセットについて、たて H cm よこ W cm の枠を出力して下さい。各データセットの後に、1つの空行を入れて下さい。
PHP
AOJ.php
<?php
while(true){
list($h,$w) = array_map("intval", explode(" ", trim(fgets(STDIN))));
if($h == 0 && $w == 0) break;
$line1 = str_repeat("#", $w) . "\n";
$line2 = "#" . str_repeat(".", $w - 2) . "#\n";
for($i = 0; $i < $h; $i++){
if($i == 0 || $i == $h - 1){
echo $line1;
} else {
echo $line2;
}
}
echo "\n";
}
?>
Java
AOJ.java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(true) {
int h = sc.nextInt();
int w = sc.nextInt();
if(h == 0 && w == 0) break;
// 上下の行を作成
StringBuilder line1 = new StringBuilder();
for(int j = 0; j < w; j++) {
line1.append("#");
}
// 中間の行を作成
StringBuilder line2 = new StringBuilder("#");
for(int j = 0; j < w - 2; j++) {
line2.append(".");
}
line2.append("#");
for(int i = 0; i < h; i++) {
if(i == 0 || i == h - 1) {
System.out.println(line1);
} else {
System.out.println(line2);
}
}
System.out.println();
}
sc.close();
}
}
- StringクラスのrepeatメソッドはJava11以降。今回は代わりにStringBuilderオブジェクトのappendメソッドを利用して文字列を連結
別解
other.java
import java.util.Scanner;
public class Main {
public static void main(String[] args){
Scanner scan=new Scanner(System.in);
while(true){
int H=scan.nextInt();
int W=scan.nextInt();
if(H==0&&W==0)break;
for(int i=0;i<H;i++){
for(int j=0;j<W;j++){
if(i==0||i==H-1||j==0||j==W-1){
System.out.print('#');
}
else{
System.out.print('.');
}
}
System.out.println();
}
System.out.println();
}
scan.close();
}
}
問3.以下のような、たてH cm よこ W cm のチェック柄の長方形を描くプログラムを作成して下さい。
#.#.#.#.#.
.#.#.#.#.#
#.#.#.#.#.
.#.#.#.#.#
#.#.#.#.#.
.#.#.#.#.#
//上図は、たて 6 cm よこ 10 cm の長方形
- 入力は複数のデータセットから構成されています。各データセットの形式は H W
- H, W がともに 0 のとき、入力の終わり
- 各データセットについて、たて H cm よこ W cm の枠を出力して下さい。各データセットの後に、1つの空行を入れて下さい。
PHP
AOJ.php
<?php
while (true) {
fscanf(STDIN, "%d %d", $h, $w);
if ($h == 0 && $w == 0) break;
//$line1 と $line2 を文字列として初期化し、ループの中で # や . を文字列として追加していく
$line1 = "";
$line2 = "";
for ($i = 0; $i < $w; $i++) {
if ($i % 2 == 0) {
$line1 .= "#";
$line2 .= ".";
} else {
$line1 .= ".";
$line2 .= "#";
}
}
for ($j = 0; $j < $h; $j++) {
if ($j % 2 == 0) {
echo $line1 . "\n";
} else {
echo $line2 . "\n";
}
}
echo "\n"; // データセットの区切りとして空行を追加
}
?>
- PHPで配列のサイズを指定したいとき→array_fill() / 配列を初期化してループで要素を追加
arr.php
array_fill('開始インデックス, 要素数, 初期値');
別解
other.php
<?php
while (true) {
list($H, $W) = array_map("intval", explode(' ', trim(fgets(STDIN))));
if ($H == 0 && $W == 0) {
break;
}
$line1 = str_repeat('#.', (int) floor($W / 2)) . str_repeat('#', $W % 2) . "\n";
$line2 = str_repeat('.#', (int) floor($W / 2)) . str_repeat('.', $W % 2) . "\n";
$lines = $line1 . $line2;
$board = str_repeat($lines, (int) floor($H / 2)) . str_repeat($line1, $H % 2);
print($board . "\n");
}
?>
other2.php
while (($input = trim(fgets(STDIN))) !== "0 0") {
list($h, $w) = array_map("intval", explode(" ", $input));
$s1 = substr(str_repeat("#.", intdiv($w+1, 2)), 0, $w);
$s2 = substr(str_repeat(".#", intdiv($w+1, 2)), 0, $w);
for ($i = 0; $i < $h; $i++) {
print(($i % 2 === 0 ? $s1 : $s2) . "\n");
}
print("\n");
}
- subst関数→指定した文字列の一部を取得することができるPHPの組み込み関数
- intdiv($w+1, 2) は第一引数を第二引数で割った商を求める関数
str.php
substr(対象文字列, 開始位置インデックス ,抽出する長さ)
- mb_substrも、指定した文字列の一部を取得する関数だが、mb_substrは、開始位置、文字数の指定に加えて、文字列の文字コードの指定を行うことができる。対象文字列が日本語の場合こっちを使うのがいい。
- substrがstr_repeatした文字列を切り取る関数と考えると、w が奇数の場合に切り取る部分が足りない→$w+1
Java
AOJ.java
import java.util.Scanner;
public class Main{
public static void main(String[]args){
Scanner sc = new Scanner(System.in);
while(true){
int h = sc.nextInt();
int w = sc.nextInt();
if(h==0&&w==0)break;
for(int j = 0; j < h; j++){
for(int i = 0; i < w; i++){
System.out.print((j+i)%2==0 ? "#" : ".");
}
System.out.println();
}
System.out.println();
}
sc.close();
}
}
- チェック柄(碁盤の目のような模様)は、隣接する行と列で交互に色が変わるパターン
行 / 列 | 0 | 1 | 2 |
---|---|---|---|
0 | # | . | # |
1 | . | # | . |
2 | # | . | # |