package sspd; use strict; #---------------------------------------- # 人工無脳『精霊石』試作D型 sspd-301 # 短期記憶実装試験 #------------------------------- ユーザ定義 ------------------------------- $sspd::Name ="muno"; # 人工無脳の名前 $sspd::UName ="user"; # ユーザの名前 $sspd::RenderDicPath ="render.dic"; # レンダリング辞書 $sspd::WorldDicPath ="world.dic"; # 知識辞書 $sspd::DeckS ="TTTTIKS"; # 起点デッキ $sspd::DeckI ="IITTRNP"; # Iデッキ (with TIRNK) $sspd::DeckT ="TTIICRS"; # Tデッキ (with TIRNK) $sspd::UIW =2; # ユーザ発言の重み $sspd::Curios =2; # 未知の単語の重み(好奇心) $sspd::NotFoundLog ="notfound.txt"; # NotFoundログ #------------------------------ 要持続性変数 ------------------------------ $sspd::STM ="-:-:-:-:-:-:-"; # 短期記憶 $sspd::LastOutput =""; # ひとつ前の無脳発言 $sspd::LastInput =""; # ひとつ前のユーザ発言 $sspd::Queue =""; # 発言のキュー $sspd::Message =""; # メッセージ #------------------------------- 内部変数 --------------------------------- $sspd::LastCard ="-"; %sspd::Dictionary=(); @sspd::WorldDicKey=(); #-------------------------------------------------------------------------- %sspd::RenderTable=( 'T'=>'$TELL$', 'I'=>'$INQUIRE$', 'R'=>'$RECALL$', 'C'=>'$COUNTER$', 'K'=>'$KIDDING$', 'W'=>'$WARNING$', 'H'=>'$THANKS$', 'S'=>'$START$', 'P'=>'$PROMPT$', 'N'=>'$NOT_FOUND$' ); sub _load() { return if $#sspd::Dictionary>0; open (DICT,$sspd::WorldDicPath) or die "$sspd::WorldDicPath not found"; while() { /^([^ ]+) ([^\n]+)/ && do{$sspd::Dictionary{$1}=$2;}; } close DICT; @sspd::WorldDicKey= keys %sspd::Dictionary; open (DICT,$sspd::RenderDicPath) or die "$sspd::RenderDicPath not found"; while() { /^([^ ]+) ([^\n]+)/ && do{$sspd::Dictionary{$1}=$2;}; } close DICT; } sub _queue($) { $sspd::Queue=shift; ""; } sub _dequeue() { $sspd::Queue=""; ""; } sub _post($) { $sspd::Message=shift; } sub get_season { my $m=$LocalTime[4]; ($m>=3)+($m>=6)+($m>=9)-3*($m==12); } sub get_zone { my $h=$LocalTime[2]; ($h>=7)+($h>=10)+($h>=11)+($h>=14)+($h>=19)-5*($h>=22); } sub get_vcond { int(2*sin(2*3.14159*time/($VCondInterv*60*60*24))+3.5); } sub get_vclim { int(2*sin(2*3.14159*time/($VWeather*60*60*24))+3.5); } sub get_birthday { my @bd=localtime $Birthtime; "$bd[4]/$bd[2]"; } sub get_age { sprintf("%3.2f",(time-$Birthtime)/(365.25*24*60*60)) } sub expand($) { my $key=shift; my @value=split(/,/, $sspd::Dictionary{$key}); my $str=$value[rand($#value)]; $str =~ s/\%uname\%/$sspd::UName/g; $str =~ s/\%name\%/$sspd::Name/g; $str =~ s/\%sec\%/$LocalTime[0]/g; $str =~ s/\%min\%/$LocalTime[1]/g; $str =~ s/\%hour\%/$LocalTime[2]/g; $str =~ s/\%date\%/$LocalTime[3]/g; $str =~ s/\%month\%/$LocalTime[4]/g; $str =~ s/\%year\%/$LocalTime[5]/g; $str =~ s/\%day\%/$LocalTime[6]/g; $str =~ s/\%season\%/ &get_season /eg; $str =~ s/\%zone\%/ &get_zone /eg; $str =~ s/\%vcond\%/ &get_vcond /eg; $str =~ s/\%vclim\%/ &get_vclim /eg; $str =~ s/\%birthday\%/ &get_birthday /eg; $str =~ s/\%age\%/ &get_age /eg; # $str =~ s/\%freq\%/ &get_freq /eg; $str =~ s/\%key\%/$sspd::_KEY_/g; $str =~ s/\%content\%/$sspd::_CONTENT_/g; $str =~ s/\%queue ([^\n]+)\%/ &_queue($1) /ge; $str =~ s/\%dequeue\%/ &_dequeue /ge; $str =~ s/\%post ([^\n\% ]+)\%/ &_post($1) /ge; $str =~ s/(\$[^ \$]+\$)/ &expand($1) /ge; return $str; } sub decision($) { my $input=shift; return "W'DONT_COPY_ME'" if $input eq $sspd::LastOutput; return "W'DONT_REPEAT'" if $input eq $sspd::LastInput; my $LastCmd=substr $sspd::LastCard,0,1; # デッキによる意思決定 my $NextCmd; if ($LastCmd eq 'T') { $NextCmd=substr($sspd::DeckT,rand(length($sspd::DeckT)),1); } elsif($LastCmd eq 'I') { $NextCmd=substr($sspd::DeckI,rand(length($sspd::DeckI)),1); } else { $NextCmd=substr($sspd::DeckS,rand(length($sspd::DeckS)),1); } if ($NextCmd eq "H") { return "H"; } elsif($NextCmd eq "K") { return "K"; } elsif($NextCmd eq "S") { return "S"; } elsif($NextCmd eq "C") { my $stm=$sspd::STM.":"; while($stm=~ s/^([^:'])([^:']*)(?:'([^']*)')://) { if($1 eq "T" || $1 eq "I") { return "C". ($2 ne "") ? $2 : $3; } } return "W'I_FORGOT_COUNTER'"; } elsif($NextCmd eq "R") { my $stm=":".$sspd::STM; while($stm=~ s/:([^:'])([^:']*)(?:'([^']*)')$//) { if($1 eq "T" || $1 eq "I") { return "R". ($2 ne "") ? $2 : $3; } } return "W'I_FORGOT_RECALL'"; } # I or T my @assoc; my $arg=""; my $i=0; foreach my $key (@sspd::WorldDicKey) { if($sspd::LastOutput =~/$key/) { push @assoc,$i; } $i++; } $i=0; foreach my $key (@sspd::WorldDicKey) { if($input =~/$key/) { for(1..$sspd::UIW) { push @assoc,$i; } } $i++; } if($NextCmd eq 'I') { for(1..$sspd::Curios) { push @assoc,"%unknown_words%"; } } if($#assoc == -1) { return "N"; } my $index=rand($#assoc); if($assoc[$index] eq '%unknown_words%') { # 未知の単語の抽出 # 未実装 return $NextCmd."'unknown_words'"; } return $NextCmd.$assoc[$index]; } sub render($) { my $input=shift; my $cmd=substr($input,0,1); my $arg=substr($input,1); $arg=~ s/^'//; $arg=~ s/'$//; return "\$$arg\$" if $cmd eq "W"; if($arg ne "") { $sspd::_KEY_ = $sspd::WorldDicKey[$arg]; $sspd::_CONTENT_=$sspd::WorldDic{$sspd::_KEY_}; } return "$sspd::RenderTable{$cmd}"; } sub reply($) { my $input=shift; my ($speach,$next); @LocalTime=localtime(time); _load; if($sspd::Queue ne "") { $speach=expand $sspd::Queue; $sspd::Queue=""; } else { $sspd::STM =~ m/^([^:']*(?:'[^']*')?)/; $sspd::LastCard=$1; my $next=decision $input; $sspd::STM =~ s/:[^:']*(?:'[^']*')?$//; $sspd::STM = $next.":".$sspd::STM; $speach=expand render $next; } $sspd::LastInput=$input; $sspd::LastOutput=$speach; print "[$sspd::STM]"; return $speach; }