ホーム » スタッフ » 斉藤徹 » 講義録 » 創造工学演習

創造工学演習」カテゴリーアーカイブ

2020年10月
 123
45678910
11121314151617
18192021222324
25262728293031

最近の投稿(電子情報)

アーカイブ

カテゴリー

Remote-sshでcould not to establish…

PHPとデータベースの実験で、クラウドサーバ上のファイルを触るために、VSCode に Remote-ssh をインストールして、サーバのファイルを編集だけど、何人かの学生がログインできない様子。

“Could not establish connection to ホスト名”といったエラーが表示される。同様のエラーの情報を探していたら、以下のようにremotePlatformを指定すれば良いとの情報。

Remote-sshの設定⚙の、「拡張機能の設定」を選び、Remote-sshのRemote Platformを編集するためのsettings.jsonの編集画面となる。

この中で、”remote.SSH.remotePlatform”に、接続相手の名前とOS種別(今回はLinux)を設定する。

創造工学演習・予備実験・PHPとDB

インターネットを活用したプログラムを作成する場合、データを保存管理するためのデータベースと、データベースのデータを処理するためのプログラム言語が必要となってくる。今回の予備実験では、そのためにリレーショナルデータベースと、Webの動的なプログラム言語である PHP について説明する。

リレーショナル・データベース

データベースは、データを保存し、矛盾が発生しない様に管理してくれるシステムであり、インターネットで活用されている。

データを確実に保存し、矛盾なく扱うためには、本来複雑なプログラムが必要となる。この中で、データを表形式のテーブルを組み合わせて管理するシステムはリレーショナルデータベースと呼ばれる。リレーショナルデータベースでは、データの問い合わせなどの処理が簡単にできるように、SQL と呼ばれる言語を使って処理を行う。

大量のデータをインターネットの中で利用するためには、ネットワークを経由してデータの問い合わせが求められ、有名なデータベースシステムには、Oracle, MySQL などがある。今回の実験では、ネットワーク機能は持たないが簡単な手続きで使うことができる SQLite を使って説明する。

また、今回の予備実験では時間も限られることから、複数の表を組み合わせた SQL の処理については割愛する。

SQLの基本

リレーショナルデータベースでは、データの基本は表形式データであり、1つの表に相当するデータはテーブルと呼ぶ。

以下の様な名前・住所・年齢のデータがあったとすると、1人前のデータをレコードと呼び、name, addr, age といった属性はカラムと呼ぶ。

name addr age
t-saitoh 越前市 55 ←レコード
sakamoto 福井市 50
murata 福井市 35
↑カラム

データの型には、文字列型(char型,varchar型,text型)や、数値型(integer型,decimal型,real型)などがあり、create table 文にてカラムの型を定義する。

create table テーブルを作る

データベースの表を使う最初には、create table 文を実行する。C言語での struct 文をイメージすると解り易いかもしれないが、データはデータベースの中に永続的に保存されるので、システムを動かす最初に一度実行するだけで良い。

上記のような名前・住所・年齢のデータ構造であれば、次の様な create table 文を使う。

create table テーブル名 (
    カラム名1  型1 ,
    カラム名2  型2 
    ) ;
-- 例 --
create table PERSON (        -- テーブル名:PERSON
    name  varchar( 20 ) ,    -- 名前
    addr  varchar( 20 ) ,    -- 住所
    age   integer ,          -- 年齢
    primary key( name )      -- name はデータ検索のキーであり重複は許されない
    ) ;

これと同じ様な処理をC言語で書くのであれば、以下の様な構造体宣言と同じであろう。

struct PERSON {
    char name[ 20 ] ;    // 名前
    char addr[ 20 ] ;    // 住所
    int  age ;           // 年齢
} ;

drop table テーブルを消す

データベースは永続的に保存されるので、テーブル全体のデータが不要であれば、drop table 命令で、テーブル全体を消す。

drop table テーブル名 ;
-- 例 --
drop table PERSON ;

insert into レコードを追加

データベースに1レコードを保存するには、insert文を用いる。

insert into テーブル名 ( カラム名... ) values( 値... ) ;
-- 例 --
insert into PERSON ( name ,       addr ,    age )
            values ( 't-saitoh' , '越前市' , 55  ) ;
insert into PERSON ( name ,       addr ,    age )
            values ( 'sakamoto' , '福井市' , 50  ) ;
insert into PERSON ( name ,       addr ,    age )
            values ( 'murata' ,   '福井市' , 35  ) ;

delete レコードを消す

データベースのレコードを消すには、delete 文を用いる。条件を満たす複数のデータをまとめて消すことができる。

delete from テーブル名 where 条件 ;
-- 例 --
-- 40歳未満のデータを全て消す。 murata,福井市,35 が消える。
delete from PERSON
       where age < 40 ;

update レコードを更新

データベースのレコードを修正するには、update 文を用いる。条件を満たす複数のデータをまとめて修正することもできる。

update テーブル名 set カラム = 値 where 条件 ;
-- 例 --
-- 住所が越前市のレコードの年齢を 0 にする。
update PERSON set age = 0
       where addr == '越前市' ;

select データを探す

データベースの内容を参照するための命令が select 文。where を記載することで、特定の条件のデータだけを選択したり、特定のカラムだけを抽出することができる。

select カラム名 from テーブル名 where 条件 ;
-- 例 --
-- PERSON の全データを出力
select * from PERSON ;

-- PERSON の住所が福井市だけを選別し、名前と住所を抽出
select name,addr from PERSON
       where addr = '福井市' ;

-- PERSON の年齢の最高値を出力 (集約関数)
select max(age) from PERSON
       where addr = '福井市' ;

-- PERSON の年齢条件を満たす人数を数える (集約関数)
select count(name) from PERSON
       where age >= 50 ;

動的なプログラム言語とPHP

