Portal:siro

ダイレクトマーケティングブログ

ちぃサイラスBOT制作:感情機能の実装と感情に応じた発言の実装

前回:
ちぃサイラスBOT制作:1時間に1回喋るようにする(cron) - Portal:siro
http://d.hatena.ne.jp/siro_xx/20110516/1305551951

Reply反応を付ける前に、先に感情の実装を行います。
今回ちぃサイラスにくっつける感情パターンは、とりあえずですが、
・うれしい
・おこった
・かなしい
・たのしい
の喜怒哀楽に、
・ねむたい
・はらぺこ
・さみしい
・すやすや
の追加4種、合計8パターンとなります。

1.感情の実装(準備)

データベースに「chi_silas_status」というテーブルを作成します。
単純に「現在の感情」を保持するだけでしたらファイルでも問題ないのですが、折角ですので「いつ、どういう風に」感情が変化したのかという記録を取りたいと思います。

テーブルのカラムは、id(通し番号:PK,auto increment)、date(日時:UK)、emotion(感情:NotNull)、cause(原因:NotNull)、causePerson(原因となった人物)という感じで作ります。


また、chi_silas_randomListにemotionというカラムを1つ追加します。
この台詞は「たのしい」時に言う台詞だということをちまちまと記録していきます。
まだ台詞数が少ないので楽ですが、メンテを考えるとちょっと方法を考えたほうがいいかもしれません。


2.感情の実装(暫定)

と言ってもまだReply対応していないですし、とりあえずは簡単に以下の条件でソースコードを修正します。
・0時〜8時まで:すやすや
・すやすやの前後2時間(現在は8時〜10時,22時〜0時):ねむたい
・12時:はらぺこ
・15時:はらぺこ
・19時:はらぺこ
・その他:「うれしい」「おこった」「かなしい」「たのしい」「さみしい」からランダム

3.感情の実装(実装)

毎時喋る処理の前に、時刻変化により現在の感情をセットする関数を作ります。
時刻変化によりセットする感情を決める関数と、セットする関数は別に作ります。
(セットする関数は後々別の処理でも使うため)

現在時刻取得にはgetdate()関数というのがありますので、それを使います。

function emotionTimer(){
  // 現在時刻によって感情を変化させる
  $now = getdate();
  switch($now["hours"]){
  	case 0:
  	case 1:
  	case 2:
  	case 3:
  	case 4:
  	case 5:
  	case 6:
  	case 7:
  		$emotion = "すやすや";
  		break;
  	case 8:
  	case 9:
  	case 22:
  	case 23:
  		$emotion = "ねむたい";
  		break;
  	case 12:
  	case 15:
  	case 19:
   		$emotion = "はらぺこ";
  		break;
  	default:
  		// 「うれしい」「おこった」「かなしい」「たのしい」「さみしい」からランダム
  		$random = rand(0,4);
  		if($random == 0){
  			$emotion = "うれしい";
  		}else if($random == 1){
  			$emotion = "おこった";
  		}else if($random == 2){
  			$emotion = "かなしい";
  		}else if($random == 3){
  			$emotion = "たのしい";
  		}else if($random == 4){
  			$emotion = "さみしい";
  		}
  		break;
  }
  emotionUpdate($emotion,"時報","");
}

感情をセットする関数はざっとこんな感じです。
相変わらずソースが初心者丸出しで美しくないね!!!!! 美しいソースってどうやったら書けるんだいハニー。


次にセットする関数を作ります。
一番単純なやり方は、問答無用でupdate掛けていくことなのですが、1時:すやすや、2時:すやすや、3時:すやすや……と記録してもあまり面白くないので、変化があったときのみ書き込むという方法を取ります。


やり方は単純で、データベースに接続して直前(つまり現在の)感情を取得します。
直前の感情は最新(最大)のidを持っているはずなので、SQL文は多分こんな感じ……。

SELECt emotion 
FROM chi_silas_status 
WHERE id = 
  (SELECT max(id) 
   FROM chi_silas_status)

シロさんは副問い合わせが苦手なのでこのSQL文実行するまで動くのかわかりません……。

てなわけでこんな感じになります。

function emotionUpdate($emotion,$cause,$causePerson){
	$emotionPrev = "みていぎ";
	
	$conn = mysql_connect("****","****","****");
	if($conn !== false){
		// おまじない
		mysql_select_db("****",$conn);
		mysql_query("SET NAMES UTF8");
		$query = mysql_query("select emotion from chi_silas_status where id = (select max(id) from chi_silas_status)");
		$obj = mysql_fetch_object($query);
		$emotionPrev = $obj->emotion;
		mysql_close($conn);
	}

	if($emotionPrev !== $emotion){
		// 直前の感情と新しい感情が異なる場合、更新する
		$conn = mysql_connect("****","****","****");
		if($conn !== false){
			// おまじない
			mysql_select_db("****",$conn);
			mysql_query("SET NAMES UTF8");
			$query = mysql_query("insert into chi_silas_status(date,emotion,cause,causePerson) values (NOW(),'" . $emotion . "','" . $cause . "','" . $causePerson . "')");
			mysql_close($conn);
		}
	}
}

