Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Text;
using System.IO;
using System.Drawing;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Linq;
using System.Net.Sockets;
using System.Drawing.Imaging;
namespace csharp {
public static class Ext {
public static void Foreach<T>(this IEnumerable<T> src, Action<T> func)
{
foreach (var s in src) {
func(s);
}
}
}
public class Sok : IDisposable {
TcpClient client;
NetworkStream ns;
StreamReader sr;
StreamWriter sw;
public Sok(string address, int host)
{
client = new TcpClient(address, host);
ns = client.GetStream();
sr = new StreamReader(ns);
sw = new StreamWriter(ns);
}
public void ReadAll(){
System.IO.MemoryStream ms = new System.IO.MemoryStream();
byte[] resBytes = new byte[256];
do
{
//データの一部を受信する
int resSize = ns.Read(resBytes, 0, resBytes.Length);
//Readが0を返した時はサーバーが切断したと判断
if (resSize == 0)
{
Console.WriteLine("サーバーが切断しました。");
break;
}
//受信したデータを蓄積する
ms.Write(resBytes, 0, resSize);
} while (ns.DataAvailable);
//受信したデータを文字列に変換
string resMsg = Encoding.ASCII.GetString(ms.ToArray());
ms.Close();
Console.WriteLine(resMsg);
}
public string ReadLine()
{
while (true) {
string ret = sr.ReadLine();
if (ret != null) {
if (ret.Length > 60) Console.WriteLine("<read> : " + ret.Substring(0, 60) + "...");
else Console.WriteLine("<read> : " + ret);
if (ret.Contains("checkp") || ret.Contains("Congrats!")) {
File.AppendAllText("key.txt",ret + "\n");
}
return ret;
}
Wait();
}
}
public void WriteLine(string text)
{
Console.WriteLine("<write> : " + text);
sw.Write(text + "\n\n"); // add emptyline
sw.Flush();
}
public void Wait()
{
System.Threading.Thread.Sleep(10);
}
public void Dispose()
{
ns.Close();
client.Close();
}
}
class csharp{
Image FromBase64(string base64)
{
var png_data = Convert.FromBase64String(base64);
var stream = new MemoryStream(png_data);
Image img = Image.FromStream(stream);
return img;
}
List<bool[]> convertToArray(Image img,int th = 255)
{
List<bool[]> ret = new List<bool[]>();
for (int i = 0; i < img.Height; i++) ret.Add(new bool[img.Width]);
Bitmap bmp = new Bitmap(img);
BitmapData bmpData = bmp.LockBits(
new Rectangle(Point.Empty, bmp.Size),
ImageLockMode.ReadWrite,
PixelFormat.Format32bppArgb);
unsafe {
byte* pixel = (byte*)bmpData.Scan0;
int dataLength = bmpData.Stride * bmpData.Height;
for (int i = 0; i < dataLength; i += 4) {
byte b = *(pixel++);
byte g = *(pixel++);
byte r = *(pixel++);
byte a = *(pixel++);
ret[i / bmpData.Stride][i % bmpData.Stride / 4] = r < th; // 黒色だけ抽出
}
}
bmp.UnlockBits(bmpData);
return ret;
}
void SwapList(List<int> l, int i, int j)
{
int tmp = l[i];
l[i] = l[j];
l[j] = tmp;
}
// [150,450) 縦棒
int Amida(List<bool[]> img){
//縦棒の位置をスキャン
int W = img[0].Length;
List<int> tate = new List<int>();
for (int i = 0; i < W - 1; i++) {
int H = 151;
if (/*!img[H-1][i] && */ !img[H][i] && img[H][i + 1]) tate.Add(i);
}
List<int> perm = Enumerable.Range(1,tate.Count).ToList();
for (int i = 150; i < 450; i++) {
for (int j = 0; j < tate.Count - 1; j++) {
int middle = (tate[j] + tate[j + 1]) / 2;
if (!img[i - 1][middle] && img[i][middle]) {
//横棒発見
SwapList(perm, j, j + 1);
}
}
}
//丸どこ?
int circleH = 470;
for (int i = 0; i < tate.Count; i++) {
if (img[circleH][tate[i]]) {
return perm[i];
}
}
return -1; //??
}
int bfs(int sh, int sw, List<bool[]> ary)
{
int ret = 1;
Queue<Point> q = new Queue<Point>();
q.Enqueue(new Point(sw, sh));
ary[sh][sw] = false;
while (q.Count != 0) {
Point p = q.Dequeue();
int h = p.Y; int w = p.X;
int[] dh = { 1, 0, -1, 0 };
int[] dw = { 0, 1, 0, -1 };
for (int i = 0; i < 4; i++) {
int nh = h + dh[i], nw = w + dw[i];
if (0 <= nh && nh < 600 && 0 <= nw && nw < 600) {
if (ary[nh][nw]) {
ary[nh][nw] = false;
ret++;
q.Enqueue(new Point(nw, nh));
}
}
}
}
return ret;
}
List<bool[]> copy(List<bool[]> ary)
{
List<bool[]> copyed = new List<bool[]>();
foreach (var x in ary) {
bool[] y = new bool[x.Length];
for (int i = 0; i < x.Length; i++) y[i] = x[i];
copyed.Add(y);
}
return copyed;
}
double getNumberDist(Point pt, List<Tuple<Point, int>> l)
{
double mn = 100000;
foreach (var t in l) {
if (t.Item2 > 300) continue;// 黒丸 or アミダ
double dx = pt.X - t.Item1.X;
double dy = pt.Y - t.Item1.Y;
mn = Math.Min(mn,Math.Sqrt(dx * dx + dy * dy));
}
return mn;
}
List<Tuple<Point, int>> getTuple(List<bool[]> ary)
{
List<bool[]> copyed = copy(ary);
List<Tuple<Point, int>> l = new List<Tuple<Point, int>>();
for (int h = 0; h < 600; h++) {
for (int w = 0; w < 600; w++) {
if (copyed[h][w]) {
int count = bfs(h, w, copyed);
l.Add(Tuple.Create(new Point(w, h), count));
}
}
}
return l;
}
List<float> getAngleByConnectedComponents(Image img, List<bool[]> ary)
{
var l = getTuple(ary);
//アミダ以外埋める
Tuple<Point, int> ch = l.Find((t) => t.Item2 == l.Max((y) => y.Item2));
List<bool[]> copyed = copy(ary);
foreach (var t in l) {
if (ch != t) {
bfs(t.Item1.Y, t.Item1.X, copyed);
}
}
//左上は1に近い.1は最もピクセル数が少ない…?(実は7の方が少ない)
// 右上の数字は?
Tuple<Point, int> one = null, LargestNum = null;
{
double dist = 0;
foreach (var t in l) {
if (t.Item2 > 300) continue;// 黒丸 or アミダ
foreach (var u in l) {
if (u.Item2 > 300) continue;// 黒丸 or アミダ
double dx = t.Item1.X - u.Item1.X;
double dy = t.Item1.Y - u.Item1.Y;
double tmp = Math.Sqrt(dx * dx + dy * dy);
if (tmp > dist) {
dist = tmp;
one = t;
LargestNum = u;
}
}
}
if (one.Item2 > LargestNum.Item2) {
Tuple<Point, int> tmp = one;
one = LargestNum;
LargestNum = tmp;
}
}
Point nearestOne = new Point(-1, -1);
{
double dist = 1000000;
for (int h = 0; h < 600; h++) {
for (int w = 0; w < 600; w++) {
if (copyed[h][w]) {
double dx = w - one.Item1.X;
double dy = h - one.Item1.Y;
double tmp = Math.Sqrt(dx * dx + dy * dy);
if (tmp < dist) {
dist = tmp;
nearestOne = new Point(w, h);
}
}
}
}
}
{
double dist = 0;
foreach (var t in l) {
if (t.Item2 > 300) continue;// 黒丸 or アミダ
double dx = t.Item1.X - one.Item1.X;
double dy = t.Item1.Y - one.Item1.Y;
double tmp = Math.Sqrt(dx * dx + dy * dy);
if (tmp > dist) {
dist = tmp;
LargestNum = t;
}
}
}
//右上の数字に近い点
Point nearestLast = new Point(-1, -1);
{
double dist = 1000000;
for (int h = 0; h < 600; h++) {
for (int w = 0; w < 600; w++) {
if (copyed[h][w]) {
double dx = w - LargestNum.Item1.X;
double dy = h - LargestNum.Item1.Y;
double tmp = Math.Sqrt(dx * dx + dy * dy);
if (tmp < dist) {
dist = tmp;
nearestLast = new Point(w, h);
}
}
}
}
}
Point diff = new Point(nearestLast.X - nearestOne.X, nearestLast.Y - nearestOne.Y);
double angle = -Math.Atan2(diff.Y, diff.X);
List<float> ret = new List<float>();
ret.Add((float)angle);
for (double i = -Math.PI / 1080; i < Math.PI / 1080; i += Math.PI / 1080) {
ret.Add((float)(angle + i));
}
return ret;
}
bool gyaku(Image img, float angle)
{
Image rot = RotImage(img, angle);
var nw_ary = convertToArray(rot);
var l = getTuple(nw_ary);
if (l.First().Item2 > 300) {
// 上に黒丸来てる
return true;
}
return false;
}
Image RotImage(Image img,float angle)
{
angle = (float)(angle / Math.PI * 180f);
Bitmap canvas = new Bitmap(img.Width, img.Height);
var g = Graphics.FromImage(canvas);
g.FillRectangle(Brushes.White, new Rectangle(0, 0, img.Width, img.Height));
g.TranslateTransform(-img.Width / 2, -img.Height / 2);
g.RotateTransform(angle, System.Drawing.Drawing2D.MatrixOrder.Append);
g.TranslateTransform(img.Width / 2, img.Height / 2, System.Drawing.Drawing2D.MatrixOrder.Append);
g.DrawImage(img, new Rectangle(0, 0, img.Width, img.Height));
g.Dispose();
return canvas;
}
int SolveRotate(Image img,List<bool[]> current_ary,int stage,int rank)
{
var angles = getAngleByConnectedComponents(img, current_ary);
bool g = gyaku(img, angles[0]);
if (g) {
for (int i = 0; i < angles.Count; i++) angles[i] += (float)Math.PI;
}
foreach (var angle in angles) {
using (var new_img = RotImage(img, angle)) {
var nw_ary = convertToArray(new_img);
int ans = Amida(nw_ary);
new_img.Save(string.Format("{0}_{1}_rot.png", stage, rank));
if (ans != -1) {
return ans;
}
}
}
Console.WriteLine("前回と同じ答えでごまかす");
return -1;
}
void main()
{
using (Sok sok = new Sok("203.178.132.117", 42719)) {
int rank = 1,stage = 1;
int last_ans = -1;
while (true) {
string line = sok.ReadLine();
string rank_str = string.Format("#{0}", rank);
if (line != rank_str) continue;
Console.WriteLine("stage : {0} , rank : {1} ", stage, rank);
string png_base64 = sok.ReadLine();
sok.ReadLine();
var img = FromBase64(png_base64);
if (stage < 10) {
var ary = convertToArray(img,200);
int ans = Amida(ary);
sok.WriteLine(ans.ToString());
}
else {
img.Save(string.Format("{0}_{1}.png", stage, rank));
var current_ary = convertToArray(img);
int index = SolveRotate(img, current_ary,stage,rank);
if (index == -1) index = last_ans;
last_ans = index;
sok.WriteLine(index.ToString());
}
rank++;
if (rank > 50) {
stage++;
rank = 1;
}
}
}
}
void rot_test()
{
var img = Image.FromFile("13_1.png");
var ary = convertToArray(img,200);
int index = SolveRotate(img, ary,13,1);
Console.WriteLine(index.ToString());
}
private static void Main(string[] args)
{
new csharp().main();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment