Evonyのリソース回収について
はじめに
なんとなくDisk整理していたらソースを発見しまいましたのでちょっとだけ書いてみます。
Evonyはリソースを集めて城を強化していくゲームです。なのでリソースが一番大事(集めるだけじゃ戦争では勝てないけれども・・・)です。
[大事な事]
1.リソース関係の研究をちゃんとする。
2.食料消費軽減の研究もちゃんとする。
3.食料回収の城とそれ以外の城を分ける。
4.停戦協定(バブル)をしておく。
Evonyの食料は時間とともに減っていくので4種類のリソースを集めても食料だけは無くなってしまいます。
なので私は食料以外を回収する城と食料だけ回収する城に分けました。
例)食料回収3城、それ以外9城
食料を回収する城は必要最低限の兵しか置かず、研究をちゃんとする事で維持費を減らすと、食料回収量が消費量を余裕で上回ります。
ダラダラとこんな事書いていてもだれも得しないので一応書いてみました。
プログラム
ProgramAutoResource.cs
string[] rss_images = new string[] { @".\template\rss_rock.jpg", @".\template\rss_wood.jpg", @".\template\rss_iron.jpg", @".\template\rss_food.jpg" };
// string[] default_rss_images = new string[] { @".\template\rss_rock.jpg", @".\template\rss_wood.jpg", @".\template\rss_iron.jpg" };
string[] default_rss_images = new string[] { @".\template\rss_rock.jpg", @".\template\rss_food.jpg" };
int default_move_max_count = 4;
public void execute(CancellationToken token, object? param, bool[] rssparam)
{
if (param == null) return;
string[] args = (string[])param;
int max_butai = 5;
bool gameReload = false;
List<string> tempRssImage = new List<string>();
for (int rssparamIndex = 0; rssparamIndex < rssparam.Length; rssparamIndex++)
{
if (rssparam[rssparamIndex])
{
tempRssImage.Add(rss_images[rssparamIndex]);
}
}
if (tempRssImage.Count > 0)
{
default_rss_images = tempRssImage.ToArray();
}
try
{
logger.Info("開始しました。。PORT={0}", args[0]);
// 部隊数
try
{
max_butai = Int32.Parse(args[1]);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return;
}
lib = new AutoPlayLib(args);
int sleep_count = 0;
string[] rss_images = default_rss_images;
List<int[]> move_pattern_table = new List<int[]>();
move_pattern_table.Add(new int[4] { 1, 3, 2, 4 });
move_pattern_table.Add(new int[4] { 1, 4, 2, 3 });
move_pattern_table.Add(new int[4] { 2, 3, 1, 4 });
move_pattern_table.Add(new int[4] { 2, 4, 1, 3 });
move_pattern_table.Add(new int[4] { 3, 1, 4, 2 });
move_pattern_table.Add(new int[4] { 3, 2, 4, 1 });
int[] move_pattern = move_pattern_table[Random.Shared.Next(move_pattern_table.Count)];
int[] swipe = new int[2] { 0, 0 };
int current_action_index = 0;
int move_count = 0;
int move_max_count = default_move_max_count;
int move_step_count = 0;
int stop_count = 0;
int ads_count = 0;
while (true)
{
// キャンセル処理
if (token.IsCancellationRequested)
{
logger.Info("キャンセルされました。PORT={0}", args[0]);
break;
}
Thread.Sleep(1000);
lib.GetScreenShot();
// 不要画面回避設定
if (!SkipAds.Skip(lib))
{
sleep_count = 0;
ads_count++;
if (ads_count > 10)
{
lib.GetScreenShot();
Console.WriteLine("位置変更");
if (lib.CheckImg(@".\template\check_chat_widnow.jpg"))
{
lib.SendBackKeyEvent();
Thread.Sleep(Setting.SLEEP_TIME);
lib.GetScreenShot();
Thread.Sleep(Setting.SLEEP_TIME);
}
if (lib.CheckImg(@".\template\check_catsle.jpg"))
{
sleep_count = 0;
stop_count = stop_count + 1;
move_count = move_count + 1;
if (move_count == move_max_count)
{
move_step_count = move_step_count + 1;
if (move_step_count > 1)
{
move_step_count = 0;
move_max_count = move_max_count + 1;
}
current_action_index = current_action_index + 1;
if (current_action_index == 4)
{
current_action_index = 0;
}
move_count = 0;
}
int next_action = move_pattern[current_action_index];
switch (next_action)
{
case 1:
lib.Swipe(270, 100, 270, 680);
break;
case 2:
lib.Swipe(270, 680, 270, 200);
break;
case 3:
lib.Swipe(105, 480, 435, 480);
break;
case 4:
lib.Swipe(435, 480, 105, 480);
break;
}
}
ads_count = 0;
}
continue;
}
// 地球儀マークが出ている場合は押す
if (lib.TouchImg(@".\template\goto_feald.jpg"))
{
Thread.Sleep(3000);
sleep_count = 0;
}
// 出撃一覧が隠れている場合は開く
else if (lib.TouchImg(@".\template\syutsudou_mark_open.jpg"))
{
Thread.Sleep(Setting.SLEEP_TIME);
sleep_count = 0;
}
// キャンプ(移動失敗分)
else if (lib.CheckImg(@".\template\camp.jpg"))
{
List<System.Drawing.Point> pos = new List<System.Drawing.Point>();
lib.CheckImg2(@".\template\camp.jpg", pos);
if (pos.Count > 0)
{
lib.TouchPos(283, pos[0].Y);
Thread.Sleep(Setting.SLEEP_TIME);
lib.GetScreenShot();
Thread.Sleep(Setting.SLEEP_TIME);
lib.TouchImg(@".\template\camp_confirm.jpg");
Thread.Sleep(Setting.SLEEP_TIME);
lib.GetScreenShot();
Thread.Sleep(Setting.SLEEP_TIME);
}
Thread.Sleep(Setting.SLEEP_TIME);
}
else
{
lib.GetScreenShot();
Thread.Sleep(2000);
int syutudou_count = 0;
bool goto_rss = false;
List<System.Drawing.Point> pos1 = new List<System.Drawing.Point>();
List<System.Drawing.Point> pos2 = new List<System.Drawing.Point>();
lib.CheckImg2(@".\template\syutsudou_mark.jpg", pos1);
lib.CheckImg2(@".\template\syutsudou_mark2.jpg", pos2);
lib.TouchImg(@".\template\syutsudou_mark_close.jpg");
if (pos1.Count + pos2.Count < max_butai)
{
Console.WriteLine($"count = '{pos1.Count}', '{pos2.Count}'");
for (int i = 0; i < rss_images.Length; i++)
{
bool move_flag = false;
lib.GetScreenShot();
Thread.Sleep(Setting.SLEEP_TIME);
List<System.Drawing.Point> pos3 = new List<System.Drawing.Point>();
if (lib.CheckImg2(rss_images[i], pos3))
{
for (int j = 0; j < pos3.Count; j++)
{
lib.TouchPos(pos3[j].X, pos3[j].Y);
Thread.Sleep(500);
lib.GetScreenShot();
Thread.Sleep(500);
if (lib.CheckImg(@".\template\rss_check_teleport.jpg"))
{
int pos_x = pos3[j].X;
int pos_y = pos3[j].Y;
if (pos_x < 220)
{
move_flag = true;
pos_x = 220;
}
if (pos_y < 272)
{
move_flag = true;
pos_y = 272;
}
if (pos_y > 815)
{
move_flag = true;
pos_y = 815;
}
lib.TouchPos(pos_x, pos_y);
goto_rss = false;
if (move_flag) break;
continue;
}
else
{
lib.GetScreenShot();
Thread.Sleep(500);
if (lib.TouchImg(@".\template\rss_ok.jpg"))
{
Thread.Sleep(Setting.SLEEP_TIME);
lib.GetScreenShot();
Thread.Sleep(Setting.SLEEP_TIME);
string movetime = lib.GetText(393, 920, 417, 955);
string movetime2 = lib.GetText2(393, 920, 417, 955);
if (movetime.Equals("") && !movetime2.Equals(""))
{
movetime = movetime2;
}
logger.Info("PORT={0} 移動予想時間={1}", args[0], movetime);
try
{
int value = Int32.Parse(movetime);
if (value < 2)
{
Thread.Sleep(1000);
lib.TouchPos(400, 915);
lib.GetScreenShot();
Thread.Sleep(500);
goto_rss = true;
move_max_count = default_move_max_count;
stop_count = 0;
}
else
{
Console.WriteLine($"遠すぎるため戻ります:'{value}'");
logger.Info("PORT={0} 遠すぎるため戻ります:={1}", args[0], value);
lib.SendBackKeyEvent();
Thread.Sleep(500);
lib.GetScreenShot();
lib.TouchImg(@".\template\home.jpg");
Thread.Sleep(Setting.SLEEP_TIME);
move_pattern = move_pattern_table[Random.Shared.Next(move_pattern_table.Count)];
current_action_index = 0;
move_count = 0;
move_max_count = default_move_max_count;
move_step_count = 0;
stop_count = 0;
goto_rss = true;
}
}
catch (Exception ex)
{
Console.WriteLine($"判定出来ないため戻ります:'{movetime}'");
logger.Info("PORT={0} 判定出来ないため戻ります:={1}", args[0], movetime);
lib.SendBackKeyEvent();
Thread.Sleep(500);
lib.GetScreenShot();
lib.TouchImg(@".\template\home.jpg");
Thread.Sleep(Setting.SLEEP_TIME);
move_pattern = move_pattern_table[Random.Shared.Next(move_pattern_table.Count)];
current_action_index = 0;
move_count = 0;
move_max_count = default_move_max_count;
move_step_count = 0;
stop_count = 0;
goto_rss = true;
}
}
else
{
int pos_x = pos3[j].X;
int pos_y = pos3[j].Y;
lib.TouchPos(pos_x, pos_y);
}
}
if (goto_rss)
{
break;
}
}
}
if (goto_rss)
{
break;
}
}
if (goto_rss == false && syutudou_count < max_butai)
{
lib.GetScreenShot();
Console.WriteLine("位置変更");
if (lib.CheckImg(@".\template\check_chat_widnow.jpg"))
{
lib.SendBackKeyEvent();
Thread.Sleep(Setting.SLEEP_TIME);
lib.GetScreenShot();
Thread.Sleep(Setting.SLEEP_TIME);
}
if (lib.CheckImg(@".\template\check_catsle.jpg"))
{
sleep_count = 0;
stop_count = stop_count + 1;
move_count = move_count + 1;
if (move_count == move_max_count)
{
move_step_count = move_step_count + 1;
if (move_step_count > 1)
{
move_step_count = 0;
move_max_count = move_max_count + 1;
}
current_action_index = current_action_index + 1;
if (current_action_index == 4)
{
current_action_index = 0;
}
move_count = 0;
}
int next_action = move_pattern[current_action_index];
int difRand = Random.Shared.Next(-50, 50);
switch (next_action)
{
case 1:
lib.Swipe(270, 300 + difRand, 270, 680);
break;
case 2:
lib.Swipe(270, 680 + difRand, 270, 300);
break;
case 3:
lib.Swipe(105 + difRand, 480, 435, 480);
break;
case 4:
lib.Swipe(435 + difRand, 480, 105, 480);
break;
}
}
}
}
Thread.Sleep(Setting.SLEEP_TIME);
sleep_count++;
if (sleep_count > 3)
{
lib.SendBackKeyEvent();
Thread.Sleep(Setting.SLEEP_TIME);
sleep_count = 0;
// ちょっと動かしてみる
stop_count = stop_count + 1;
move_count = move_count + 1;
if (move_count == move_max_count)
{
move_step_count = move_step_count + 1;
if (move_step_count > 1)
{
move_step_count = 0;
move_max_count = move_max_count + 1;
}
current_action_index = current_action_index + 1;
if (current_action_index == 4)
{
current_action_index = 0;
}
move_count = 0;
}
int next_action = move_pattern[current_action_index];
int difRand = Random.Shared.Next(-50, 50);
switch (next_action)
{
case 1:
lib.Swipe(270, 300 + difRand, 270, 680);
break;
case 2:
lib.Swipe(270, 680 + difRand, 270, 300);
break;
case 3:
lib.Swipe(105 + difRand, 480, 435, 480);
break;
case 4:
lib.Swipe(435 + difRand, 480, 105, 480);
break;
}
}
}
}
}
catch (Exception ex)
{
logger.Error(ex, $"PORT='{args[0]}'");
}
logger.Info("終了しました。。PORT={0}", args[0]);
実は結構苦戦しまして、謎なプログラムが多数入っています。
画面をキャプチャして画像判定してなどとやっていても、画面端だったりすると位置がずれて変なもの指してしまうことがあったりします。そのためにキャンプになってしまったりするので、キャンプになったら帰ってくるようにしています。また、妙に遠くの座標に突然移動してしまうことがあったので移動時間を見て、遠くに行かないようにしたりしています。
あと他の人が入っている場所には行かないようしていますが、相手も進行中だったりするとぶつかってしまいますので停戦協定(バブル)は使っておいた方が迷惑かけずにすみます。(もちろん自分の部隊は攻撃されると思いますが、自動化のコストと思ってあきらめてました)
MAPの移動方法はかなり適当なので自分で見ていても微妙でした。良い案がある方は改良・差し替えをオススメします。
あとがき
なんとなくダラダラ書いてみましたが、なぜ書いているかというと・・・競艇AI(もどき)の開発に行き詰ったので気分転換したかったら!
また開発に行き詰ったらEvony石板割とか書くかもしれないです。
1枠が強すぎる!!!