本来、Webサーバが作られた頃は、論文や研究用のデータを公開する物であったが、扱うデータが増えるにつれ、特定の論文や研究データの一覧を表示したり探したりという処理が求められた。こういった処理のためにWebページのアクセスを受けた時に処理を実行する CGI という機能があったが、これを発展させてできたプログラム言語が PHP である。

PHPでは、ページを表示するための HTML の中に <?php?> のといった開始タグ・終了タグの中に、ブラウザから送られてきたデータに合わせて、処理を行うPHPの命令を記述し、データを(一般的にはHTML形式で)表示することができる。基本文法は C 言語に似ているが、様々なデータを扱うために変数にはどのような型でも保存できるようになっている。

ブラウザからデータを送るためのform文

ブラウザで入力欄を作ったり選択肢を表示し、その結果を送るための HTML は、入力フォーム(form)と呼ぶ。

<form method="get" action="処理ページ" >

  <input type="text" name="変数名" />

  <input type="radio" name="変数名" value="値" />
  <input type="checkbox" name="変数名" value="値" />

  <textarea cols="横文字数" rows="行数"></textarea>

  <select name="変数名">
    <option value="値1">表示1</option>
    <option value="値2">表示2</option>
  </select>
  <input type="submit" value="実行ボタンに表示する内容" />
</form>

formでは、入力する項目に変数名の名前を付け、action=”” で示したページにデータを送る。

PHPのプログラムの基本

PHPのプログラムは、外見は一般的に HTML ファイルであり、途中で <?php のタグからは、?> までの範囲が、PHP で処理が行われる。PHP のプログラムで print が実行されると、その場所に print 内容が書かれているような HTML ファイルが生成され、ブラウザで表示される。

PHP の中で変数は、$ で始まり、型宣言は基本的に不要である。

文字データを連結する場合は、”.” 演算子を使う。ダブルクオテーション”…”で囲まれた文字列の中の $名前 の部分は、変数名として扱われ、変数名の内容に置き換えられる。

HTMLのform文の action 属性で示された php であれば、PHPの中で送られてきた値を $_GET[‘変数名’] (method=”get”の場合)、 $_POST[‘変数名’] (method=”post”の場合)、または $_REQUEST[‘変数名’] (method=”get” or “post”) で参照できる。

((( sample.php )))
<html>
   <head>
      <title>sample.php</title>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
   </head>
   <body>
      <form action="sample.php" method="POST">
         <input name="A" type="text" />     <!-- 変数 $A -->
         +
         <input name="B" type="text" />     <!-- 変数 $B -->
         =
         <?php 
            ini_set( 'error_reporting' , E_WARNING ) ;
            if ( $_REQUEST[ "A" ] != "" && $_REQUEST[ "B" ] != "" ) {
               print $_REQUEST[ "A" ] + $_REQUEST[ "B" ] ;
            } else {
               print "<INPUT TYPE=submit>" ;
            }
         ?>
      </form>
   </body>
</html>

PHPでデータベースを扱う

SQLのデータベースを、プログラム言語の中で扱う場合は、その記述も色々である。PHPでは以下の様にSQLを扱う。

((( survey-init.php )))
<html>
   <head>
      <title>survey_init.php</title>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
   </head>
   <body>
      <?php
         // デバッグ用にエラー警告を表示する
         ini_set( 'error_reporting' , E_WARNING ) ;
         // データベースに接続する
         $data_dir = "../public_data" ;
         $dbh = new PDO( "sqlite:$data_dir/sqlite.db" ) ;
         // データベースを初期化する
         $init_sql = "drop table if exists Survey ;"
                   . "create table Survey ("
                   . "  uid  varchar( 20 ) ,"
                   . "  item varchar( 10 )"
                   . ") ;"
                   . "insert into Survey ( uid , item ) values ( 't-saitoh' , '猫'        ) ;"
                   . "insert into Survey ( uid , item ) values ( 'tomoko' ,   'ケーキ'     ) ;"
                   . "insert into Survey ( uid , item ) values ( 'mitsuki' ,  'ボードゲーム' ) ;"
                   ;
         if ( $dbh->exec( $init_sql ) < 0 ) {
            print "Error: $init_sql" ;
         }
         // データベースの表形式を読み出し、表形式で出力する。
         print "<table border='1'>\n" ;
         print "<tr><td align='center'>uid</td><td align='center'>item</td></tr>\n" ;
         $select_sql = "select uid,item from Survey ;" ;
         foreach( $dbh->query( $select_sql ) as list( $uid , $item ) ) {
            print "<tr><td>$uid</td><td>$item</td></tr>\n" ;
         }
         print "<table>\n" ;

         // データベースの単一データを取り出す
         $count_sql = "select count(item) from Survey where item = 'ケーキ' ;" ;
         print $dbh->query( $count_sql )->fetchColumn() ;
      ?>
   </body>
</html>

PHPの主要なSQL関数(PDO)

$dbh = new PDO(…) ; データベースに接続するハンドラを取得。
$dbh->exec( “create…” ) ; データベースでSQLを実行。
$dbh->query( “select…” ) ; データベースに問い合わせ。「1レコードに対応した配列」が全データだけ繰り返す、2次元配列を返す。
$dbh->query( “…” )->fetchColumn() 結果が1つだけの問い合わせ。集約関数の結果を参照する場合に用いる。

練習問題(1)

  • 上記の survey-init.php の select 文の部分を編集し、色々なデータ検索を試してみよ。

入力フォームのデータをデータベースに書き込む

