ルーカレーのカレー屋さんなのですが、カレーパンも売られているので、
テイクアウトしました。
1個250円なのですが、3個で700円、5個で1200円です。
写真には写ってませんが、中にじゃがいもが入ってますね。
今回買ったのはカレーパンですが、カレールーもテイクアウトできます。
タッパーを持参すればさらに50円引きになるみたいです。
今度ルーカレーも買ってみよう。
残ったカレーパンは明日の朝ご飯にします。
以前、紹介した、このマッサージ器。
これを使いまくった結果、ある事に気がついたんですよ。
オイラは以前から、あくびが止まらない、と言うことをスゴイ気にしていました。
夜になると、ホントにあくびが止まらなくて、顎が痛くなるぐらい。
しかし、そのあくびが出なくなった。
ここである事に気がついたんですよ。
首が凝る
↓
頭に巡る血流が悪くなる
↓
脳に酸素が行かなくなる
↓
脳は酸素を欲しがって、あくびをするようになる
このメカニズムが成り立つんじゃないかと。
そう考えたら、
首の凝りが解消される
↓
頭に血液が流れるようになる
↓
脳に酸素が渡るようになる
↓
あくびが止まる
いやいや、脳に酸素が行かなくなった時点でヤバイから。
でも、このマッサージ器で血流が良くなったら1万円の投資なんて安い物よ。
整体1回行ったらウン千円取られるのよ。
どちらがより経費がかからないか、なんて一目瞭然。
でも調子悪いときは一度見てもらった方が良いかもしれないけど。
いや、でもここまで激変するとは思わんかった。
これはマジで、買って良かった物ですわ。

前回までの状況はこちら。
最新ソースはこちら。(gitHub)
https://github.com/takishita2nd/Picross
さて、今回はここを攻めていきます。

ここはマスクされたマスのすぐ隣に塗られたマスがあるので、当てはめる数字が分かればここも確実に塗ることができます。
ただ、前から塗る場合と後ろから塗る場合で、一緒に考えるとハマってしまうので、今回は前から塗るケースを考えました。
つまり、今回の対象はここになります。

解き方はこんな風に考えました。
空いているマスを抽出し、その端っこ(今回は先頭)が塗られているならば、数字に従って塗る。
そして、その次のマスは必ずマスクされますので、マスクする。
これでいきます。
// 解析パターンその5
// 端っこ(先頭)が塗られていたら塗る。
private void pattern5()
{
// Row
pattern5Row();
// Col
pattern5Col();
}
private void pattern5Row()
{
int row = 0;
foreach (var rowlist in rowNumbers)
{
if (rowlist.IsAnalyzed())
{
row++;
continue;
}
rowlist.AnalyzeDatas.Reverse();
// 塗った場所が端っこならそこを塗る
// マスクされていない部分をリスト化して取得する
List<List<BitmapData>> data = new List<List<BitmapData>>();
{
List<BitmapData> dataList = new List<BitmapData>();
for (int col = 0; col < colNumbers.Count; col++)
{
if (_bitmapData[row, col].IsMasked() == false)
{
dataList.Add(_bitmapData[row, col]);
}
else
{
if (dataList.Count != 0)
{
data.Add(dataList);
dataList = new List<BitmapData>();
}
}
}
if (dataList.Count != 0)
{
data.Add(dataList);
}
if (data.Count == 0)
{
row++;
continue;
}
}
int rowNumberIndex = 0;
foreach (var dataList in data)
{
// 端っこが塗られているか?
if (dataList[0].IsPainted())
{
// すでに処理済みか?
if (rowlist.AnalyzeDatas[rowNumberIndex].IsAnalyzed())
{
rowNumberIndex++;
continue;
}
// 数字に従ってマスを塗る
int count = 0;
foreach (var s in dataList)
{
if (count < rowlist.AnalyzeDatas[rowNumberIndex].Value)
{
s.Paint();
count++;
}
else
{
if (s.IsMasked() == false)
{
s.Mask();
}
rowlist.AnalyzeDatas[rowNumberIndex].Analyzed();
rowlist.CheckAnalyze();
break;
}
}
}
}
row++;
}
}
private void pattern5Col()
{
int col = 0;
foreach (var collist in colNumbers)
{
if (collist.IsAnalyzed())
{
col++;
continue;
}
collist.AnalyzeDatas.Reverse();
// 塗った場所が端っこならそこを塗る
// マスクされていない部分をリスト化して取得する
List<List<BitmapData>> data = new List<List<BitmapData>>();
{
List<BitmapData> dataList = new List<BitmapData>();
for (int row = 0; row < rowNumbers.Count; row++)
{
if (_bitmapData[row, col].IsMasked() == false)
{
dataList.Add(_bitmapData[row, col]);
}
else
{
if (dataList.Count != 0)
{
data.Add(dataList);
dataList = new List<BitmapData>();
}
}
}
if (dataList.Count != 0)
{
data.Add(dataList);
}
if (data.Count == 0)
{
col++;
continue;
}
}
int colNumberIndex = 0;
foreach (var dataList in data)
{
// 端っこが塗られているか?
if (dataList[0].IsPainted())
{
// すでに処理済みか?
if (collist.AnalyzeDatas[colNumberIndex].IsAnalyzed())
{
colNumberIndex++;
continue;
}
// 数字に従ってマスを塗る
int count = 0;
foreach (var s in dataList)
{
if (count < collist.AnalyzeDatas[colNumberIndex].Value)
{
s.Paint();
count++;
}
else
{
if (s.IsMasked() == false)
{
s.Mask();
}
collist.AnalyzeDatas[colNumberIndex].Analyzed();
collist.CheckAnalyze();
break;
}
}
}
}
col++;
}
}
考え方は簡単に思えますが、実際に実装して見ると結構複雑になったりします。
このコーディングが正しく動かすまでに何度もデバッグを繰り返しました。
プログラミングとはそういうもんです。
基本的にトライエラーで正しく動くまで修正するのです。
実行結果はこうなりました。

小さな一歩ですが、確実に行きましょう。

前回までの状況はこちら。
最新ソースはこちら。(gitHub)
https://github.com/takishita2nd/Picross
この問題を解いてみました。

とりあえず、前回までのロジックを実装した解析プログラムを適用してみます。

当然、解けませんでした。
では、ここに注目してみましょう。

左の数字を見ると、真ん中に4マス空いていますので、そこが塗れると思います。
逆に考えれば、その左右にある1マスの所には塗れないことが明らかになっています。
ピクロスの解析の基本は、塗れないところはマスクしていく、と言うことなので、今回の解析パターンでは、こういったスペースをマスクするロジックを作成していきます。
それができれば、残ったスペースには解析パターン2が適用されて塗ってくれるはずです。
そこで、こういうクラスを用意しました。
class Pattern4Data
{
public int Index;
public int Value;
public Pattern4Data(int index, int value)
{
Index = index;
Value = value;
}
}
空きがある位置と、空いているマスの数を数えて保持します。
これをListで持ちます。
List<Pattern4Data> countList = new List<Pattern4Data>();
こうやって、空白のある部分を全て抽出します。
その中から、与えられた数字のマスが確実に入らないところ、とりあえずは、一番小さな値よりも小さいマスを検出して、その空白を全てマスクして塗れない様にします。
と言うわけで、こういうコードを書きました。
// 解析パターンその4
// 空いているマスが少なくて塗れないマスをマスクする
private void pattern4()
{
// Row
pattern4Row();
// Col
pattern4Col();
}
private void pattern4Row()
{
int row = 0;
foreach (var rowlist in rowNumbers)
{
if (rowlist.IsAnalyzed())
{
row++;
continue;
}
// マスクされていない連続したマスを数える
int col = 0;
int rememberCol = colNumbers.Count;
int count = 0;
List<Pattern4Data> countList = new List<Pattern4Data>();
while (col < colNumbers.Count)
{
if (_bitmapData[row, col].IsMasked() == false)
{
count++;
if(rememberCol == colNumbers.Count)
{
rememberCol = col;
}
}
else
{
if (count != 0)
{
countList.Add(new Pattern4Data(rememberCol, count));
count = 0;
rememberCol = colNumbers.Count;
}
}
col++;
if (col == colNumbers.Count)
{
if (count != 0)
{
countList.Add(new Pattern4Data(rememberCol, count));
}
}
}
// 数字の中で一番小さい値を取得する
int val = colNumbers.Count;
foreach(var s in rowlist.AnalyzeDatas)
{
if(val > s.Value)
{
val = s.Value;
}
}
// マスクされていない連続したマスの数が数字より小さい場合はマスクする
foreach(var data in countList)
{
if(val > data.Value)
{
for(int i = 0; i< data.Value; i++)
{
if(_bitmapData[row, data.Index + i].IsValid() == false)
{
_bitmapData[row, data.Index + i].Mask();
}
}
}
}
row++;
}
}
private void pattern4Col()
{
int col = 0;
foreach (var collist in colNumbers)
{
if (collist.IsAnalyzed())
{
col++;
continue;
}
// マスクされていない連続したマスを数える
int row = 0;
int rememberRow = rowNumbers.Count;
int count = 0;
List<Pattern4Data> countList = new List<Pattern4Data>();
while (row < rowNumbers.Count)
{
if (_bitmapData[row, col].IsMasked() == false)
{
count++;
if(rememberRow == rowNumbers.Count)
{
rememberRow = row;
}
}
else
{
if (count != 0)
{
countList.Add(new Pattern4Data(rememberRow, count));
count = 0;
rememberRow = rowNumbers.Count;
}
}
row++;
if (row == rowNumbers.Count)
{
if (count != 0)
{
countList.Add(new Pattern4Data(rememberRow, count));
}
}
}
// 数字の中で一番小さい値を取得する
int val = rowNumbers.Count;
foreach(var s in collist.AnalyzeDatas)
{
if(val > s.Value)
{
val = s.Value;
}
}
// マスクされていない連続したマスの数が数字より小さい場合はマスクする
foreach(var data in countList)
{
if(val > data.Value)
{
for(int i = 0; i< data.Value; i++)
{
if(_bitmapData[data.Index + i, col].IsValid() == false)
{
_bitmapData[data.Index + i, col].Mask();
}
}
}
}
col++;
}
}
public BitmapData[,] Run()
{
pattern1();
while (checkPainedCount())
{
pattern2();
pattern3();
pattern4();
}
return _bitmapData;
}
実行結果はこうなりました。

