#!/usr/local/bin/perl use strict; # いずれかを有効にする。 require 'jcode.pl'; # use Jcode; # 入力関連の関数 my ($buffer,%FORM,$THIS_SCRIPT,%CHECKED); $THIS_SCRIPT = "http://$ENV{'SERVER_NAME'}$ENV{'SCRIPT_NAME'}"; # $THIS_SCRIPT = 'http://hpcgi1.nifty.com/Iruka/ENV_FORM.cgi'; # 処理関数 my ($key,$ref,@allMembers,@GamesList,%ThisGame,$mode); # 出力関数 my ($orderOutput,@inputError,$GameNumber,%MembersList,%Count,$GamesTableData,$membersTableData,$Links, @ListGameList,@ListSortedGameList,@ListMembersList,$membersCSV,$gameCSV,$form,$Abstract,$naviList); if( $ENV{'PATH_INFO'} =~ m#help.html?#i ){ $Links = qq~\t\t
    \t
  1. 配布サイトホーム
  2. \t
  3. CGI目次へ
  4. \t
  5. メンバーCGIへ
  6. \t
  7. 携帯用メンバーCGIへ
  8. \t
  9. ヘルプ
  10. \n\t\t
\n~; } else{ $Links = qq~\t\t
  1. ホーム
  2. \t
  3. ヘルプ
  4. \n\t\t
\n~; } my $DocumentInfo =qq~

文書情報

\n$Links\t\t
\t
First Published
\t
2009-03-18
\t
Last Modified
\t
2009-04-06 12:00:00 (JST)
\n~; # 初期値 my $formMax = '55'; my $gameTableTitle = 'G\M'; my $memberTableTitle = 'M\G'; my $memberTableTotal = 'Total'; my $gameName = ''; my $memberName = ''; my $group = 10; my $member=6; my $random='limit'; my %url=(); $GameNumber = '0'; my $Num=$#allMembers+1; if ($ENV{'REQUEST_METHOD'} eq "POST") { read(STDIN,$buffer,$ENV{'CONTENT_LENGTH'}); } else { $buffer = $ENV{'QUERY_STRING'}; } if($ENV{'PATH_INFO'}=~ m#help.html?#i ){&HELP;} else{ if( $ENV{'PATH_INFO'}=~ m#tty#i ){$mode = 'tty';} if($buffer ne ''){ &INPUT;} &FORM_check; &makeNaviList; print "Pragma: no-cache\nCache-Control: no-cache\nExpires: -1\nContent-type: text/html\; charset=euc-jp\n\n"; &printTopMessage; if( $buffer ){ if( $#inputError >= 0){&printErrorMessage;&makeForm;print $form,"\n";} else{ &makeOrderList; @ListGameList = (); for (@GamesList) {push @ListGameList, [ @$_ ];} @ListGameList = &makeOutputData(@ListGameList); @ListSortedGameList = (); for (@GamesList) { push @ListSortedGameList, [ sort {$a <=> $b} @$_ ]; } @ListSortedGameList = &makeOutputData(@ListSortedGameList); @ListMembersList = &makeOutputMemberHash; $GamesTableData = qq~
\n\t\t

組み合わせ結果(Table)

\n\t\t

一部修正しての再計算は上の入力フォームを書き換えてください。すべての値を書き換える場合は元のページに戻ってください。\n\t\t