((( survey-vote.php )))
<?php
    // エラー警告を表示                                                                                                     
    ini_set( 'error_reporting' , E_WARNING ) ;

    // form から送られてきた変数を保存                                                                                      
    $uid  = $_REQUEST[ "uid" ] ;
    $item = $_REQUEST[ "item" ] ;

    // データベースに接続する                                                                                               
    $data_dir = "../public_data" ;
    $dbh = new PDO( "sqlite:$data_dir/sqlite.db" ) ;

    // データベースに項目を追加する                                                                                         
    if ( $uid != "" && $item != "" ) {
        $insert_sql = sprintf( "insert into Survey( uid , item ) values ( %s , %s ) ;" ,
                               $dbh->quote( $uid ) , $dbh->quote( $item ) ) ;
        $dbh->exec( $insert_sql ) ;

        // reload処理で追記しないためページを強制的に再表示させる                                                           
        header( "Location: survey-vote.php" ) ;
    }
?>
<html>
  <head>
    <title>survey_vote.php</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  </head>
  <body>
    <form method="get" action="survey-vote.php">
       名前:   <input type="text" name="uid" />
       好きな物:<input type="text" name="item" />
       <input type="submit" value="投票" />
    </form>
    <?php
      // データベースの表形式を読み出し、表形式で出力する。                                                                   
      print "<table border='1'>\n" ;
      print "  <tr><td align='center'>uid</td><td align='center'>item</td></tr>\n" ;

      $select_sql = "select uid,item from Survey ;" ;
      foreach( $dbh->query( $select_sql ) as list( $t_uid , $t_item ) ) {
          print "  <tr><td>$t_uid</td><td>$t_item</td></tr>\n" ;
      }
      print "</table>\n" ;
    ?>
  </body>
</html>

練習問題(2)

  • 上記の survey-vote.php のプログラムを編集し色々な入力方法・出力方法を試してみよ。
    • 例えば、入力の item 選択に select や ラジオボタン フォームを使う。
    • 例えば、出力結果で、item の投票結果を、棒グラフで出力する。

創造工学演習・予備実験・パズル問題

プログラミングコンテストの競技部門では、パズルのような組み合わせ問題が 出題されることが多い。また、課題部門や自由部門であっても、複数の条件の組み合わせの中から最良のものを選ぶといった処理も求められる。そこで、この予備実験では、きわめて単純なパズル問題(組み合わせ問題) のプログラムについて扱う。

組み合わせ問題の基礎

簡単な問題として「100未満の整数の値を3つ選び、その値を辺の長さとした場合、 直角三角形となるものをすべて表示する。」について考える。

一番簡単な方法は、以下となるであろう。

#include <stdio.h>
#include <math.h>
#include <time.h>

// 整数比の直角三角形の一覧を求める。
void integer_triangle( int n ) {
   for( int a = 1 ; a < n ; a++ ) {
      for( int b = 1 ; b < n ; b++ ) {
         // 一番ダサい方法
         for( int c = 1 ; c < n ; c++ ) {
            if ( a*a + b*b == c*c ) {
               printf( "%d %d %d\n" , a , b , c ) ;
            }
         }
      }
   }
}
int main() {
   integer_triangle( 100 ) ;
   return 0 ;
}

しかしこのプログラムの欠点としては、100×100×100回のループで無駄な処理が多い。

ループ回数を減らすだけなら、最も内側の処理を、計算で整数値か確認すればいい。

void integer_triangle( int n ) {
   for( int a = 1 ; a < n ; a++ ) {
      for( int b = 1 ; b < n ; b++ ) {
         // ココも改良できるよね?
         int d = a*a + b*b ;
         int c = (int)sqrt( d ) ;
         // 斜辺Cの整数値を求め、改めて確認する。
         if ( c*c == d ) {
            printf( "%d %d %d\n" , a , b , c ) ;
         }
      }
   }
}

(1) 計算誤差の問題を考えてみよう。

たとえば、3:4:5の直角三角形で、3*3+4*4 = 25 だが、sqrt(25)は実数で計算するから、 計算誤差で4.99999で求まったらどうなるだろうか?

1~100までの数値で、”int c = sqrt( (double)(i*i) ) ;” を計算してみて、 異なる値が求まることはあるか? 多少の計算誤差があっても正しく処理が行われるにはどうすればいいか、考えてみよう。

(2) 無駄な答えについて考えてみよう。

このプログラムの答えでは、簡単な整数比の答えの「整数倍の答え」も表示されてしまう。 たとえば、(3:4:5)の答えのほかに、(6:8:10)も表示される。 こういった答えを表示しないようにするにはどうすればよいか?

また、この2つのプログラムの処理時間を実際に比べてみる。

#include <stdio.h>
#include <time.h>

int main() {
   time_t start , end ;
   // time() 関数は、秒数しか求まらないので、
   // あえて処理を1000回繰り返し、数秒かかる処理にする。
   start = time( NULL ) ;
   for( int i = 0 ; i < 1000 ; i++ ) {
      // ただし、関数内のprintfをコメントアウトしておくこと
      integer_triangle( 100 ) ;
   }
   end = time( NULL ) ;
   printf( "%lf\n" , difftime( end , start ) ) ;
   return 0 ;
}

再帰プログラミング

組み合わせ問題では、forループの多重の入れ子で問題を解けない場合が多い。 (書けないことはないけど無駄なループで処理が遅くなるか、入れ子段数が可変にできない。)

こういった場合には、再帰プログラミングがよく利用される。 もっとも簡単な再帰の例として、階乗のプログラムを考える。 通常であれば、以下のような for ループで記述することになるだろう。

// 階乗の計算
int fact( int x )
{  // ループ
   int f = 1 ;
   for( int i = 2 ; i <= x ; i++ )
      f = f * i ;
   return f ;
}

再帰呼び出しでは、関数の処理の中に、自分自身の関数呼び出しが含まれる。 また、無限に自分自身を呼び出したら処理が止まらないので、 問題を一つ小さくして、これ以上小さくできないときは処理を止めるように記述する。

int fact( int x )
{  // 再帰呼び出し
   if ( x <= 1 )
      return 1 ;
   else
      return x * fact( x - 1 ) ;
}

ここ以降は、指定長さを指定辺の組み合わせで作る課題と、後に述べるFlood-fill 課題の選択とする。