想定通りの動作をしていますね。

前回までの状況はこちら。

最新ソースはこちら。(gitHub)
https://github.com/takishita2nd/Picross
次は、ここを攻めていきます。

この赤い部分、すでに塗られているマスから、開いているマスは全て塗ることができないことが分かると思います。
これを処理していきましょう。
パターン2では塗られていないマスを数えましたが、パターン3では塗られているマスを数えます。
コードはパターン2と似ていますが、条件が変わっています。
// 解析パターンその3
// すでに塗りつぶされたマスからマスクをする
private void pattern3()
{
// Row
pattern3Row();
// Col
pattern3Col();
}
private void pattern3Row()
{
int row = 0;
foreach (var rowlist in rowNumbers)
{
if (rowlist.IsAnalyzed())
{
row++;
continue;
}
// 塗ったマスを数える
int col = 0;
int count = 0;
List<int> countList = new List<int>();
while (col < colNumbers.Count)
{
if (_bitmapData[row, col].IsPainted())
{
count++;
}
else
{
if (count != 0)
{
countList.Add(count);
count = 0;
}
}
col++;
if (col == colNumbers.Count)
{
if (count != 0)
{
countList.Add(count);
}
}
}
// 数えた数字が全て一致すれば確定とする
bool result = true;
if (rowlist.AnalyzeDatas.Count != countList.Count)
{
row++;
continue;
}
for (int i = 0; i < countList.Count; i++)
{
if (rowlist.AnalyzeDatas[i].Value != countList[i])
{
result = false;
}
}
if (result)
{
// 開いているところをマスクする
col = 0;
while (col < colNumbers.Count)
{
if (_bitmapData[row, col].IsValid() == false)
{
_bitmapData[row, col].Mask();
}
col++;
}
rowlist.Analyzed();
}
row++;
}
}
private void pattern3Col()
{
int col = 0;
foreach (var collist in colNumbers)
{
if (collist.IsAnalyzed())
{
col++;
continue;
}
// 塗ったマスを数える
int row = 0;
int count = 0;
List<int> countList = new List<int>();
while (row < rowNumbers.Count)
{
if (_bitmapData[row, col].IsPainted())
{
count++;
}
else
{
if (count != 0)
{
countList.Add(count);
count = 0;
}
}
row++;
if (row == rowNumbers.Count)
{
if(count != 0)
{
countList.Add(count);
}
}
}
// 数えた数字が全て一致すれば確定とする
bool result = true;
if (collist.AnalyzeDatas.Count != countList.Count)
{
col++;
continue;
}
countList.Reverse();
for (int i = 0; i < countList.Count; i++)
{
if (collist.AnalyzeDatas[i].Value != countList[i])
{
result = false;
}
}
if (result)
{
// 開いているところをマスクする
row = 0;
while (row < rowNumbers.Count)
{
if (_bitmapData[row, col].IsValid() == false)
{
_bitmapData[row, col].Mask();
}
row++;
}
collist.Analyzed();
}
col++;
}
}
実行結果はこちら。

