void Genetic::workout(std::ostream & fout) { // Answer answer(ncity); Answer ** colony = new Answer*[SIZE]; for (size_t i = 0; i < SIZE; i++) { colony[i] = new Answer(ncity); } Answer ** nextGene = new Answer*[SIZE]; for (size_t i = 0; i < SIZE; i++) { nextGene[i] = new Answer(ncity); } int t = 0; double bestAnswer = 0.0; int bestGeneId = -1; initPopulation(colony, SIZE); int gene_num = 1000 * ncity; while (t < gene_num) { // 结束条件: 遗传代数到达城市数目的1000倍 bestGeneId = nextGeneration(colony, nextGene); bestAnswer = total_cost(*colony[bestGeneId]); // print(fout, colony[bestGeneId]); // (9) for (size_t i = 0; i < SIZE; i++) { *colony[i] = *nextGene[i]; } t = t + 1; } // (10) print(fout, colony[bestGeneId]); std::cout << bestAnswer << std::endl; }
void Genetic::print(std::ostream & fout, Answer * answer) { for (size_t i = 0; i < ncity; i++) { fout << m_vc[(*answer)[i]].getName() << ' '; if (i + 1 == ncity) { fout << std::setprecision(5) << total_cost(*answer) << std::endl; } } }
/** * Clone a vehicle. If it is a train, it will clone all the cars too * @param tile tile of the depot where the cloned vehicle is build * @param flags type of operation * @param p1 the original vehicle's index * @param p2 1 = shared orders, else copied orders * @param text unused * @return the cost of this operation or an error */ CommandCost CmdCloneVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { CommandCost total_cost(EXPENSES_NEW_VEHICLES); Vehicle *v = Vehicle::GetIfValid(p1); if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR; Vehicle *v_front = v; Vehicle *w = NULL; Vehicle *w_front = NULL; Vehicle *w_rear = NULL; /* * v_front is the front engine in the original vehicle * v is the car/vehicle of the original vehicle that is currently being copied * w_front is the front engine of the cloned vehicle * w is the car/vehicle currently being cloned * w_rear is the rear end of the cloned train. It's used to add more cars and is only used by trains */ CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; if (v->type == VEH_TRAIN && (!v->IsFrontEngine() || Train::From(v)->crash_anim_pos >= 4400)) return CMD_ERROR; /* check that we can allocate enough vehicles */ if (!(flags & DC_EXEC)) { int veh_counter = 0; do { veh_counter++; } while ((v = v->Next()) != NULL); if (!Vehicle::CanAllocateItem(veh_counter)) { return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME); } } v = v_front; do { if (v->type == VEH_TRAIN && Train::From(v)->IsRearDualheaded()) { /* we build the rear ends of multiheaded trains with the front ones */ continue; } /* In case we're building a multi headed vehicle and the maximum number of * vehicles is almost reached (e.g. max trains - 1) not all vehicles would * be cloned. When the non-primary engines were build they were seen as * 'new' vehicles whereas they would immediately be joined with a primary * engine. This caused the vehicle to be not build as 'the limit' had been * reached, resulting in partially build vehicles and such. */ DoCommandFlag build_flags = flags; if ((flags & DC_EXEC) && !v->IsPrimaryVehicle()) build_flags |= DC_AUTOREPLACE; CommandCost cost = DoCommand(tile, v->engine_type | (1 << 16), 0, build_flags, GetCmdBuildVeh(v)); if (cost.Failed()) { /* Can't build a part, then sell the stuff we already made; clear up the mess */ if (w_front != NULL) DoCommand(w_front->tile, w_front->index | (1 << 20), 0, flags, GetCmdSellVeh(w_front)); return cost; } total_cost.AddCost(cost); if (flags & DC_EXEC) { w = Vehicle::Get(_new_vehicle_id); if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) { SetBit(Train::From(w)->flags, VRF_REVERSE_DIRECTION); } if (v->type == VEH_TRAIN && !v->IsFrontEngine()) { /* this s a train car * add this unit to the end of the train */ CommandCost result = DoCommand(0, w->index | 1 << 20, w_rear->index, flags, CMD_MOVE_RAIL_VEHICLE); if (result.Failed()) { /* The train can't be joined to make the same consist as the original. * Sell what we already made (clean up) and return an error. */ DoCommand(w_front->tile, w_front->index | 1 << 20, 0, flags, GetCmdSellVeh(w_front)); DoCommand(w_front->tile, w->index | 1 << 20, 0, flags, GetCmdSellVeh(w)); return result; // return error and the message returned from CMD_MOVE_RAIL_VEHICLE } } else { /* this is a front engine or not a train. */ w_front = w; w->service_interval = v->service_interval; w->SetServiceIntervalIsCustom(v->ServiceIntervalIsCustom()); w->SetServiceIntervalIsPercent(v->ServiceIntervalIsPercent()); } w_rear = w; // trains needs to know the last car in the train, so they can add more in next loop } } while (v->type == VEH_TRAIN && (v = v->GetNextVehicle()) != NULL); if ((flags & DC_EXEC) && v_front->type == VEH_TRAIN) { /* for trains this needs to be the front engine due to the callback function */ _new_vehicle_id = w_front->index; } if (flags & DC_EXEC) { /* Cloned vehicles belong to the same group */ DoCommand(0, v_front->group_id, w_front->index, flags, CMD_ADD_VEHICLE_GROUP); } /* Take care of refitting. */ w = w_front; v = v_front; /* Both building and refitting are influenced by newgrf callbacks, which * makes it impossible to accurately estimate the cloning costs. In * particular, it is possible for engines of the same type to be built with * different numbers of articulated parts, so when refitting we have to * loop over real vehicles first, and then the articulated parts of those * vehicles in a different loop. */ do { do { if (flags & DC_EXEC) { assert(w != NULL); /* Find out what's the best sub type */ byte subtype = GetBestFittingSubType(v, w, v->cargo_type); if (w->cargo_type != v->cargo_type || w->cargo_subtype != subtype) { CommandCost cost = DoCommand(0, w->index, v->cargo_type | 1U << 7 | (subtype << 8), flags, GetCmdRefitVeh(v)); if (cost.Succeeded()) total_cost.AddCost(cost); } if (w->IsGroundVehicle() && w->HasArticulatedPart()) { w = w->GetNextArticulatedPart(); } else { break; } } else { const Engine *e = v->GetEngine(); CargoID initial_cargo = (e->CanCarryCargo() ? e->GetDefaultCargoType() : (CargoID)CT_INVALID); if (v->cargo_type != initial_cargo && initial_cargo != CT_INVALID) { bool dummy; total_cost.AddCost(GetRefitCost(NULL, v->engine_type, v->cargo_type, v->cargo_subtype, &dummy)); } } if (v->IsGroundVehicle() && v->HasArticulatedPart()) { v = v->GetNextArticulatedPart(); } else { break; } } while (v != NULL); if ((flags & DC_EXEC) && v->type == VEH_TRAIN) w = w->GetNextVehicle(); } while (v->type == VEH_TRAIN && (v = v->GetNextVehicle()) != NULL); if (flags & DC_EXEC) { /* * Set the orders of the vehicle. Cannot do it earlier as we need * the vehicle refitted before doing this, otherwise the moved * cargo types might not match (passenger vs non-passenger) */ DoCommand(0, w_front->index | (p2 & 1 ? CO_SHARE : CO_COPY) << 30, v_front->index, flags, CMD_CLONE_ORDER); /* Now clone the vehicle's name, if it has one. */ if (v_front->name != NULL) CloneVehicleName(v_front, w_front); } /* Since we can't estimate the cost of cloning a vehicle accurately we must * check whether the company has enough money manually. */ if (!CheckCompanyHasMoney(total_cost)) { if (flags & DC_EXEC) { /* The vehicle has already been bought, so now it must be sold again. */ DoCommand(w_front->tile, w_front->index | 1 << 20, 0, flags, GetCmdSellVeh(w_front)); } return total_cost; } return total_cost; }
double Genetic::fitvalue(const Answer & answer) { double dist = total_cost(answer); return 1.0 / dist; }
/** * Terraform land * @param tile tile to terraform * @param flags for this command type * @param p1 corners to terraform (SLOPE_xxx) * @param p2 direction; eg up (non-zero) or down (zero) * @param text unused * @return the cost of this operation or an error */ CommandCost CmdTerraformLand(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { _terraform_err_tile = INVALID_TILE; CommandCost total_cost(EXPENSES_CONSTRUCTION); int direction = (p2 != 0 ? 1 : -1); TerraformerState ts; /* Compute the costs and the terraforming result in a model of the landscape */ if ((p1 & SLOPE_W) != 0 && tile + TileDiffXY(1, 0) < MapSize()) { TileIndex t = tile + TileDiffXY(1, 0); CommandCost cost = TerraformTileHeight(&ts, t, TileHeight(t) + direction); if (cost.Failed()) return cost; total_cost.AddCost(cost); } if ((p1 & SLOPE_S) != 0 && tile + TileDiffXY(1, 1) < MapSize()) { TileIndex t = tile + TileDiffXY(1, 1); CommandCost cost = TerraformTileHeight(&ts, t, TileHeight(t) + direction); if (cost.Failed()) return cost; total_cost.AddCost(cost); } if ((p1 & SLOPE_E) != 0 && tile + TileDiffXY(0, 1) < MapSize()) { TileIndex t = tile + TileDiffXY(0, 1); CommandCost cost = TerraformTileHeight(&ts, t, TileHeight(t) + direction); if (cost.Failed()) return cost; total_cost.AddCost(cost); } if ((p1 & SLOPE_N) != 0) { TileIndex t = tile + TileDiffXY(0, 0); CommandCost cost = TerraformTileHeight(&ts, t, TileHeight(t) + direction); if (cost.Failed()) return cost; total_cost.AddCost(cost); } /* Check if the terraforming is valid wrt. tunnels, bridges and objects on the surface * Pass == 0: Collect tileareas which are caused to be auto-cleared. * Pass == 1: Collect the actual cost. */ for (int pass = 0; pass < 2; pass++) { for (std::set<TileIndex>::const_iterator it = ts.dirty_tiles.begin(); it != ts.dirty_tiles.end(); it++) { TileIndex tile = *it; assert(tile < MapSize()); /* MP_VOID tiles can be terraformed but as tunnels and bridges * cannot go under / over these tiles they don't need checking. */ if (IsTileType(tile, MP_VOID)) continue; /* Find new heights of tile corners */ int z_N = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 0)); int z_W = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 0)); int z_S = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 1)); int z_E = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 1)); /* Find min and max height of tile */ int z_min = min(min(z_N, z_W), min(z_S, z_E)); int z_max = max(max(z_N, z_W), max(z_S, z_E)); /* Compute tile slope */ Slope tileh = (z_max > z_min + 1 ? SLOPE_STEEP : SLOPE_FLAT); if (z_W > z_min) tileh |= SLOPE_W; if (z_S > z_min) tileh |= SLOPE_S; if (z_E > z_min) tileh |= SLOPE_E; if (z_N > z_min) tileh |= SLOPE_N; if (pass == 0) { /* Check if bridge would take damage */ if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) { int bridge_height = GetBridgeHeight(GetSouthernBridgeEnd(tile)); /* Check if bridge would take damage. */ if (direction == 1 && bridge_height <= z_max) { _terraform_err_tile = tile; ///< highlight the tile under the bridge return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); } /* Is the bridge above not too high afterwards? * @see tunnelbridge.h for a detailed discussion. */ if (direction == -1 && bridge_height > (z_min + MAX_BRIDGE_HEIGHT)) { _terraform_err_tile = tile; return_cmd_error(STR_ERROR_BRIDGE_TOO_HIGH_AFTER_LOWER_LAND); } } /* Check if tunnel would take damage */ if (direction == -1 && IsTunnelInWay(tile, z_min)) { _terraform_err_tile = tile; // highlight the tile above the tunnel return_cmd_error(STR_ERROR_EXCAVATION_WOULD_DAMAGE); } } /* Is the tile already cleared? */ const ClearedObjectArea *coa = FindClearedObject(tile); bool indirectly_cleared = coa != NULL && coa->first_tile != tile; /* Check tiletype-specific things, and add extra-cost */ const bool curr_gen = _generating_world; if (_game_mode == GM_EDITOR) _generating_world = true; // used to create green terraformed land DoCommandFlag tile_flags = flags | DC_AUTO | DC_FORCE_CLEAR_TILE; if (pass == 0) { tile_flags &= ~DC_EXEC; tile_flags |= DC_NO_MODIFY_TOWN_RATING; } CommandCost cost; if (indirectly_cleared) { cost = DoCommand(tile, 0, 0, tile_flags, CMD_LANDSCAPE_CLEAR); } else { cost = _tile_type_procs[GetTileType(tile)]->terraform_tile_proc(tile, tile_flags, z_min, tileh); } _generating_world = curr_gen; if (cost.Failed()) { _terraform_err_tile = tile; return cost; } if (pass == 1) total_cost.AddCost(cost); } } Company *c = Company::GetIfValid(_current_company); if (c != NULL && (int)GB(c->terraform_limit, 16, 16) < ts.tile_to_new_height.size()) { return_cmd_error(STR_ERROR_TERRAFORM_LIMIT_REACHED); } if (flags & DC_EXEC) { /* change the height */ { for (std::map<TileIndex, int>::const_iterator it = ts.tile_to_new_height.begin(); it != ts.tile_to_new_height.end(); it++) { TileIndex tile = it->first; int height = it->second; SetTileHeight(tile, (uint)height); } } /* finally mark the dirty tiles dirty */ { MarkTilesDirty(ts); } if (c != NULL) c->terraform_limit -= ts.tile_to_new_height.size() << 16; } return total_cost; }
/** * Terraform the north corner of a tile to a specific height. * * @param ts TerraformerState. * @param tile Tile. * @param height Aimed height. * @return Error code or cost. */ static CommandCost TerraformTileHeight(TerraformerState *ts, TileIndex tile, int height) { assert(tile < MapSize()); /* Check range of destination height */ if (height < 0) return_cmd_error(STR_ERROR_ALREADY_AT_SEA_LEVEL); if (height > _settings_game.construction.max_heightlevel) return_cmd_error(STR_ERROR_TOO_HIGH); /* * Check if the terraforming has any effect. * This can only be true, if multiple corners of the start-tile are terraformed (i.e. the terraforming is done by towns/industries etc.). * In this case the terraforming should fail. (Don't know why.) */ if (height == TerraformGetHeightOfTile(ts, tile)) return CMD_ERROR; /* Check "too close to edge of map". Only possible when freeform-edges is off. */ uint x = TileX(tile); uint y = TileY(tile); if (!_settings_game.construction.freeform_edges && ((x <= 1) || (y <= 1) || (x >= MapMaxX() - 1) || (y >= MapMaxY() - 1))) { /* * Determine a sensible error tile */ if (x == 1) x = 0; if (y == 1) y = 0; _terraform_err_tile = TileXY(x, y); return_cmd_error(STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP); } /* Mark incident tiles that are involved in the terraforming. */ TerraformAddDirtyTileAround(ts, tile); /* Store the height modification */ TerraformSetHeightOfTile(ts, tile, height); CommandCost total_cost(EXPENSES_CONSTRUCTION); /* Increment cost */ total_cost.AddCost(_price[PR_TERRAFORM]); /* Recurse to neighboured corners if height difference is larger than 1 */ { const TileIndexDiffC *ttm; TileIndex orig_tile = tile; static const TileIndexDiffC _terraform_tilepos[] = { { 1, 0}, // move to tile in SE {-2, 0}, // undo last move, and move to tile in NW { 1, 1}, // undo last move, and move to tile in SW { 0, -2} // undo last move, and move to tile in NE }; for (ttm = _terraform_tilepos; ttm != endof(_terraform_tilepos); ttm++) { tile += ToTileIndexDiff(*ttm); if (tile >= MapSize()) continue; /* Make sure we don't wrap around the map */ if (Delta(TileX(orig_tile), TileX(tile)) == MapSizeX() - 1) continue; if (Delta(TileY(orig_tile), TileY(tile)) == MapSizeY() - 1) continue; /* Get TileHeight of neighboured tile as of current terraform progress */ int r = TerraformGetHeightOfTile(ts, tile); int height_diff = height - r; /* Is the height difference to the neighboured corner greater than 1? */ if (abs(height_diff) > 1) { /* Terraform the neighboured corner. The resulting height difference should be 1. */ height_diff += (height_diff < 0 ? 1 : -1); CommandCost cost = TerraformTileHeight(ts, tile, r + height_diff); if (cost.Failed()) return cost; total_cost.AddCost(cost); } } } return total_cost; }