指定長を指定辺の組み合わせで作る(テーマ1)

再帰を使った簡単なパズル問題として、以下のプログラムを作成したい。

配列の中に、複数の辺の長さが入っている。これを組み合わせて指定した長さを作れ。 使用する辺はできるだけ少ない方がよい。
int a[] = { 4 , 5 , 2 , 1 , 3 , 7 } ;
(例) 辺の長さ10を作るには、(5,4,1)とか(7,3)などが考えられる。
これは、ナップサック問題の基本問題で、容量の決まったナップサックに最大量入れる組合せを求めるのと同じである。

このプログラムを解くには…

10 を [4,5,2,1,3,7] で作るには...
 (0) 6=10-4 を [4|5,2,1,3,7]で作る。
 (1) 5=10-5 を [5|4,2,1,3,7]で作る。
 (2) 8=10-2 を [2|5,4,1,3,7]で作る。
 (3) 9=10-1 を [1|5,2,4,3,7]で作る。
 (4) 7=10-3 を [3|5,2,1,4,7]で作る。
 (5) 3=10-7 を [7|5,2,1,3,4]で作る。

そこで、ここまでの考えを、以下のようなプログラムで記述してみる。
# まだ再起呼び出しにはしていない。

// 指定されたデータを入れ替える。
void swap( int*a , int*b )
{  int x = *a ;
   *a = *b ;
   *b = x ;
}
void check( int array[] , int size , int len , int n )
{
   // array[] 配列
   // size    配列サイズ
   // len     作りたい長さ
   // n       使った個数
   for( int i = n ; i < size ; i++ ) {
      // i番目を先頭に...
      swap( &array[ n ] , &array[ i ] ) ;
      printf( "check( array , %d , %d , %d )\n" ,
              size , len - array[ n ] , n+1 ) ;
      // 最初のswapでの変更を元に戻す。
      swap( &array[ i ] , &array[ n ] ) ;
   }
}
int main() {
   int a[] = { 4 , 5 , 2 , 1 , 3 , 7 } ;
   check( a , 6 , 10 , 0 ) ;
}

(1) これを再帰呼び出しにしてみよう。どう書けばいい?

void check( int array[] , int size , int len , int n )
{
   // array[] 配列
   // size    配列サイズ
   // len     作りたい長さ
   // n       使った個数
   if ( len < 0 ) {
      // 指定した丁度の長さを作れなかった。
      ;
   } else if ( len == 0 ) {
      // 指定した長さを作れたので答えを表示。
      for( int i = 0 ; i < n ; i++ ) {
         printf( "%d " , array[ i ] ) ;
      }
      printf( "\n" ) ;
   } else {
      // 問題を一つ小さくして再帰。
      for( int i = n ; i < size ; i++ ) {
         swap( &array[ n ] , &array[ i ] ) ;
         printf( "check( array , %d , %d , %d )\n" ,
                 size , len - array[ n ] , n+1 ) ;
         check( array , size , len - array[ n ] , n + 1 ) ;
         swap( &array[ i ] , &array[ n ] ) ;
      }
   }
}

(2) 少ない組み合わせの方がポイントが高い場合には、プログラムをどう変更する?
(3) 答えが1つだけで良い場合は、プログラムをどう変更する?
(4) このプログラムでは、冗長な答えがあるか?ないか?検討せよ。
(5) 前設問の整数比直角三角形のプログラムで、冗長な答えを削除するプログラムを作成せよ。

# レポートでは、(2),(3),(4)を検討した結果を実験すること。(5)までチャレンジした人は(2),(3),(4)の説明は簡単に記載するだけで良い。

Flood fill アルゴリズム

前の問題は、今年度のプログラミングコンテストの課題のパズルとは、方向性が違うので、今年度のプロコンの競技部門に近いパズルネタで演習。(Wikipedia Flood-fill参照)

以下の image のような2次元配列が与えられたら、指定座標(x,y)を中心に周囲を塗りつぶす処理を作成せよ。

include <stdio.h>

// *は壁 SPCは白 この領域の指定位置を#で塗りつぶす。                            
char image1[10][10] = { // (4,4)始点で塗りつぶし後
        "*********" ,   // ********* 
        "*   *   *" ,   // *   *###*
        "*   *   *" ,   // *   *###*
        "*  *    *" ,   // *  *####*
        "***   ***" ,   // ***###***
        "*    *  *" ,   // *####*  *
        "*   *   *" ,   // *###*   *
        "*   *   *" ,   // *###*   *
        "*********" ,   // *********
} ;

char image2[10][10] = { // 応用問題用の画像例
        "*********" ,   //  *   のような隙間は通り抜けられる
        "*   *   *" ,   // *    ようにするにはどうすればいい?
        "*  **   *" ,   //   **
        "* **    *" ,   //  **  これは通り抜けられない
        "***   ***" ,   // **
        "*    *  *" ,
        "*   *   *" ,
        "*   *   *" ,
        "*********" ,
} ;

// 盤面を表示                                                                   
void print_image( char image[10][10] ) {
  for( int y = 0 ; y < 9 ; y++ ) {
    for( int x = 0 ; x < 9 ; x++ ) {
      printf( "%c" , image[y][x] ) ;
    }
    printf( "\n" ) ;
  }
}

// 再帰呼び出しを使った flud_fill アルゴリズム                                  
void flood_fill( char image[10][10] , int x , int y , char fill ) {
  // image: 塗りつぶす画像
  // x,y:   塗りつぶす場所
  // fill:  書き込む文字
  // 指定座標が空白なら
  if ( image[y][x] == ' ' ) {
    // その座標を埋める
    image[y][x] = fill ;
    //////////////////////////////////////
    // ここに周囲をflud_fillする処理を書く  //
    ////////////////////////////////////// 
  }
}

