using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using CDSAE3_Lian_Lian_Kan.Forms.Interface; namespace CDSAE3_Lian_Lian_Kan.Boards { internal class Graph_Board : IBoard { class Node { public Node? LNode, RNode, UNode, DNode; public int x, y; public int value; public Node(int x, int y, int value) { this.x = x; this.y = y; this.value = value; LNode = RNode = UNode = DNode = null; } public Node(Node? lNode, Node? rNode, Node? uNode, Node? dNode, int x, int y, int value) { LNode = lNode; RNode = rNode; UNode = uNode; DNode = dNode; this.x = x; this.y = y; this.value = value; } } public (int, int) size { get; set; }//width,height Dictionary<(int,int),Node>Index = new Dictionary<(int,int), Node>();//width,height private Dictionary> boardIndex = new Dictionary>(); Board_funcs board_Funcs = new Board_funcs(); private int total; private int Total { get { return total; } set { total = value; if (Total == 0) Etcs.gameModeForm?.Finished_Handler(this, new FinishArgs { finishType = FinishArgs.FinishType.All_done }); } } private int[] Vals_per_Image { get; set; } = Array.Empty(); public void decrease(params (int, int)[] poss) { foreach (var (x, y) in poss) { int type = Index[(x, y)].value; if(Index.TryGetValue((x,y),out Node? node)) { if (node.RNode != null) node.RNode.LNode = node.LNode; if(node.LNode!=null) node.LNode.RNode = node.RNode; if(node.DNode!=null) node.DNode.UNode = node.UNode; if(node.UNode!=null) node.UNode.DNode = node.DNode; Index.Remove((x, y)); } else throw new Exception("Val not Found in Index"); if (!boardIndex[type].Remove((x, y))) throw new Exception("Val not Found in board_Index"); Vals_per_Image[type]--; Total--; } } public List> get_tip((int, int) start) { List> ans = new List>(); if (boardIndex.TryGetValue(Index[start].value, out var tip)) foreach (var pos in tip) { var (result, path) = test(start, pos); if (result && path != null) ans.Add(path); } return ans; } public int[,] make_board() { size = Etcs.get_length_width(); var (width, height) = size; int[,]Bd = new int[height + 2, width + 2]; for (int i = 0; i < height + 2; i++) for (int j = 0; j < width + 2; j++) { Bd[i, j] = -1; Index.Add((j, i), new Node(j, i, -1)); } bool doSwap_causeByOddtotal = false; int sum = width * height; if (sum % 2 != 0) { doSwap_causeByOddtotal = true; sum--; } total = sum; int types = Etcs.Images_size(); Vals_per_Image = board_Funcs.get_vals_per_image(Total, types); int last_val = -1; int cur_width = 1, cur_height = 1; var temp_val_per_Image = (int[])Vals_per_Image.Clone(); for (int i = 0; i < sum; i++) { Bd[cur_height, cur_width] = board_Funcs.getval(ref temp_val_per_Image, ref last_val, types); if (boardIndex.TryGetValue(Bd[cur_height, cur_width], out var index)) index.Add((cur_width, cur_height)); else boardIndex.Add(Bd[cur_height, cur_width], new List<(int, int)> { (cur_width, cur_height) }); Index[(cur_width, cur_height)].value = Bd[cur_height, cur_width]; cur_width++; if (cur_width > width) { cur_height++; cur_width = 1; } } if (doSwap_causeByOddtotal) (Bd[height, width], Bd[(height + 1) / 2, (width + 1) / 2]) = (Bd[(height + 1) / 2, (width + 1) / 2], Bd[height, width]); foreach(var (index,node)in Index) { if (Index.TryGetValue((node.x - 1, node.y), out var lnode)) node.LNode = lnode; if (Index.TryGetValue((node.x + 1, node.y), out var rnode)) node.RNode = rnode; if (Index.TryGetValue((node.x, node.y - 1), out var unode)) node.UNode = unode; if (Index.TryGetValue((node.x, node.y + 1), out var dnode)) node.DNode = dnode; Index[index] = node; } return Bd; } public int[,] remake_board() { boardIndex.Clear(); int[] temp_val_per_Image = (int[])Vals_per_Image.Clone(); var (width, height) = size; int[,] Bd = new int[height + 2, width + 2]; for (int i = 0; i < height + 2; i++) for (int j = 0; j < width + 2; j++) Bd[i, j] = -1; int last_val = -1; foreach(var (index,node) in Index) { if(node.value==-1) continue; node.value = board_Funcs.getval(ref temp_val_per_Image, ref last_val, Etcs.Images_size()); Bd[node.y,node.x] = node.value; if(boardIndex.TryGetValue(node.value,out var list)) list.Add((node.x, node.y)); else boardIndex.Add(node.value, new List<(int, int)> { (node.x, node.y) }); } return Bd; } public (bool, List<(int, int)>?) test((int, int) a, (int, int) b) { if(a==b) return (false, null); int xa, ya, xb, yb; if (Index.TryGetValue(a, out var nodeA) && Index.TryGetValue(b, out var nodeB)) { if (nodeA.value != nodeB.value) return (false,null); else { (xa, ya) = a; (xb, yb) = b; } } else return (false, null); Func line_test = (bool x, int ct, int from, int to) => {//ct is x (x==true)left to right ///up to down ///Index must contain from or to ///只管中间 if (from > to) (from, to) = (to, from); if(ct==0||(ct == size.Item1+1&&!x)||(ct==size.Item2+1&&x)) return true; if(x) { var node = Index[(0, ct)].RNode; while(node!=null) { if (node.x > to) return true; if (node.x > from && node.x < to) return false; node = node.RNode; } return true; } else { var node = Index[(ct, 0)].DNode; while (node != null) { if (node.y > to) return true; if (node.y > from && node.y < to) return false; node = node.DNode; } return true; } }; if (xa == xb) if (line_test(false, xa, ya, yb)) return (true, new List<(int, int)> { a, b }); if (ya == yb) if (line_test(true, ya, xa, xb)) return (true, new List<(int, int)> { a, b }); {//two line test (int, int) extra_pa = (xa, yb); (int, int) extra_pb = (xb, ya); if (!Index.ContainsKey(extra_pa)) if (line_test(true, yb, xa, xb) && line_test(false, xa, ya, yb)) return (true, new List<(int, int)> { a, extra_pa, b }); if (!Index.ContainsKey(extra_pb)) if (line_test(true, ya, xa, xb) && line_test(false, xb, ya, yb)) return (true, new List<(int, int)> { a, extra_pb, b }); } (int, int)[] squareA = new (int, int)[4]; (int, int)[] squareB = new (int, int)[4];//urdl {//three line test Func get_square = (Node node) => { (int, int)[] result = new (int, int)[4]; result[0] = (node.UNode!.x, node.UNode!.value==-1? node.UNode!.y: node.UNode!.y + 1); result[1] = (node.RNode!.value==-1? node.RNode!.x: node.RNode!.x - 1, node.RNode!.y); result[2] = (node.DNode!.x, node.DNode!.value==-1? node.DNode!.y: node.DNode!.y - 1); result[3] = (node.LNode!.value==-1? node.LNode!.x: node.LNode!.x + 1, node.LNode!.y); return result; }; squareA = get_square(nodeA); squareB = get_square(nodeB); Func<(int, int), (int, int), (bool, (int, int))> intersection = ((int, int) a, (int, int) b) =>//first small last big { if(a.Item1==a.Item2&&b.Item1==b.Item2&& a.Item1 == b.Item1) return (false, (-1, -1)); if (a.Item1 > b.Item1) (a, b) = (b, a); if (a.Item2 < b.Item1) return (false, (-1, -1)); if (a.Item2 > b.Item2) return (true, (b.Item1, b.Item2)); return (true, (b.Item1, a.Item2)); }; var (throughx, xrange) = intersection((squareA[3].Item1, squareA[1].Item1), (squareB[3].Item1, squareB[1].Item1)); var (throughy, yrange) = intersection((squareA[0].Item2, squareA[2].Item2), (squareB[0].Item2, squareB[2].Item2)); Func<(int, int), int, List> swing_check = ((int, int) range, int center) => { List result = new List(); if (center < range.Item1) { for (int k = range.Item1; k <= range.Item2; k++) result.Add(k); return result; } if (center > range.Item2) { for (int k = range.Item2; k >= range.Item1; k--) result.Add(k); return result; } result.Add(center); Func inrange = (int t) => t >= range.Item1 && t <= range.Item2; bool go_on = true; for (int i = 1; go_on; i++) { go_on = false; if (go_on |= inrange(center + i)) result.Add(center + i); if (go_on |= inrange(center - i)) result.Add(center - i); } return result; }; if (throughx) foreach (int i in swing_check(xrange, a.Item1)) if (line_test(false, i, a.Item2, b.Item2)) return (true, new List<(int, int)> { a, (i, a.Item2), (i, b.Item2), b }); if (throughy) foreach (int i in swing_check(yrange, a.Item2)) if (line_test(true, i, a.Item1, b.Item1)) return (true, new List<(int, int)> { a, (a.Item1, i), (b.Item1, i), b }); } return (false, null); } public (int, int) GetRandomBlock() { Random random = new(); int k = random.Next(0, boardIndex.Count); for(int i = 0;i