接続を関数化してまとめるのは次回やるのでちょっと長いコードなのは許してください。
……何処をまとめるのがいいと思いますかね?どうしても個別にやらないといけない処理が多すぎるので、接続をラッパー関数にするってのくらいしか思いつかないんですけど。


最後に、自動発言部分を弄ります。
これまで使っていたCOUNT(*)が単純に使えないので、SELECT FROM 現在の感情で絞ったあと、その中からランダムで1発言選ぶ方法を考えます。
前の記事で遠まわしに無駄が多いとdisりましたが、今回は件数も少ないのでRAND()を使います。

SELECT string 
FROM chi_silas_randomList 
WHERE emotion = '現在の感情' 
ORDER BY RAND() 
LIMIT 1


そうするとソースコード全体では以下のようになります

<?php
// 外部ファイル読み込み
require_once "Services/Twitter.php";
require_once "Services/twitteroauth.php";

// 基本部分
$st =& new Services_Twitter(
/* 省略 */
TRUE );

// ランダム発言部
// 発言はDBから取得

// 現在の感情を決定
emotionTimer();
// DBに接続
$talk_conn = mysql_connect(/* 省略 */);
if($talk_conn !== false){
	// おまじない
	mysql_select_db(/* 略 */,$talk_conn);
	mysql_query("SET NAMES UTF8");
	// 今の感情を取得
	$emo_query = mysql_query("select emotion from chi_silas_status where id = (select max(id) from chi_silas_status)");
	$obj = mysql_fetch_object($emo_query);
	$emotion = $obj->emotion;
	// 今の感情と合致する台詞を喋る
	$talk_query = mysql_query("select string from chi_silas_randomList where emotion = '" . $emotion . "' order by RAND() limit 1");
	$talk_obj = mysql_fetch_object($talk_query);
	$st->setUpdate($talk_obj->string);
	mysql_close($talk_conn);
}


function emotionTimer(){
  // 現在時刻によって感情を変化させる
  $now = getdate();
  switch($now["hours"]){
  	case 0:
  	case 1:
  	case 2:
  	case 3:
  	case 4:
  	case 5:
  	case 6:
  	case 7:
  		$emotion = "すやすや";
  		break;
  	case 8:
  	case 9:
  	case 22:
  	case 23:
  		$emotion = "ねむたい";
  		break;
  	case 12:
  	case 15:
  	case 19:
   		$emotion = "はらぺこ";
  		break;
  	default:
  		// 「うれしい」「おこった」「かなしい」「たのしい」「さみしい」からランダム
  		$random = rand(0,4);
  		if($random == 0){
  			$emotion = "うれしい";
  		}else if($random == 1){
  			$emotion = "おこった";
  		}else if($random == 2){
  			$emotion = "かなしい";
  		}else if($random == 3){
  			$emotion = "たのしい";
  		}else if($random == 4){
  			$emotion = "さみしい";
  		}
  		break;
  }
  emotionUpdate($emotion,"時報","");
}


function emotionUpdate($emotion,$cause,$causePerson){
	$emotionPrev = "みていぎ";
	
	$conn = mysql_connect(/* 略 */);
	if($conn !== false){
		// おまじない
		mysql_select_db(/* 略 */,$conn);
		mysql_query("SET NAMES UTF8");
		$query = mysql_query("select emotion from chi_silas_status where id = (select max(id) from chi_silas_status)");
		$obj = mysql_fetch_object($query);
		$emotionPrev = $obj->emotion;
		mysql_close($conn);
	}

	if($emotionPrev !== $emotion){
		// 直前の感情と新しい感情が異なる場合、更新する
		$conn = mysql_connect(/* 略 */);
		if($conn !== false){
			// おまじない
			mysql_select_db(/* 略 */,$conn);
			mysql_query("SET NAMES UTF8");
			$query = mysql_query("insert into chi_silas_status(date,emotion,cause,causePerson) values (NOW(),'" . $emotion . "','" . $cause . "','" . $causePerson . "')");
			mysql_close($conn);
		}
	}
}

?>


時報つけたので、1日以上様子見でテスト試運転させてみます。
結果は以下の通り。

TLはこんな感じ。(5/19 07:46時点)


ねっ、簡単でsy

次は各人に対する好感度の記憶と管理の機能をつけたいと思います。
リプライ機能はそれらが全部終わるまで、待って、ください、ね……!