int main() {
  print_image( image1 ) ;
  flood_fill( image1 , 4 , 4 , '#' ) ;
  print_image( image1 ) ;
  return 0 ;
}

応用問題

Wikipediaのflood-fill のプログラムの説明のアルゴリズムでは、左図黒のような斜めに並んだブロックは、境界として通り抜けられないようにつくられている。

そこで、斜めに並んだブロックは通り抜けられるルールとした場合のプログラムを記述せよ。

レポート提出

レポートでは、指定長を辺の組み合わせで作るテーマか、Flood-fill のテーマのいずれかにて、以下の内容をまとめてレポートとして提出すること。

    • レポートの説明(自分の選んだテーマと自分なりの説明)
    • プログラムリスト
    • 動作確認の結果

サーヴェイとは(FD研修会)

発想法の指導に関するFD研修会

サーヴェイ

はじめに

  • 論理立てて思考する起点を見出すのがサーヴェイ
  • デザインの作ろうとする物事の仕組みや考えを論理立てて説明出来るための要
  • 自身が納得できて、説得するためではなく説明の基礎

アイデア・イメージメモ

  • 考えの写真・図・イラスト
  • コメント1(思いつき、気付き、疑問、不、好感、利点など)
  • コメント2(提案、発展、課題など)
  • その他

Surveyとは、

  • SurveyとResearchの違い
    • Research…研究・調査
      • 研究する、調査する
    • Survey …調査、探査、測量、実地踏査
      • 見渡す、概観する
    • field work …実地研究、野外調査、実地調査、現地調査、巡見
  • 探検・発見

ResearchとSurveyの相違

  • リサーチ
    • 準備して調べること
      • 縛りが強い、決め事がある
      • 客観的
      • 設定
      • 定数的
      • やや論理的
      • ロジカル、裏付け的
  • サーヴェイ
    • 特に準備なく体感すること
      • 縛りがゆるやか、決め事はない
      • 主観的
      • 想定
      • 定性的
      • 感覚的
      • エモーショナル、曖昧さがあっていい

Surveyでの留意点

  • サーヴェイは、情報・データを得る方法の1つ
  • 問題を発見する方法
  • ポイント
    • 先入観を持たずに概観(常識や固定観念をはずす)
      • 自分の経験や知識を一度仕舞い込む
      • 常識や規則、良識に囚われていないかと自分に問う
    • 自分の五感+αに素直(感じや思いを表出する)
      • 感じるがまま、思うがままを表現
      • 幼少時の感覚を思い起こす
        • 純真な子供に成り代わって素直に対象と接する
    • 気付き、思いつきをメモ
      • 記号化 – 話し言葉、書き言葉、絵、写真、図など「うつし」
        • 取捨選択をしない
        • あまり深く考えない
        • 結論や解を求めない
        • 評価しない
  • 気になることがない…という場合には
    • アイデアイメージを書けない理由
      • こんなことはできない、不可能だから言わない、提案しても採用されない…
    • 曼荼羅法→根拠理由を考えて再度行う
      • なぜ書けないを曼荼羅法で気づかせる
    • なぜ、どうしてと問わない。関わり、関係を考えない

Surveyからメモ作成での姿勢と方向

  • 対象の概観(観察)
  • 時間を区切る
    • (5) / 15 / (30) / 45 / 90 分
    • 5分でまとめる(連想法を5分で…)
    • 30分以上同じことをさせない
  • 自他の評価を考えない・行わない
  • 対象の良い点も悪い点も見つける
    • 曼荼羅法、
      • 3×3の表
      • 真ん中にテーマと気付き
      • その周り8コマにアイデア(上下左右にプラスマイナス)
    • プラスマイナスカード法、
    • Brain Writing法、
    • Brain Storming法(希望点列挙法,欠点列挙法)
  • 素直に問う
    • 気になることを「何だろう」「どうしてかな」と自問する
  • 話す・見せる
  • ▶︎サーヴェイによるデータ・資料作成のプロセスとなる

サーヴェイの位置付け・必要性・実施の意味

  • サーヴェイ
    • 問題の発見 … 問う「なぜ?」「どうして?」と疑問に思うこと
    • 問題の探索 … さぐる、さがす
    • 問題の把握 … 全貌と細部(ディテール、詳細) → 現状把握・確認
  • 「発想のネタ」、「創造のいとぐち」を見出すためのプロセスの最初の行為であり思考
  • サーヴェイと問題
    • 発見、把握、探索

サーヴェイの発散・収束の思考

  • イメージからアイデアに
    • 探索→発見→把握→探索…のスパイラルアップ
  • 感覚的から論理的に
  • 関係や関わりも探り考える(空間・場・時間・機会・遊・休・知・美・感・交・操・演)

発想を出す時のテクニック

  • Surveyする時の写真は、モノクロの方がいい
    • 余計な情報が先入観になってしまう
  • 写真にマーカーを入れる
    • マーク付けした所をもとに議論

 

創造工学演習発表会