ここまで来たら、パターン2とパターン3の繰り返しで全て塗れるのでは無いでしょうか?
では、パターン2とパターン3をループ処理させるのに、終了条件を判定する処理を作成します。
private bool checkPainedCount()
{
int newPaintedCount = 0;
for (int row = 0; row < rowNumbers.Count; row++)
{
for(int col = 0; col < colNumbers.Count; col++)
{
if(_bitmapData[row, col].IsValid())
{
newPaintedCount++;
}
}
}
if(oldPaintedCount == newPaintedCount)
{
return false;
}
oldPaintedCount = newPaintedCount;
return true;
}
考え方は、全てのマスが確定したかを判定し、その数を数えます。
ループ前とループ後のカウント数を比較し、変化があればカウント数を更新、変化が無ければループを終了します。
public BitmapData[,] Run()
{
pattern1();
while (checkPainedCount())
{
pattern2();
pattern3();
}
return _bitmapData;
}
実行結果はこうなりました。

これは・・・黒電話かな?

解けたようです。
まだ完全ではないですが、簡単な問題ならこれで解けそうです。

最近は暖かくなってきたので(とはいえ、まだ朝晩は寒いのでストーブは手放せないですが)ほぼ毎日1時間程度のウォーキングをしています。
札幌市内でも郊外の方はほとんど人は歩いていませんので、3密に該当しません。
むしろ、車の方が多い。
むしろ、公園とか、白石のサイクリングロードの方が人が集まっている様な気がして、そちらの方は避けています。
それと、マスクでは無く、ファイスマスクを付けたりとかしています。
そして、故障して買い直したネックマッサージャーも届きました。
1日3回ぐらい使用しています。
やはり、これを使った後は首の調子が良い。
首の可動範囲が、整体行った後と同じくらい動きます。
あと、筋トレ、ストレッチも欠かしていません。
これなら家の中でもできる。
このストレッチ本、なかなか良いよ。
首や肩のこりは、脳を巡る血液に影響が出るので、特に気をつけた方が良いよ。
まだフルタイムは無理ですが、体の稼働時間もだいぶ増えてきました。
少しゲームの時間を減らして、クリエイティブな時間を増やそうかとも思います。
例えば、小説の執筆も再開したりとか。
まぁ、適度に頑張ります。
こちらのブログの情報を元に、実際に購入しました。
http://kamechari.blog.jp/archives/1077373761.html

上の写真はフェイスマスク。
自転車載りガチ勢が使用しているもので、本来は口の中に虫が入るのを防ぐためのもの何ですが、通気性がかなり良いので使用している人が多いみたいです。
でも、これだけだと、唇が布に付くのが嫌!という人も多いので、下の写真のアイテムも使用します。
下の写真はフェイスガード。

主にサバゲーの時に使用するものなのですが、口の鼻の周りの空間を確保してくれるので、フェイスマスクと併用して使用している自転車乗りも多いらしい。
つけて見るとこんな感じ。

まぁ、マスクより防御力は劣りますが、飛沫感染は防ぐことができますし、何より楽に呼吸することができます。
自転車は思った以上に運動量が多いし、呼吸も激しくなるので、実際に使用して、マスクよりも遙かに楽でした。
お値段もAmazonで2000円程度で買えますし、繰り返し使えますので、自転車で運動不足解消をしたいなら買って良いのでは無いでしょうか??
かめちゃりさん、情報ありがとうございます!

前回までの状況はこちら。

最新ソースはこちら。(gitHub)
https://github.com/takishita2nd/Picross
つぎはどう攻めていくかというと、ここに注目しましょう。

