private StateHash CalculateStateHash(MapTile pos1, MapTile pos2, MapTile pos3, MapTile pos4, MapTile[] positions, eMapSymmetry symmetry) { StateHash sh; sh.a = 0; sh.b = 0; sh.c = 0; sh.d = 0; #if SYMMETRY_FOR_STATE_HASH_CHECK if (pos1 != null) { sh.Add(pos1.Index[(int)symmetry], 1); } if (pos2 != null) { sh.Add(pos2.Index[(int)symmetry], 1); } if (pos3 != null) { sh.Add(pos3.Index[(int)symmetry], 1); } if (pos4 != null) { sh.Add(pos4.Index[(int)symmetry], 1); } for (int idx = 0; idx < positions.Length; idx++) { if (positions[idx] != null) { sh.Add(positions[idx].Index[(int)symmetry], 2); } } #else if (pos1 != null) { sh.Add(pos1.Index, 1); } if (pos2 != null) { sh.Add(pos2.Index, 1); } if (pos3 != null) { sh.Add(pos3.Index, 1); } if (pos4 != null) { sh.Add(pos4.Index, 1); } for (int idx = 0; idx < positions.Length; idx++) { if (positions[idx] != null) { sh.Add(positions[idx].Index, 2); } } #endif return(sh); }
private MapTile[,] tiles; // x,y indexing private bool LoadMapImpl(Tuple <MapTile.TileType, MovingObject.ObjectType>[,] map) { this.width = map.GetLength(1); this.height = map.GetLength(0); tiles = new MapTile[width, height]; ExitTile = null; int actorsCount = 0; int x = 0, y = 0; int index = 0; foreach (var t in map) { x = index % width; y = index / width; index++; MapTile.TileType tileType = t.Item1; MovingObject.ObjectType objectType = t.Item2; var tile = new MapTile(tileType, x, y, index, this); tiles[x, y] = tile; if (tileType == MapTile.TileType.Exit) { if (ExitTile != null) { //Console.WriteLine( "Map exit already defined" ); return(false); } ExitTile = tile; } if (objectType != MovingObject.ObjectType.None) { tile.obj = new MovingObject { type = objectType } } ; if (objectType == MovingObject.ObjectType.Actor) { actors[actorsCount++] = tile; } else if (objectType == MovingObject.ObjectType.AntiActor) { contrActors.Add(tile); } } if (index != width * height) { //Console.WriteLine( "Invalid map data" ); return(false); } if (TestIsOn == false && actorsCount == 0) { //Console.WriteLine( "No actors on map" ); return(false); } if (TestIsOn == false && ExitTile == null) { //Console.WriteLine( "No exit on map" ); return(false); } SetupTileNeighbourhood(); Symmetry = eMapSymmetry.None; FindSymmetry(); var res = CalculateDistanceToExit(); return(res); }
/// <summary> /// Most game logic is implemented in this method. /// </summary> public GameState GetNewState(GameState currentState, Direction dir, Func <StateHash, bool> checkHash) { MapTile pos1 = null; MapTile pos2 = null; MapTile pos3 = null; MapTile pos4 = null; MapTile[] contractorNewPos = new MapTile[currentState.ContrActors.Length]; currentState.ContrActors.CopyTo(contractorNewPos, 0); // TODO: Boxes pushed by Actors and Contractors? if (actor1.Push(dir) == false) { return(null); } if (actor2.Push(dir) == false) { return(null); } if (actor3.Push(dir) == false) { return(null); } if (actor4.Push(dir) == false) { return(null); } // Step 1: Just Actors are moving. All movements are simultaneous. if (currentState.pos1 != null && GetNewPos(currentState.pos1, dir, out pos1) == false) { return(null); } if (currentState.pos2 != null && GetNewPos(currentState.pos2, dir, out pos2) == false) { return(null); } if (currentState.pos3 != null && GetNewPos(currentState.pos3, dir, out pos3) == false) { return(null); } if (currentState.pos4 != null && GetNewPos(currentState.pos4, dir, out pos4) == false) { return(null); } // Check Actors colliding themselves. if (pos1 != null && (pos1 == pos2 || pos1 == pos3 || pos1 == pos4) || pos2 != null && (pos2 == pos3 || pos2 == pos4) || pos3 != null && pos3 == pos4) { return(null); } // Step 2: ContrActors are moving. All movements are simultaneous. Check for collision with Actors the same time. // Consider removing Contractors from the list instead of nullifying them for (int idx = 0; idx < contractorNewPos.Length; idx++) { MapTile pos = contractorNewPos[idx]; if (contractorNewPos[idx] != null) { // Check for collision with Actors before movement if (pos1 != null && pos1 == pos || pos2 != null && pos2 == pos || pos3 != null && pos3 == pos || pos4 != null && pos4 == pos) { return(null); } GetNewPos(pos, (Direction)((int)dir ^ 2), out pos); if (pos != null) { // Check for collision with Actors after movement if (pos1 != null && pos1 == pos || pos2 != null && pos2 == pos || pos3 != null && pos3 == pos || pos4 != null && pos4 == pos) { return(null); } // Check for collision with other Contractors, remove collided for (int idxInner = 0; idxInner < idx; idxInner++) { if (contractorNewPos[idxInner] == pos) { pos = null; break; } } } contractorNewPos[idx] = pos; } } // Step 3: Actors are pushed by pushers. All movements are simultaneous. if (pos1 != null && GetNewPos(pos1, null, out pos1) == false) { return(null); } if (pos2 != null && GetNewPos(pos2, null, out pos2) == false) { return(null); } if (pos3 != null && GetNewPos(pos3, null, out pos3) == false) { return(null); } if (pos4 != null && GetNewPos(pos4, null, out pos4) == false) { return(null); } // Check Actors colliding themselves. if (pos1 != null && (pos1 == pos2 || pos1 == pos3 || pos1 == pos4) || pos2 != null && (pos2 == pos3 || pos2 == pos4) || pos3 != null && pos3 == pos4) { return(null); } // Step 3: Contractors and Boxes are pushed by pushers. All movements are simultaneous. for (int idx = 0; idx < contractorNewPos.Length; idx++) { MapTile pos = contractorNewPos[idx]; if (pos != null) { GetNewPos(pos, null, out pos); if (pos != null) { // Check for collision with Actors after movement if (pos1 != null && pos1 == pos || pos2 != null && pos2 == pos || pos3 != null && pos3 == pos || pos4 != null && pos4 == pos) { return(null); } // Check for collision with other Contractors, remove collided for (int idxInner = 0; idxInner < idx; idxInner++) { if (contractorNewPos[idxInner] == pos) { pos = null; break; } } } contractorNewPos[idx] = pos; } } // Check if we already have same state var hash = CalculateStateHash(pos1, pos2, pos3, pos4, contractorNewPos, eMapSymmetry.None); if (checkHash != null && checkHash(hash) == false) { return(null); } #if SYMMETRY_FOR_STATE_HASH_CHECK for (eMapSymmetry s = eMapSymmetry.Horizontal; s <= eMapSymmetry.Both; s++) { if ((Symmetry & s) == s) { var hashOther = CalculateStateHash(pos1, pos2, pos3, pos4, s); if (checkHash(hashOther) == false) { return(null); } } } #endif return(new GameState(currentState, pos1, pos2, pos3, pos4, contractorNewPos, dir, hash)); }
public GameState(GameState prevState, MapTile pos1, MapTile pos2, MapTile pos3, MapTile pos4, MapTile[] contrActors, Direction moveDir, StateHash hash) { this.PrevState = prevState; this.pos1 = pos1; this.pos2 = pos2; this.pos3 = pos3; this.pos4 = pos4; this.ContrActors = contrActors; this.moveDir = moveDir; this.Hash = hash; if (prevState != null) { turn = prevState.turn + 1; } }