創造工学演習

  • 07/30 (不明飛行物捕手) UFOキャッチャーのシミュレータをUnityで作成。UFOキャッチャーの有名な技をいくつか実践できることを目指した。(UFOキャッチャーに3000円ツッコム想定でレベル変化。俺は500円以上ツッコンだことない) #創造工学演習
  • 07/30 (不明飛行物捕手) UFOキャッチャーのシミュレータ #創造工学演習 https://twitter.com/TohruSaitoh/status/1…
  • 07/30 (Typing. edu) タイピング練習とプログラミングのためのタイピング? もう少しプログラミングの言語をイメージした練習ワードをでるようにして欲しかったり。でもこれは情報系ジジイ教員の感想ね。 #創造工学演習
  • 07/30 (sin Go!!) 信号はsignalとかsignだしsign(しん)go(ごー)じゃね? #創造工学演習
  • 07/30 (sin Go!!) 運転支援で信号の変化を予測できないか…。信号情報はVICSから取得したいが、そのハードは開発困難で想定データを受信できたとしてシステム構築。データが公開されている地域も限定的なのでデータフォーマットなども想定で作らざるおえなかったみたい。 #創造工学演習
  • 07/30 (sin Go!!) #創造工学演習 https://twitter.com/TohruSaitoh/status/1…
  • 07/30 (ideal idea) アイデア発想の支援するために、曼荼羅法などの機能を実装。関連ワードの検索で支援。検索結果の内容を評価ができれば高評価だけど…。関連ワード検索などは動くけど複数人の利用を想定したセッション管理は未実装かな。 #創造工学演習
  • 07/30 (ideal idea) #創造工学演習 https://twitter.com/TohruSaitoh/status/1…
  • 07/30 (UnEI-C) 学祭の運営の支援システム構築。発表がソフトコンペのような丁寧なアイデア提案型で始まったけど、全般にわたるいい説明ですな。1人説明だけどな。支援のためのページを簡単生成できるような自動化について議論が欲しかった。 #創造工学演習
  • 07/30 (UnEI-C) #創造工学演習 https://twitter.com/TohruSaitoh/status/1…
  • 07/30 質問者から「実際にお客さんにサービス提供したとして幾ら?」との質問。シビアな質問だけど、先日訪問した情報・経営システム工学課程なら、定番の質問だろうな。ま、本科4年では意識を持てるだけで充分。 #創造工学演習
  • 07/30 →ALL 自分たちで作ったもの写メってTweetしたかぁ?? #創造工学演習
  • 07/30 (忘れ物防止) RFIDで忘れ物防止システムの構築。発表は実装重視型かな。個人的には好きだけどね。グループで作るネタをうまく配分してたかな。 #創造工学演習
  • 07/30 (忘れ物防止) #創造工学演習 https://twitter.com/TohruSaitoh/status/1…
  • 07/30 (ceries) 複数の希望に応じた候補のランキングなどのアルゴリズムの説明が欲しい。Instagram連携にチャレンジしているのは女の子らしくってGoodだけど、そこは未完か…残念。 #創造工学演習
  • 07/30 (ceries) 週末デートをどうするか支援するアプリだとぉ〜。非リア充は土日は引きこもりなんだよ。 #創造工学演習
  • 07/30 (TCMS) 注文までのインタフェースは基本が完成していた。作るメニューの画面を写真とテキストを与えたら自動生成するなどの対応を期待。発注の流れをメールに割り切ったのは基本機能を完成させる点でアリかな。 #創造工学演習
  • 07/30 (競技部門) 敵の行動予測をしたい,先の手をもっと読ませたいとの目標だけど、同じじゃ無いか? 領域ポイントの戦略がこのゲームの面白さなので、フィールドスカスカのターン数のはず。スカスカな状態で終わるターン数でもっと戦略を試してほしい。 #創造工学演習

 

高専プロコン連携シンポジウム2019

〜セキュリティの観点からプロコンに期待すること〜

高専プロコンの応募に合わせ、以下のような講演会が開催されます。
今年度は、課題部門で「ICT を活用した地域活性化」,自由部門で「クラウドコンピューティング」「オープンデータ」「サイバーセキュリティ」「人工知能」がキーワードに挙げられており、高専生に現場のニーズや動向を学習する機会として、開催されます。