ここも塗れるのが確定していますよね。
ここを塗るための条件を確認しましょう。
マスクされていないマスを数え、連続したマスの数と、範囲の数が全て一致した場合、確定とする。
つまり、

マスクされていないマスが2個、1個、2個と並んでいて、これらが全て左の数字と一致するため、この開いているマスは全て塗ることができます。
これをコーディングします。
// 解析パターンその2
private void pattern2()
{
// Row
pattern2Row();
// Col
pattern2Col();
}
private void pattern2Row()
{
int row = 0;
foreach (var rowlist in rowNumbers)
{
if (rowlist.IsAnalyzed())
{
row++;
continue;
}
// マスクされていない連続したマスを数える
int col = 0;
int count = 0;
List<int> countList = new List<int>();
while (col < colNumbers.Count)
{
if (_bitmapData[row, col].IsMasked() == false)
{
count++;
}
else
{
if (count != 0)
{
countList.Add(count);
count = 0;
}
}
col++;
if(col == colNumbers.Count)
{
countList.Add(count);
}
}
// 数えた数字が全て一致すれば確定とする
bool result = true;
if (rowlist.AnalyzeDatas.Count != countList.Count)
{
row++;
continue;
}
for (int i = 0; i < countList.Count; i++)
{
if (rowlist.AnalyzeDatas[i].Value != countList[i])
{
result = false;
}
}
if (result)
{
// 開いているところを塗る
col = 0;
while (col < colNumbers.Count)
{
if(_bitmapData[row, col].IsValid() == false)
{
_bitmapData[row, col].Paint();
}
col++;
}
rowlist.Analyzed();
}
row++;
}
}
private void pattern2Col()
{
int col = 0;
foreach (var collist in colNumbers)
{
if (collist.IsAnalyzed())
{
col++;
continue;
}
// マスクされていない連続したマスを数える
int row = 0;
int count = 0;
List<int> countList = new List<int>();
while (row < rowNumbers.Count)
{
if (_bitmapData[row, col].IsMasked() == false)
{
count++;
}
else
{
if (count != 0)
{
countList.Add(count);
count = 0;
}
}
row++;
if (row == rowNumbers.Count)
{
countList.Add(count);
}
}
// 数えた数字が全て一致すれば確定とする
bool result = true;
if (collist.AnalyzeDatas.Count != countList.Count)
{
col++;
continue;
}
countList.Reverse();
for (int i = 0; i < countList.Count; i++)
{
if (collist.AnalyzeDatas[i].Value != countList[i])
{
result = false;
}
}
if (result)
{
// 開いているところを塗る
row = 0;
while (row < rowNumbers.Count)
{
if (_bitmapData[row, col].IsValid() == false)
{
_bitmapData[row, col].Paint();
}
row++;
}
collist.Analyzed();
}
col++;
}
}
数える→数を確認する→塗るの順で処理しています。
少しデータの持ち方も変えています。
private List<AnalyzeListData> rowNumbers;
private List<AnalyzeListData> colNumbers;
class AnalyzeListData
{
private bool _analyzed;
public List<AnalyzeData> AnalyzeDatas;
public AnalyzeListData()
{
_analyzed = false;
AnalyzeDatas = new List<AnalyzeData>();
}
public bool IsAnalyzed()
{
return _analyzed;
}
public void Analyzed()
{
_analyzed = true;
}
class AnalyzeData
{
private bool _analyzed;
public int Value { get; }
public AnalyzeData(int value)
{
Value = value;
_analyzed = false;
}
public bool IsAnalyzed()
{
return _analyzed;
}
public void Analyzed()
{
_analyzed = true;
}
}
どのデータを塗ったかどうかを確認できるようにしています。
実行結果はこうなりました。

うん、順調ですね。

前回までの状況はこちら。
最新ソースはこちら。(gitHub)
https://github.com/takishita2nd/Picross
さぁ、解析処理を作っていくぞ。
例題として、こちらの問題を用意しました。

データを入力。

まず、ピクロス解法の定石パターンとして、確実に塗れるところから塗っていくというもの。
この例題からすると、

この赤い部分は全て塗れるのは、すぐに分かりますよね。
さらに、

ここも塗れるのは分かりますでしょうか。
例えば、[1,4,3]と合った場合は、
■×■■■■×■■■
と10マスが確定しますよね?
これを公式化すると、
数字の合計+(数字の数ー1)=マスの数
※1+4+3+(3-1) = 10
となった場合、その列または行の塗れるマスは自動的に確定します。
これを実装します。
// 解析パターンその1
private void pattern1()
{
// Row
pattern1Row();
// Col
pattern1Col();
}
/**
* Rowに対して解析パターン1を適用
*/
private void pattern1Row()
{
int row = 0;
foreach (var rowlist in rowNumbers)
{
int total = 0;
foreach (var v in rowlist)
{
total += v;
}
total += rowlist.Count - 1;
if (total == colNumbers.Count)
{
// 塗れるマス確定
// リストを反転コピー
List<int> revRowList = new List<int>();
foreach (var v in rowlist)
{
revRowList.Add(v);
}
revRowList.Reverse();
int col = 0;
foreach (var v in revRowList)
{
int c;
for (c = 0; c < v; c++)
{
_bitmapData[row, col + c].Paint();
}
if(col + c < colNumbers.Count)
{
_bitmapData[row, col + c].Mask();
c++;
}
col += c;
}
}
row++;
}
}
/**
* Colに対して解析パターン1を適用
*/
private void pattern1Col()
{
int col = 0;
foreach (var collist in colNumbers)
{
int total = 0;
foreach (var v in collist)
{
total += v;
}
total += collist.Count - 1;
if (total == colNumbers.Count)
{
// 塗れるマス確定
// リストを反転コピー
List<int> revColList = new List<int>();
foreach (var v in collist)
{
revColList.Add(v);
}
revColList.Reverse();
int row = 0;
foreach (var v in revColList)
{
int r;
for (r = 0; r < v; r++)
{
_bitmapData[row + r, col].Paint();
}
if (row + r < rowNumbers.Count)
{
_bitmapData[row + r, col].Mask();
r++;
}
row += r;
}
}
col++;
}
}
列の数字データは右から順に並んでいるので、これを反転させる必要があります。
ただ、直接Reverse()を使用すると、インプットデータが壊れてしまうので、コピーを作成してからReverse()を使用します。
あとは、Listの先頭からピクロスのルールに従って塗っていきます。
実行結果はこうなりました。

解析がしやすくなるように、塗れないマスは×を表示するようにしました。
まぁ、ここまでは順調ですな。

みんなそんなにマイクラサーバを立てたいのか。
マインクラフトのサーバを自前で利用することのメリット。
それはハードウェアがあれば無料で運用することができる。
しかし、ハードルはいくつかありまして、
まず、サーバをどこに設置するか。
自宅にサーバを設置する場合、プレイヤーは同じLANの中からアクセスしなければならない。
自宅サーバを外部に開放する場合は、それなりの専門知識が必要だし、セキュリティリスクも発生します。
そこでVPSにサーバを設置するという方法もあります。
VPSを提供するサービスの中には、マインクラフト用テンプレートがあらかじめ用意されているものもあり、それを利用すれば、簡単にマインクラフトサーバを立ち上げることができます。
では、料金的にどうなのか?
Realmを使用する場合、統合版では10プレイヤー用が月470円、10プレイヤー用が月930円です。


Java版の場合は10プレイヤー用が月904円で提供されています。

VPSを使用する場合、Conohaだと月880円~で利用できます。
https://www.conoha.jp/vps/function/minecraft/

プレイヤーの制限はありませんが、利用プレイヤーが増えれば、それだけ要求されるスペックが高くなり、その分コストは高くなります。

これだけ見ると、VPSの方が遙かにコストが高いっすね。
サーバが重くなると、地形の描画に時間がかかったり、ゲームが少し前の状態に巻き戻ってしまう、などの動作異常が頻発します。
特にエリトラで飛行する場合は注意。
たぶん推奨スペックでもエリトラで地図作成する場合はかなりサーバに負荷がかかります。
と言うことで、まとめ。
自宅ネットワークでプレイ→自前サーバ
遠隔地から少人数でプレイ(10人まで)→Realm
大人数でプレイ(11人以上)→VPS
マニアックで物好きな人→VPS
サーバの運用が分からない人→Realm
一人でプレイする人→ローカルで良いんじゃない?
