「日記2010年8月その2」の編集履歴(バックアップ)一覧はこちら
日記2010年8月その2 - (2010/08/06 (金) 14:20:50) の1つ前との変更点
追加された行は緑色になります。
削除された行は赤色になります。
2010/8/5
架空鉄道の話。
ネット上に柏鉄鉄道という路線の設定を作っているテツオタの方がいまして、リンク先のような路線図を作っていました。
http://www.pixiv.net/member_illust.php?mode=medium&illust_id=8264767
http://www.pixiv.net/member_illust.php?mode=medium&illust_id=11922112
このデータから下記リンク先のような運賃表を完成させたいそうなのです。
http://www.pixiv.net/member_illust.php?mode=medium&illust_id=12044821
架空の路線や運賃表を作って楽しむ人、完成した表をみて楽しむ人。
僕には何が面白いのか、理解できない世界ですが、話を聞いてみると運賃表の作成どうやら手作業で行っていて大変なようです。
コメントをやり取りしてみるとデータは静的、信頼できないデータは来ないし外部センサーが不調になる可能性も考えなくていい、ユーザーがでたらめな操作もしない。
プログラムとしてはとても楽な話のようです。
C#の勉強もかねて運賃表を作成することにしてみました。
コードは、指定した2駅間の最短路線距離を経路探索で求める処理です。
理屈では、環状線だらけの路線図でも対応できる処理になっています。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.IO;
namespace 架空鉄道柏鉄運賃表計算プログラム
{
public partial class Form1 : Form
{
Hashtable ht = new Hashtable();
List<double> lenSums = new List<double>();
List<string> gakkennTosisen = new List<string>();
List<string> kuukouSen = new List<string>();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
StreamReader sr = new StreamReader(
"D:/色々/架空鉄道運賃表/柏鉄路線データ.txt", Encoding.GetEncoding("Shift_JIS"));
char[] delimiterChars = {'\t'};
while (!sr.EndOfStream)
{
string s=sr.ReadLine();
string[] row = s.Split(delimiterChars);
setStationDate(row[0],row[1],double.Parse(row[2]));
}
sr.Close();
sr = new StreamReader(
"D:/色々/架空鉄道運賃表/柏鉄路線データ駅名一覧.txt", Encoding.GetEncoding("Shift_JIS"));
List<string> stationNames = new List<string>();
while (!sr.EndOfStream)
{
stationNames.Add ( sr.ReadLine());
}
sr.Close();
sr = new StreamReader(
"D:/色々/架空鉄道運賃表/柏線学研都市線駅名一覧.txt", Encoding.GetEncoding("Shift_JIS"));
while (!sr.EndOfStream)
{
gakkennTosisen.Add(sr.ReadLine());
}
sr.Close();
sr = new StreamReader(
"D:/色々/架空鉄道運賃表/柏線空港路線駅名一覧.txt", Encoding.GetEncoding("Shift_JIS"));
while (!sr.EndOfStream)
{
kuukouSen.Add(sr.ReadLine());
}
sr.Close();
int count =stationNames.Count;
string [,] sUntinDate=new string [count+1,count+1];
sUntinDate[0, 0] = "";
for (int i = 1; i < count+1; i++)
{
sUntinDate[0, i] = stationNames[i-1];
sUntinDate[i, 0] = stationNames[i-1];
}
for (int i = 0; i < count; i++)
{
for (int j = 0; j < count; j++)
{
if (i == j)
{
sUntinDate[i + 1, j + 1] = "0";
}
else
{
search_root(stationNames[i], stationNames[j], 0.0d);
lenSums.Sort();
sUntinDate[i + 1, j + 1] = CalcUntin(stationNames[i], stationNames[j], lenSums[0]).ToString();
lenSums.Clear();
}
}
}
string outDate = "";
StreamWriter sw = new StreamWriter("D:/色々/架空鉄道運賃表/運賃一覧表.txt", true, System.Text.Encoding.GetEncoding("shift_jis"));
for (int i = 0; i < count+1; i++)
{
for (int j = 0; j < count+1; j++)
{
outDate += sUntinDate[i, j] + ",";
}
sw.WriteLine(outDate);
outDate="";
}
sw.Close();
}
internal int CalcUntin(string sStartStation, string sGoalStation, double km)
{
/*
路線
空港線 20
学研都市線 30
*
1キロ以下の端数は切り上げ
小人は半額(10円以下切り捨て)
1~3 130円
4~6 160円
7~10 190円
11~15 220円
16~20 250円
21~25 280円
26~30 310円
31~35 350円
36~40 390円
41~45 430円
46~50 470円
51~60 510円
61~70 550円
71~80 600円
81~90 650円
91~100 700円
101~110 750円
111~120 800円
*/
int Untin=0;
int km2=(int)Math.Floor(km);
if (km2 > 0 && km2 < 4)
{
Untin = 130;
}
if (km2 > 3 && km2 < 7)
{
Untin = 160;
}
if (km2 > 6 && km2 < 11)
{
Untin = 190;
}
if (km2 > 10 && km2 < 16)
{
Untin = 220;
}
if (km2 > 15 && km2 < 21)
{
Untin =250;
}
if (km2 > 20 && km2 < 26)
{
Untin = 280;
}
if (km2 > 25 && km2 < 31)
{
Untin = 310;
}
if (km2 > 30 && km2 < 36)
{
Untin = 350;
}
if (km2 > 35 && km2 < 41)
{
Untin = 390;
}
if (km2 > 40 && km2 < 46)
{
Untin = 430;
}
if (km2 > 45 && km2 < 51)
{
Untin = 470;
}
if (km2 > 50 && km2 < 61)
{
Untin = 510;
}
if (km2 > 60 && km2 < 71)
{
Untin = 550;
}
if (km2 > 70 && km2 < 81)
{
Untin = 600;
}
if (km2 > 80 && km2 < 91)
{
Untin = 650;
}
if (km2 > 90 && km2 < 101)
{
Untin = 700;
}
if (km2 > 100 && km2 < 111)
{
Untin = 750;
}
if (km2 > 110 && km2 < 121)
{
Untin = 800;
}
bool b1 = kuukouSen.Contains(sStartStation);
bool b2 = kuukouSen.Contains(sGoalStation);
bool b3 = gakkennTosisen.Contains(sStartStation);
bool b4 = gakkennTosisen.Contains(sGoalStation);
//もし加算運賃の路線がもう一本多ければ、加算運賃の計算を2次元の組み合わせ表を用意して計算する必要があったわけです。
//このサイズならif文で書けるので、対応表は用意しませんでした。
/*
* 1 学研で乗り空港線で降りる 学研都市、空港両線の加算運賃を適用
2 学研で乗り学研で降りる 加算運賃の適用は無し
3 学研で乗り、学研と空港以外で降りる 学研都市線の加算運賃を適用-
4 学研と空港以外で乗り、学研で降りる場合 学研都市線の加算運賃
*/
//学研線で乗車した場合
if(b3==true && b2==false && b4==false){
//学研線から乗り、学研線と空港線意外で降りた場合
Untin += 30;
}
if(b3==true && b2==true){
//学研線から乗り、空港線で降りた場合
Untin+=50;
}
//空港線で乗車
if(b1==true && b2==false && b4==false){
//空港線から乗り、学研線と空港線意外で降りた場合
Untin += 20;
}
if(b1==true && b4==true){
//空港線から乗り、学研線で降りた場合
Untin += 50;
}
//それ以外で乗車
if(b1==false && b3==false && b2==true){
//学研線と空港線意外で乗り、空港線で降りた場合
Untin += 20;
}
if(b1== false && b3==false && b4==true){
//学研線と空港線以外で乗り、学研線で降りた場合。
Untin += 30;
}
return Untin;
}
internal void search_root(string sNowStation,string sGoalStation,double sumKm)
{
if(sNowStation==sGoalStation){
lenSums.Add(sumKm);
}else{
stationDate sd = (stationDate)ht[sNowStation];
if (sd != null && sd.stampGoOk==true )
{
sd.stampGoOk = false;
ht[sNowStation] = sd;
for (int i = 0; i < sd.nextStation.Count; i++)
{
search_root(sd.nextStation[i], sGoalStation, sumKm + sd.nextLen[i]);
}
sd.stampGoOk = true;
ht[sNowStation] = sd;
}
}
}
public void setStationDate(string sStation1,string sStation2,double len){
stationDate SD;
if (ht[sStation1] == null)
{
ht[sStation1] = new stationDate();
}
SD=(stationDate)ht[sStation1];
SD.set_StationDate(sStation2 ,len);
ht[sStation1] = SD;
if (ht[sStation2] == null)
{
ht[sStation2] = new stationDate();
}
SD = (stationDate)ht[sStation2];
SD.set_StationDate(sStation1, len);
ht[sStation2] = SD;
}
}
public class stationDate
{
internal List<string> nextStation = new List<string>();
internal List<double> nextLen = new List<double>();
internal bool stampGoOk = true;//駅間の経路探索のとき一度通った駅か記録するため、 通ってないならtrue
public void set_StationDate(string sNextStation, double dLen)
{
nextStation.Add(sNextStation);
nextLen.Add(dLen);
}
}
}
2010/8/5
架空鉄道の話。
ネット上に柏鉄鉄道という路線の設定を作っているテツオタの方がいまして、リンク先のような路線図を作っていました。
http://www.pixiv.net/member_illust.php?mode=medium&illust_id=8264767
http://www.pixiv.net/member_illust.php?mode=medium&illust_id=11922112
このデータから下記リンク先のような運賃表を完成させたいそうなのです。
http://www.pixiv.net/member_illust.php?mode=medium&illust_id=12044821
架空の路線や運賃表を作って楽しむ人、完成した表をみて楽しむ人。
僕には何が面白いのか、理解できない世界ですが、話を聞いてみると運賃表の作成どうやら手作業で行っていて大変なようです。
コメントをやり取りしてみるとデータは静的、信頼できないデータは来ないし外部センサーが不調になる可能性も考えなくていい、ユーザーがでたらめな操作もしない。
プログラムとしてはとても楽な話のようです。
C#の勉強もかねて運賃表を作成することにしてみました。
コードは、指定した2駅間の最短路線距離を経路探索で求める処理です。
理屈では、環状線だらけの路線図でも対応できる処理になっています。
まずはデータを加工しまして、全ての駅の隣駅とそこまでの路線距離をデータにしました。
&ref(柏鉄路線データ.txt)
&ref柏鉄路線データ駅名一覧.txt)
&ref(柏線学研都市線駅名一覧.txt)
&ref(柏線空港路線駅名一覧.txt)
&ref(運賃一覧表.txt)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.IO;
namespace 架空鉄道柏鉄運賃表計算プログラム
{
public partial class Form1 : Form
{
Hashtable ht = new Hashtable();
List<double> lenSums = new List<double>();
List<string> gakkennTosisen = new List<string>();
List<string> kuukouSen = new List<string>();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
StreamReader sr = new StreamReader(
"D:/色々/架空鉄道運賃表/柏鉄路線データ.txt", Encoding.GetEncoding("Shift_JIS"));
char[] delimiterChars = {'\t'};
while (!sr.EndOfStream)
{
string s=sr.ReadLine();
string[] row = s.Split(delimiterChars);
setStationDate(row[0],row[1],double.Parse(row[2]));
}
sr.Close();
sr = new StreamReader(
"D:/色々/架空鉄道運賃表/柏鉄路線データ駅名一覧.txt", Encoding.GetEncoding("Shift_JIS"));
List<string> stationNames = new List<string>();
while (!sr.EndOfStream)
{
stationNames.Add ( sr.ReadLine());
}
sr.Close();
sr = new StreamReader(
"D:/色々/架空鉄道運賃表/柏線学研都市線駅名一覧.txt", Encoding.GetEncoding("Shift_JIS"));
while (!sr.EndOfStream)
{
gakkennTosisen.Add(sr.ReadLine());
}
sr.Close();
sr = new StreamReader(
"D:/色々/架空鉄道運賃表/柏線空港路線駅名一覧.txt", Encoding.GetEncoding("Shift_JIS"));
while (!sr.EndOfStream)
{
kuukouSen.Add(sr.ReadLine());
}
sr.Close();
int count =stationNames.Count;
string [,] sUntinDate=new string [count+1,count+1];
sUntinDate[0, 0] = "";
for (int i = 1; i < count+1; i++)
{
sUntinDate[0, i] = stationNames[i-1];
sUntinDate[i, 0] = stationNames[i-1];
}
for (int i = 0; i < count; i++)
{
for (int j = 0; j < count; j++)
{
if (i == j)
{
sUntinDate[i + 1, j + 1] = "0";
}
else
{
search_root(stationNames[i], stationNames[j], 0.0d);
lenSums.Sort();
sUntinDate[i + 1, j + 1] = CalcUntin(stationNames[i], stationNames[j], lenSums[0]).ToString();
lenSums.Clear();
}
}
}
string outDate = "";
StreamWriter sw = new StreamWriter("D:/色々/架空鉄道運賃表/運賃一覧表.txt", true, System.Text.Encoding.GetEncoding("shift_jis"));
for (int i = 0; i < count+1; i++)
{
for (int j = 0; j < count+1; j++)
{
outDate += sUntinDate[i, j] + ",";
}
sw.WriteLine(outDate);
outDate="";
}
sw.Close();
}
internal int CalcUntin(string sStartStation, string sGoalStation, double km)
{
/*
路線
空港線 20
学研都市線 30
*
1キロ以下の端数は切り上げ
小人は半額(10円以下切り捨て)
1~3 130円
4~6 160円
7~10 190円
11~15 220円
16~20 250円
21~25 280円
26~30 310円
31~35 350円
36~40 390円
41~45 430円
46~50 470円
51~60 510円
61~70 550円
71~80 600円
81~90 650円
91~100 700円
101~110 750円
111~120 800円
*/
int Untin=0;
int km2=(int)Math.Floor(km);
if (km2 > 0 && km2 < 4)
{
Untin = 130;
}
if (km2 > 3 && km2 < 7)
{
Untin = 160;
}
if (km2 > 6 && km2 < 11)
{
Untin = 190;
}
if (km2 > 10 && km2 < 16)
{
Untin = 220;
}
if (km2 > 15 && km2 < 21)
{
Untin =250;
}
if (km2 > 20 && km2 < 26)
{
Untin = 280;
}
if (km2 > 25 && km2 < 31)
{
Untin = 310;
}
if (km2 > 30 && km2 < 36)
{
Untin = 350;
}
if (km2 > 35 && km2 < 41)
{
Untin = 390;
}
if (km2 > 40 && km2 < 46)
{
Untin = 430;
}
if (km2 > 45 && km2 < 51)
{
Untin = 470;
}
if (km2 > 50 && km2 < 61)
{
Untin = 510;
}
if (km2 > 60 && km2 < 71)
{
Untin = 550;
}
if (km2 > 70 && km2 < 81)
{
Untin = 600;
}
if (km2 > 80 && km2 < 91)
{
Untin = 650;
}
if (km2 > 90 && km2 < 101)
{
Untin = 700;
}
if (km2 > 100 && km2 < 111)
{
Untin = 750;
}
if (km2 > 110 && km2 < 121)
{
Untin = 800;
}
bool b1 = kuukouSen.Contains(sStartStation);
bool b2 = kuukouSen.Contains(sGoalStation);
bool b3 = gakkennTosisen.Contains(sStartStation);
bool b4 = gakkennTosisen.Contains(sGoalStation);
//もし加算運賃の路線がもう一本多ければ、加算運賃の計算を2次元の組み合わせ表を用意して計算する必要があったわけです。
//このサイズならif文で書けるので、対応表は用意しませんでした。
/*
* 1 学研で乗り空港線で降りる 学研都市、空港両線の加算運賃を適用
2 学研で乗り学研で降りる 加算運賃の適用は無し
3 学研で乗り、学研と空港以外で降りる 学研都市線の加算運賃を適用-
4 学研と空港以外で乗り、学研で降りる場合 学研都市線の加算運賃
*/
//学研線で乗車した場合
if(b3==true && b2==false && b4==false){
//学研線から乗り、学研線と空港線意外で降りた場合
Untin += 30;
}
if(b3==true && b2==true){
//学研線から乗り、空港線で降りた場合
Untin+=50;
}
//空港線で乗車
if(b1==true && b2==false && b4==false){
//空港線から乗り、学研線と空港線意外で降りた場合
Untin += 20;
}
if(b1==true && b4==true){
//空港線から乗り、学研線で降りた場合
Untin += 50;
}
//それ以外で乗車
if(b1==false && b3==false && b2==true){
//学研線と空港線意外で乗り、空港線で降りた場合
Untin += 20;
}
if(b1== false && b3==false && b4==true){
//学研線と空港線以外で乗り、学研線で降りた場合。
Untin += 30;
}
return Untin;
}
internal void search_root(string sNowStation,string sGoalStation,double sumKm)
{
if(sNowStation==sGoalStation){
lenSums.Add(sumKm);
}else{
stationDate sd = (stationDate)ht[sNowStation];
if (sd != null && sd.stampGoOk==true )
{
sd.stampGoOk = false;
ht[sNowStation] = sd;
for (int i = 0; i < sd.nextStation.Count; i++)
{
search_root(sd.nextStation[i], sGoalStation, sumKm + sd.nextLen[i]);
}
sd.stampGoOk = true;
ht[sNowStation] = sd;
}
}
}
public void setStationDate(string sStation1,string sStation2,double len){
stationDate SD;
if (ht[sStation1] == null)
{
ht[sStation1] = new stationDate();
}
SD=(stationDate)ht[sStation1];
SD.set_StationDate(sStation2 ,len);
ht[sStation1] = SD;
if (ht[sStation2] == null)
{
ht[sStation2] = new stationDate();
}
SD = (stationDate)ht[sStation2];
SD.set_StationDate(sStation1, len);
ht[sStation2] = SD;
}
}
public class stationDate
{
internal List<string> nextStation = new List<string>();
internal List<double> nextLen = new List<double>();
internal bool stampGoOk = true;//駅間の経路探索のとき一度通った駅か記録するため、 通ってないならtrue
public void set_StationDate(string sNextStation, double dLen)
{
nextStation.Add(sNextStation);
nextLen.Add(dLen);
}
}
}