日  時: 5月20日(月) 16:20〜16:50
Skype for businessを用いた動画配信
学内場所: 電子情報工学科3F 情報処理演習室
講   師: 株式会社日立製作所
セキュリティ事業統括本部サイバーセキュリティ技術本部
セキュリティ人材統括センタセンタ長千葉寛之様
講演テーマ: セキュリティの観点からプロコンに期待すること
補   足: 発言・質問は、Twitter(ハッシュタグ #procon30 にて)受付

予備実験2 パズル問題

プログラミングコンテストの競技部門では、パズルのような組み合わせ問題が 出題されることが多い。そこで、この予備実験では、きわめて単純なパズル問題(組み合わせ問題) のプログラムについて扱う。

組み合わせ問題の基礎

簡単な問題として、「100未満の整数の値を3つ選び、その値を辺の長さとした場合、 直角三角形となるものをすべて表示する。」について考える。

一番簡単な方法は、以下となるであろう。

#include <stdio.h>
#include <math.h>
#include <time.h>

// 整数比の直角三角形の一覧を求める。
void integer_triangle( int n ) {
   for( int a = 1 ; a < n ; a++ ) {
      for( int b = 1 ; b < n ; b++ ) {
         // 一番ダサい方法
         for( int c = 1 ; c < n ; c++ ) {
            if ( a*a + b*b == c*c ) {
               printf( "%d %d %d\n" , a , b , c ) ;
            }
         }
      }
   }
}
int main() {
   integer_triangle( 100 ) ;
   return 0 ;
}

しかしこのプログラムの欠点としては、100×100×100回のループで無駄な処理が多い。

ループ回数を減らすだけなら、最も内側の処理を、計算で整数値か確認すればいい。

void integer_triangle( int n ) {
   for( int a = 1 ; a < n ; a++ ) {
      for( int b = 1 ; b < n ; b++ ) {
         // ココも改良できるよね?
         int d = a*a + b*b ;
         int c = (int)sqrt( d ) ;
         // 斜辺Cの整数値を求め、改めて確認する。
         if ( c*c == d ) {
            printf( "%d %d %d\n" , a , b , c ) ;
         }
      }
   }
}

(1) 計算誤差の問題を考えてみよう。

たとえば、3:4:5の直角三角形で、3*3+4*4 = 25 だが、sqrt(25)は実数で計算するから、 計算誤差で4.99999で求まったらどうなるだろうか?

1~100までの数値で、”int a = sqrt( (double)(i*i) ) ;” を計算してみて、 異なる値が求まることはあるか? 多少の計算誤差があっても正しく処理が行われるにはどうすればいいか、考えてみよう。

(2) 無駄な答えについて考えてみよう。

このプログラムの答えでは、簡単な整数比の答えの「整数倍の答え」も表示されてしまう。 たとえば、(3:4:5)の答えのほかに、(6:8:10)も表示される。 こういった答えを表示しないようにするにはどうすればよいか?

また、この2つのプログラムの処理時間を実際に比べてみる。

int main() {
   time_t start , end ;
   // time() 関数は、秒数しか求まらないので、
   // あえて処理を1000回繰り返し、数秒かかる処理にする。
   start = time( NULL ) ;
   for( int i = 0 ; i < 1000 ; i++ ) {
      // ただし、関数内のprintfをコメントアウトしておくこと
      integer_triangle( 100 ) ;
   }
   end = time( NULL ) ;
   printf( "%lf\n" , difftime( end , start ) ) ;
   return 0 ;
}

再帰プログラミング

組み合わせ問題では、forループの多重の入れ子で問題を解けない場合が多い。 (書けないことはないけど無駄なループで処理が遅くなるか、入れ子段数が可変にできない。)

こういった場合には、再帰プログラミングがよく利用される。 もっとも簡単な再帰の例として、階乗のプログラムを考える。 通常であれば、以下のような for ループで記述することになるだろう。

// 階乗の計算
int fact( int x )
{  // ループ
   int f = 1 ;
   for( int i = 2 ; i <= x ; i++ )
      f = f * i ;
   return f ;
}

再帰呼び出しでは、関数の処理の中に、自分自身の関数呼び出しが含まれる。 また、無限に自分自身を呼び出したら処理が止まらないので、 問題を一つ小さくして、これ以上小さくできないときは処理を止めるように記述する。

int fact( int x )
{  // 再帰呼び出し
   if ( x <= 1 )
      return 1 ;
   else
      return x * fact( x - 1 ) ;
}

ここ以降は、指定長さを指定辺の組み合わせで作ると、Flood-fill の選択とする。

指定長を指定辺の組み合わせで作る

再帰を使った簡単なパズル問題として、以下のプログラムを作成したい。

配列の中に、複数の辺の長さが入っている。これを組み合わせて指定した長さを作れ。 使用する辺はできるだけ少ない方がよい。
int a[] = { 4 , 5 , 2 , 1 , 3 , 7 } ;
(例) 辺の長さ10を作るには、(5,4,1)とか(7,3)などが考えられる。
これは、ナップサック問題の基本問題で、容量の決まったナップサックに最大量入れる組合せを求めるのと同じである。

このプログラムを解くには…

10 を [4,5,2,1,3,7] で作るには...
 (0) 6=10-4 を [5,2,1,3,7]で作る。
 (1) 5=10-5 を [4,2,1,3,7]で作る。
 (2) 8=10-2 を [5,4,1,3,7]で作る。
 (3) 9=10-1 を [5,2,4,3,7]で作る。
 (4) 7=10-3 を [5,2,1,4,7]で作る。
 (5) 3=10-7 を [5,2,1,3,4]で作る。

そこで、ここまでの考えを、以下のようなプログラムで記述してみる。

// 指定されたデータを入れ替える。
void swap( int*a , int*b )
{  int x = *a ;
   *a = *b ;
   *b = x ;
}
void check( int array[] , int size , int len , int n )
{
   // array[] 配列
   // size    配列サイズ
   // len     作りたい長さ
   // n       使った個数
   for( int i = n ; i < size ; i++ ) {
      // i番目を先頭に...
      swap( &array[ n ] , &array[ i ] ) ;
      printf( "check( array , %d , %d , %d )\n" ,
              size , len - array[ n ] , n+1 ) ;
      // 最初のswapでの変更を元に戻す。
      swap( &array[ i ] , &array[ n ] ) ;
   }
}
int main() {
   int a[] = { 4 , 5 , 2 , 1 , 3 , 7 } ;
   check( a , 6 , 10 , 0 ) ;
}

(1) これを再帰呼び出しにしてみよう。どう書けばいい?

void check( int array[] , int size , int len , int n )
{
   // array[] 配列
   // size    配列サイズ
   // len     作りたい長さ
   // n       使った個数
   if ( len < 0 ) {
      // 指定した丁度の長さを作れなかった。
      ;
   } else if ( len == 0 ) {
      // 指定した長さを作れたので答えを表示。
      for( int i = 0 ; i < n ; i++ ) {
         printf( "%d " , array[ i ] ) ;
      }
      printf( "\n" ) ;
   } else {
      // 問題を一つ小さくして再帰。
      for( int i = n ; i < size ; i++ ) {
         swap( &array[ n ] , &array[ i ] ) ;
         printf( "check( array , %d , %d , %d )\n" ,
                 size , len - array[ n ] , n+1 ) ;
         check( array , size , len - array[ n ] , n + 1 ) ;
         swap( &array[ i ] , &array[ n ] ) ;
      }
   }
}

(2) 少ない組み合わせの方がポイントが高い場合には、プログラムをどう変更する?
(3) 答えが1つだけで良い場合は、プログラムをどう変更する?
(4) このプログラムでは、冗長な答えがあるか?ないか?検討せよ。
(5) 前設問の整数比直角三角形のプログラムで、冗長な答えを削除するプログラムを作成せよ。
# ただし、(2)〜(5)は、演習の実験の時間内でできる範囲とする。

Flood fill アルゴリズム

前の問題は、今年度のプログラミングコンテストの課題のパズルとは、方向性が違うので、今年度のプロコンの競技部門に近いパズルネタで演習。(Wikipedia Flood-fill参照)

以下の image のような2次元配列が与えられたら、指定座標(x,y)を中心に周囲を塗りつぶす処理を作成せよ。

include <stdio.h>

// *は壁 SPCは白 この領域の指定位置を#で塗りつぶす。                            
char image1[10][10] = { // (4,4)始点で塗りつぶし後
        "*********" ,   // ********* 
        "*   *   *" ,   // *   *###*
        "*   *   *" ,   // *   *###*
        "*  *    *" ,   // *  *####*
        "***   ***" ,   // ***###***
        "*    *  *" ,   // *####*  *
        "*   *   *" ,   // *###*   *
        "*   *   *" ,   // *###*   *
        "*********" ,   // *********
} ;

char image2[10][10] = { // 応用問題用の画像例
        "*********" ,   //  *   のような隙間は通り抜けられる
        "*   *   *" ,   // *    ようにするにはどうすればいい?
        "*  **   *" ,   //   **
        "* **    *" ,   //  **  これは通り抜けられない
        "***   ***" ,   // **
        "*    *  *" ,
        "*   *   *" ,
        "*   *   *" ,
        "*********" ,
} ;

// 盤面を表示                                                                   
void print_image( char image[10][10] ) {
  for( int y = 0 ; y < 9 ; y++ ) {
    for( int x = 0 ; x < 9 ; x++ ) {
      printf( "%c" , image[y][x] ) ;
    }
    printf( "\n" ) ;
  }
}

// 再帰呼び出しを使った flud_fill アルゴリズム                                  
void flood_fill( char image[10][10] , int x , int y , char fill ) {
  // 指定座標が空白なら
  if ( image[y][x] == ' ' ) {
    // その座標を埋める
    image[y][x] = fill ;
    //////////////////////////////////////
    // ここに周囲をflud_fillする処理を書く  //
    ////////////////////////////////////// 
  }
}

int main() {
  print_image( image1 ) ;
  flood_fill( image1 , 4 , 4 , '#' ) ;
  print_image( image1 ) ;
  return 0 ;
}

応用問題

Wikipediaのflood-fill のプログラムの説明のアルゴリズムでは、左図黒のような斜めに並んだブロックは、境界として通り抜けられないようにつくられている。

そこで、斜めに並んだブロックは通り抜けられるルールとした場合のプログラムを記述せよ。

予備実験1 データベースの操作

データベースの基本操作

データベースをWebから操作

練習問題

  1. 上記の db_query.php を改良して、ユーザ名を入力してもらい、その名前のデータを表示するプログラムに改造する。
  2. おなじく、年齢を入力したら、指定した年齢以上の人のデータを表示するプログラムに改良する。

創造工学演習・予備実験(SQLとPHP)

先週のPHPの予備実験に引き続き、データベースの説明とそのプログラムで演習を行う。

<?php
// データの保存先
$dbfile = "/home/guests/guest0/public_data/tsaitoh.db" ;

if ( !file_exists( $dbfile ) ) {
   // データベースの宣言と初期化
   $db = new SQLite3( $dbfile ) ;
   $cmd = "create table nametel ( name char( 20 ) , phone char( 20 ) ) ;"
        ."insert into nametel ( name , phone ) values ( 't-saitoh' , '090-1111-1111' ) ;"
        ."insert into nametel ( name , phone ) values ( 'tomoko' , '090-2222-2222' ) ;"
        ."insert into nametel ( name , phone ) values ( 'mitsuki' , '090-3333-3333' ) ;"
        ."insert into nametel ( name , phone ) values ( 'ayuka' , '090-4444-4444' ) ;"
        ;
   if ( $db->exec( $cmd ) ) {
      print "Success.\n" ;
   } else {
      print "Fail\n" ;
   }
   $db = null ;
}
?>
<html>
<head>
<title></title>
</head>
<body>

<?php
// 警告表示の抑止
ini_set( 'error_reporting' , E_WARNING ) ;

// データベース処理(検索処理)
$db = new SQLite3( $dbfile ) ;
$id = $_REQUEST[ "name" ] ;
if ( $db !== FALSE && $id != "" ) {
   // SQL命令の生成(インジェクションの危険性指摘は別述)
   $cmd = "select * from nametel where name='$id' ;" ;
   print $cmd ;
   // 問い合わせの実行
   $result = $db->query( $cmd ) ;
   print "<table border='1'>\n" ;
   print "<tr><td>name</td><td>phone</td></tr>" ;
   while( ($row = $result->fetchArray( SQLITE3_BOTH )) !== FALSE ) {
      print "<tr>"
         ."<td>".$row[0]."</td>"
         ."<td>".$row[1]."</td>"
         ."</tr>\n" ;
   }
   print "</table>\n" ;
}
?>

<form method="post" action="sql.php">
<input type="text" name="name" />
<input type="submit" value="exec" />
</form>

<?php
// データベース登録処理
$newname = $_REQUEST[ "newname" ] ;
$newphone = $_REQUEST[ "newphone" ] ;
if ( $newname != "" && $newphone != "" ) {
   // データ登録用SQL
   $cmd = "insert into nametel ( name , phone ) values ( '$newname' , '$newphone' ) ;" ;
   // データ登録
   $db->exec( $cmd ) ;
      print "$newname さんの電話番号 $newphone を登録しました" ;
   }
?>

<form method="post" action="sql.php">
<input type="text" name="newname" />
<input type="text" name="newphone" />
<input type="submit" value="exec" />
</form>

</body>
</html>

sakura.ioでIT人材育成

さくらインターネット様による高専のIT教育支援を受け、sakura.io,Arduino用シールド,IchigoJam が届きました。

これらの機材を使い、電子回路からインターネットへと幅広い開発の経験から、創造的IT人材育成にチャレンジします。

{CAPTION}

IT教育支援の共同研究(H30年3月まで)として、以下のテーマに取組みます。

  • sakura.ioを用いた、低学年でのIoT連携実験
  • おなじく、高学年での創造的なシステム構築演習
  • さくらのクラウドを用いた、クラウド環境実験
  • これらを応用した卒業研究