/// <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? // 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)); }
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); }