~; if($orderOutput == 1){ $GamesTableData.=&makeTable('ゲーム',@ListSortedGameList); } else{ $GamesTableData.=&makeTable('ゲーム',@ListGameList); } $membersTableData.=&makeTable('メンバー',@ListMembersList); if($orderOutput == 1){ $gameCSV .= &makeCSV('ゲーム',@ListSortedGameList); } else{ $gameCSV .= &makeCSV('ゲーム',@ListGameList); } $membersCSV .= &makeCSV('メンバー',@ListMembersList); &makeForm; print qq~$form\n~; print qq~$GamesTableData\n$membersTableData\n$naviList\n\t
\n\t\t
\n~; unless( $mode eq 'tty'){ print qq~\t
\n\t\t

組み合わせ結果(CSV)

\n\t\t\t

一部修正しての再計算は上の入力フォームを書き換えてください。すべての値を書き換える場合は元のページに戻ってください。\n\t\t\t\t

\n\t\t\t\t\t\tMS office Excell形式のCSVです。下記文字列をドラッグして選択しコピーし、それを、そのままエクセルに貼り付ける。そのときテキストウィザードを使用すると表として貼り付けられる。

$gameCSV\n$membersCSV\n$naviList\t
\n
\n~; } } } else{ &printAbstract; &makeForm; print $form,"\n"; } } &printEndMessage; print "\n\n\n"; sub printErrorMessage{ my $count = $#inputError + 1; print qq~\t

入力に間違いがあります。

\n\t\t\t入力に$count箇所、間違いがあります。訂正してください。\n\t\t

\n\t\t

エラー

\n\t\t\t詳しい説明はヘルプをご覧ください。\n\t\t

$naviList\n\t
\n~; } sub makeNaviList{ $naviList=qq~\t\t\n~; } sub makeCSV{ my @IN_Data = @_; my $message=shift @IN_Data; my $kind; if($message eq 'メンバー'){ $kind='membersCSV';} else{$kind='gamesCSV';} my $CSV = qq~

$message一覧CSV

~;
	for $ref(0..$#IN_Data){
		$CSV .= join ',', map {(s/"/""/g or /[\r\n,]/) ? qq("$_") : $_} @{$IN_Data[$ref]};
		$CSV =~ s/<\/?small>//g;

		$CSV .="\n";
	}
	$CSV .=qq~
~; return $CSV; } sub makeForm{ $form = qq~\t
\n\t\t

入力フォーム

\t\n~; unless( $mode eq 'tty'){ $form .= qq~\t\t\n\t\t\t\t\t \t\t\n\t\t\t\t\n~; } $form .= qq~\t\t\t\t\n\t\t\t\t\t\n~; } else{ $form .= qq~\t\t\t\t\t\t番号 \t\t\n~; } $form .= qq~\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t \t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t \t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
\t\t(ゼッケン)名前\n\t\t\t\t\t\t

\n\t\t\t\t\t\t\t"(ゼッケン)名前"欄は名前だけでも良い。 \t\t\t\tカンマ(,)を間にゼッケンを書いておくとゼッケン順に並べ替えて出力できる。
\t\t\t\t記入例:2,山本太郎
\n\t\t\t\t\t\t\t    16,鈴木\n\t\t\t\t\t\t

\n\t\t\t\t\t
\n\t\t\t\t\t\t~; for(1..$formMax){ my $num="member$_"; $form .= qq~ ~; if( ($_/5-int($_/5))==0){ $form .="\n\t\t\t\t\t\t"; } } $form .= qq~\n\t\t\t\t\t
~; if( $mode eq 'tty'){ $form .= qq~\t\t\t\t\t\t番号 \t\t\n \t\t\t番〜 \t\t\t番 \t\t
\t\t\t一ゲームの人数\n\t\t\t\t\t \t\t\t人:ゲームあたりの人数 \t\t
\n\t\t\t\t\t\t試合数\n\t\t\t\t\t \t\t\t試合:試合数 \t\t
オプション \t\t

\t\t\t:制限付きランダム。全員が同じ試合数を消化するまで次のゲームに参加しない。
\t\t\t\tデフォルト(初期値)\n\t\t\t\t\t\t

\n\t\t\t\t\t\t

\t\t\t\t:ランダム。連続して次のゲームに連続して参加することもある。一人当たりのゲーム差が大きくなることもある。
\t\t\t

\n\t\t\t\t\t\t

\t\t\t\t:結果を番号、またはゼッケンで並べ替えする。デフォルト(初期値)
\t\t\t\t組み合わせをさらに複数のグループに分けるときなどは、このチェックを外す。 \t\t\t

\n\t\t\t\t\t
\t\t\t   \n\t\t\t\t\t
\n\t\t
$naviList\n\t
~; } sub makeTable{ my @IN_Data = @_; my @OUT_DATA = (); my $message=shift @IN_Data; my $kind; if($message eq 'メンバー'){ $kind='membersTable';} else{$kind='gamesTable';} my @line; my $ref; my @Line=(); my $tableData = qq~

$message一覧表

$messageごとの参加者の一覧。

\n~; for $ref(0..$#IN_Data){ $tableData .= "\t\t\t\t\n"; @Line = @{$IN_Data[$ref]}; my $num; if( $ref<1){ for $num(0..$#Line){ $tableData .=""; } } else{ for $num(0..$#Line){ if( $num ==0 ){ $tableData .=""; } else{ $tableData .=""; } } } $tableData .="\n"; } $tableData .= "\t\t\t\n\t\t
$Line[$num]$Line[$num]$Line[$num]
\n"; return $tableData; } sub makeOutputMemberHash{ my @List=(); my @outputList; my $Number = 0; foreach $key (sort {$a <=> $b} keys %MembersList){ @outputList = @{$MembersList{$key}}; for(0..$GameNumber-1){ if($outputList[$_] !~ /○/){ $outputList[$_] = ' ';} } unshift @outputList,($key,$Count{$key}); push @{ $List[$Number]},@outputList; $Number++; } my @firstLine=(); push @firstLine,("$memberTableTitle","$memberTableTotal"); for(1..$GameNumber){ push @firstLine,$gameName.$_; } unshift @List,[ @firstLine ]; return @List; } sub makeOutputData{ my @List=@_; for(0..$#List){ my $VoL = $_ +1; $VoL .=$gameName; unshift @{$List[$_]},$VoL; } my @firstLine=(); push @firstLine,("$gameTableTitle"); for(1..$member){ push @firstLine,$_.$memberName; } unshift @List,[ @firstLine ]; return @List; } sub makeOrderList{ my ($Orderd,$Number_of_ThisGame,$count,$Max); my @waitingMembers = @allMembers; $Orderd = 0; foreach(;;){ my ($number_of_waitingMembers,$picup); $Max=$group*$member; if($Orderd >= $Max){ last; } # 参加者が決まると終了 if($random eq 'limit'){ if( $#waitingMembers == 0 ){ $picup=$waitingMembers[0]; $ThisGame{$picup}=1; @waitingMembers = @allMembers; } else{ $number_of_waitingMembers = $#waitingMembers; $picup = splice(@waitingMembers,int (rand( $number_of_waitingMembers )),1); if( $ThisGame{$picup} == 1){ push @waitingMembers,$picup; next; } else{ $ThisGame{$picup}=1; } } } else{ $number_of_waitingMembers = $#allMembers; $picup = $allMembers[int (rand( $number_of_waitingMembers ))]; if( $ThisGame{$picup} == 1){ next;} else{$ThisGame{$picup}=1;} } push @{$GamesList[$GameNumber]} ,"$picup"; $Count{$picup}++; $Number_of_ThisGame++; $MembersList{$picup}[$GameNumber]='○'; if( $Number_of_ThisGame > $member-1){ $GameNumber++; $Number_of_ThisGame=0; undef %ThisGame; } $Orderd ++; } } sub INPUT{ my (@pairs,$pair,$name,$value,@Member); @pairs = split(/&/,$buffer); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; &jcode'convert(*value,'euc'); if($name =~ /member\d+/ && $value ne''){push @Member,$value;} $FORM{$name} = $value; } if($FORM{'nameOrNumber'} =~ /name/i){ undef @allMembers;@allMembers = @Member;} } sub FORM_check{ if( $FORM{'nameOrNumber'} eq 'number'){ if($FORM{'startNumber'} =~ /\D+/ ){ push @inputError,("開始番号($FORM{'startNumber'})に数字以外の文字が含まれています。"); } elsif($FORM{'startNumber'} < 1 ){ push @inputError,("開始番号($FORM{'startNumber'})を入力してください。"); } if($FORM{'endNumber'} =~ /\D+/ ){ push @inputError,("終了番号($FORM{'endNumber'})に数字以外の文字が含まれています。"); } elsif($FORM{'endNumber'} <=0 ){ push @inputError,("終了番号($FORM{'endNumber'})を入力してください。"); } if($FORM{'endNumber'}<$FORM{'startNumber'}){ push(@inputError,'番号は大きいほうを右に書いてください。'); } if($FORM{'endNumber'}-$FORM{'startNumber'}>100){ push(@inputError,'最大100件までです。'); } if(($FORM{'endNumber'}-$FORM{'startNumber'})<$FORM{'number'}){ push(@inputError,'参加者よりゲームに必要な人数は少なくなければいけません。'); } my ($min,$MAX)=("$FORM{'startNumber'}","$FORM{'endNumber'}"); foreach($min..$MAX){ push @allMembers,$_; } if($#allMembers +1 <= $FORM{'number'}){ push(@inputError,'参加者よりゲームに必要な人数は少なくなければいけません。'); } $CHECKED{'nameOrNumber_number'} =' checked'; } elsif($FORM{'nameOrNumber'} eq 'name'){ if($#allMembers+1 < $FORM{'number'} ){ my $count = $#allMembers + 1; push @inputError,"名前での計算の場合、参加者数は$count名、参加者数は1ゲームの人数($FORM{'number'})以上必要です。番号での計算の場合は番号をチェック"; } $CHECKED{'nameOrNumber_name'} =' checked'; } else{ $CHECKED{'nameOrNumber_name'} =' checked';} if( $buffer ){ if($FORM{'order'} == 1){ $orderOutput = 1;$CHECKED{'check_order'} = ' checked'; } else{ $orderOutput = 0;$CHECKED{'check_order'}=''; } } else{ $CHECKED{'check_order'} = ' checked';} if($FORM{'randomOrLimit'} =~ /full/i ){ $CHECKED{'randomOrLimit_full'}=' checked'; $random = 'fll'; } else{ $CHECKED{'randomOrLimit_limit'}=' checked'; $random = 'limit'; } $group = $FORM{'Games'}; $member = $FORM{'number'}; } sub HELP{ print "Pragma: no-cache\nCache-Control: no-cache\nExpires: -1\nContent-type: text/html\; charset=euc-jp\n\n"; &printTopMessage; while(){ s/\$THIS_SCRIPT\$ENV{'PATH_INFO'}/$THIS_SCRIPT$ENV{'PATH_INFO'}/g; print ; } } sub printAbstract{ if( $mode eq 'tty'){ print qq~\t
\n\t\t
\n\t\t\t

このCGIは・・(概要)

パソコンなどの場合は、スクリーン端末(\@mediaType=screen)用をご利用ください。(氏名での組み合わせが利用できます。)

\t

\n\t\t\t\tスポーツやゲームで、メンバーの組み合わせを行います。参加する人数からできるだけランダムにメンバーを選択して1グループずつ作っていきます。 \t

\n\t\t
\n\n$naviList\t
\n~; } else{ print qq~\t
\n\t\t
\n\t\t\t

このCGIは・・(概要)

携帯端末の場合は、携帯端末(\@mediaType=TTY)用をご利用ください。(その場合氏名での組み合わせは出来ません。)

\t

\n\t\t\t\tスポーツやゲームで、メンバーの組み合わせを行います。参加する人数からできるだけランダムにメンバーを選択して1グループずつ作っていきます。 \t

\n\t\t\t

\n\t\t\t\tこのプログラムは、「テニスや卓球の練習試合の組み合わせを決めるためのCGIは無いか」という疑問から、探してもなさそうなのでいっそのこと作ってしまえと取り掛かりました。 \t

\n\t\t\t

\n\t\t\t\tそれを実現するためには、配列のハッシュや配列の配列という二次元データの処理というよく使う手順でありながら、意外と奥の深い処理手順を駆使する必要がありました。 \t

\n\t\t\t

\n\t\t\t\tあまり必要なプログラムとは思えないので、用途は後から考えることにして、とりあえず動けばよいという考えで作られていますので、まだ工夫の余地はあると思われます。そのため、GPLで配布しますから、皆さんで工夫してみてください。 \t

\n\t\t\t

このプログラムで出来ること

\n\t\t\t
    \t\t
  • メンバー(または番号)を入力したものから、一回戦ごとの参加メンバーを決めます。
  • \t\t
  • 2回戦目からは、すでに参加したものを除いて参加メンバーを決めることもできます。
  • \t\t
  • 全員が参加し終わると改めて参加メンバーの組み合わせを計算します。
  • \n\t\t\t
\n\t\t\t

\n\t\t\t\t詳しい説明はヘルプをご覧ください。またこのCGIのソースはMEMBERS.CGIにあります。文字コードはEUCです。EUCが編集できるテキストエディタでご利用ください。 \t

\n\t\t\t

\n\t\t\t\t著作権についてはこのページの文書情報をご覧ください。 \t

\n\t\t
\n\n$naviList\t
\n~; } } sub printTopMessage{ print qq~ \n\n 組み合わせ\n \n\n \n\n

組み合わせ

\n\n~; } sub printEndMessage{ print qq^\t
\n\t\t
\t\n\t\t\t$DocumentInfo\n\n\t\t\t

著作権

\n\t\t\t

\t\tこのプログラムはThe GNU General Public License \t\t\t\t\t( \t\t\t\t\tGNU 一般公衆利用許諾書 バージョン3 (GPLv3))で配布します。 \t

\n\t\t\t
© TESHIMA Shizuka 2009 - 2012 All Rights Reserved \t\t\t\t\t \t\t\t\t\tmailto:office@ichiya.com
\n\t\t
$naviList
\n\t\t\n\t
\n\n^; } __END__

このCGIは・・(概要)

スポーツやゲームで、メンバーの組み合わせを行います。参加する人数からできるだけランダムにメンバーを選択して1グループずつ作っていきます。

このプログラムは、「テニスや卓球の練習試合の組み合わせを決めるためのCGIは無いか」という疑問から、探してもなさそうなのでいっそのこと作ってしまえと取り掛かりました。

それを実現するためには、配列のハッシュや配列の配列という二次元データの処理というよく使う手順でありながら、意外と奥の深い処理手順を駆使する必要がありました。

あまり必要なプログラムとは思えないので、用途は後から考えることにして、とりあえず動けばよいという考えで作られていますので、まだ工夫の余地はあると思われます。そのため、GPLで配布しますから、皆さんで工夫してみてください。

このプログラムで出来ること

  • メンバー(または番号)を入力したものから、一回戦ごとの参加メンバーを決めます。
  • 2回戦目からは、すでに参加したものを除いて参加メンバーを決めることもできます。
  • 全員が参加し終わると改めて参加メンバーの組み合わせを計算します。

詳しい説明はヘルプをご覧ください。またこのCGIのソースはMEMBERS.CGIにあります。文字コードはEUCです。EUCが編集できるテキストエディタでご利用ください。

著作権についてはこのページの文書情報をご覧ください。

入力フォーム

(ゼッケン)名前
"(ゼッケン)名前"欄には、ゲーム参加者の氏名などを記入します。
このとき、氏名の前に数字またはアルファベットを含む文字列をカンマ(,)で区切っていれておくと、その文字順に並べ替えて出力できる。
  • 記入例:2,山本太郎
  • 記入例:16,鈴木
飛び番号がある場合もこちらを利用する。
番号を記入する場合
IDなど、連続番号で指定する場合はこちらを利用する。その場合、開始番号と終了番号を記入する。
一ゲームの人数
ゲームあたりに参加する人数を決める。
クラス対抗のゲームでランダムに選択してチームを作る場合など、自チームだけを決める場合は、ここに1チームのメンバーを入力します。
また、練習試合のように、両チームの参加者をランダムに選択したい場合は両チーム合わせた人数を入力します。
  • 参加者6人×2チームのポートボールの場合12人となります。
  • テニスや卓球のダブルスの場合は4人
野球などのように1ゲームへの参加者が多い場合は、1チームの人数を1ゲームの参加者として、制限付きランダムを選択する。
一方のチームだけ決める場合は、番号順に並べ替えて出力できます。
練習試合のように双方のチームに誰が行くかもランダムに決めたい場合は並べ替えをしないで、得られた組み合わせを前後で二つに分ける。
試合数
何回試合を行うかを入力します。
この場合、オプションで試合毎にランダムに選択するか、全員の参加機会が出来るだけ同じにするかを指定する。
オプション
組み合わせと出力方法の指定をする。
制限付きランダム
全員が同じ試合数を消化するまで次のゲームに参加しない。デフォルト(初期値)
ランダム
連続して次のゲームに連続して参加することもある。一人当たりのゲーム差が大きくなることもある。
結果を番号、またはゼッケンで並べ替えする。
デフォルト(初期値)
組み合わせをさらに複数のグループに分けるときなどは、このチェックを外す。

組み合わせ結果(Table)の解説

ゲーム一覧表
各ゲームの参加者の一覧です。入力時に並べ替えが指定してあると並べ替えがされています。
メンバー一覧表
参加者別の試合数と参加するゲームの一覧

組み合わせ結果(CSV)の解説

MS office Excell形式のCSVです。下記文字列をドラッグして選択しコピーメモ帳などに貼り付けて、拡張子をcsvにして保存するか、そのままエクセルに貼り付ける。そのとき、エクセルで表示されるメニューからテキストウィザードを使用すると表として貼り付けられる。

ゲーム一覧
ゲーム毎の参加者の一覧
メンバー一覧
参加者毎の参加ゲームの一覧

設置方法

このCGIは、サーバーにテキストモードで転送して実行権限を与えるだけで動作するように作成されています。拡張子を.txtから、.cgiに変更してください。

jcode.plはこのCGIと同じ場所に置くか、PATHを書き換えること。

なお、サーバーにJcode.pmがある場合は、最初のrequire 'jcode.pl';の部分を、use Jcode;に書き換えれば動きます。その他、書き換えが必要そうな部分は最初の方にまとめてありますから適当に変更してください。