Skip to content

Commit

Permalink
Merge pull request #2 from patsonluk/master
Browse files Browse the repository at this point in the history
update
  • Loading branch information
Bohaska authored Aug 16, 2022
2 parents fbd7deb + 6693f14 commit 31aea5c
Showing 82 changed files with 2,601 additions and 1,438 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -25,6 +25,11 @@ Version 2 alpha at https://v2.airline-club.com
11. Open another terminal, navigate to `airline-web`, run the web server by `activator run`
12. The application should be accessible at `localhost:9000`

## Banners
Self notes, too much trouble for other people to set it up right now. Just do NOT enable the banner. (disabled by default, to enable change `bannerEnabled` in `application.conf`

For the banners to work properly, need to setup google photo API. Download the oauth json and put it under airline-web/conf. Then run the app, the log should show an oauth url, use it, then it should generate a token under airline-web/google-tokens. Now for server deployment, copy the oauth json `google-oauth-credentials.json` to `conf` AND the google-tokens (as folder) to the root of `airline-web`.


## Attribution
Some icons by [Yusuke Kamiyamane](http://p.yusukekamiyamane.com/). Licensed under a [Creative Commons Attribution 3.0 License](http://creativecommons.org/licenses/by/3.0/)
4 changes: 4 additions & 0 deletions airline-data/db_scripts/issue485_patch.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
DELETE FROM link WHERE transport_type <> 0;

ALTER TABLE `airline_v2`.`link`
DROP FOREIGN KEY `link_ibfk_3`;
8 changes: 8 additions & 0 deletions airline-data/db_scripts/patch_airline_modifer.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
ALTER TABLE `airline_modifier` ADD INDEX `modifier_airline` (`airline` ASC) VISIBLE;

ALTER TABLE `airline_modifier` DROP INDEX `PRIMARY`;
ALTER TABLE `airline_modifier` ADD `id` INT PRIMARY KEY NOT NULL AUTO_INCREMENT FIRST;


REPLACE INTO `airline_modifier_property`(id, name, value) SELECT o.id, "DURATION", 52 FROM `airline_modifier` o WHERE o.modifier_name = "DELEGATE_BOOST";
REPLACE INTO `airline_modifier_property`(id, name, value) SELECT o.id, "STRENGTH", 3 FROM `airline_modifier` o WHERE o.modifier_name = "DELEGATE_BOOST";
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE `airline_v2`.`link_consumption`
ADD COLUMN `transport_type` TINYINT NULL AFTER `duration`;
2 changes: 2 additions & 0 deletions airline-data/db_scripts/patch_log.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE `log` ADD `id` INT PRIMARY KEY NOT NULL AUTO_INCREMENT FIRST;

18 changes: 9 additions & 9 deletions airline-data/src/main/scala/com/patson/AirlineSimulation.scala
Original file line number Diff line number Diff line change
@@ -26,7 +26,7 @@ object AirlineSimulation {
val allAirlines = AirlineSource.loadAllAirlines(true)
val allLinks = LinkSource.loadAllLinks(LinkSource.FULL_LOAD)
val allFlightLinksByAirlineId = allLinks.filter(_.transportType == TransportType.FLIGHT).map(_.asInstanceOf[Link]).groupBy(_.airline.id)
val allShuttleLinksByAirlineId = allLinks.filter(_.transportType == TransportType.SHUTTLE).map(_.asInstanceOf[Shuttle]).groupBy(_.airline.id)
//val allShuttleLinksByAirlineId = allLinks.filter(_.transportType == TransportType.SHUTTLE).map(_.asInstanceOf[Shuttle]).groupBy(_.airline.id)
val allTransactions = AirlineSource.loadTransactions(cycle).groupBy { _.airlineId }
val allTransactionalCashFlowItems: scala.collection.immutable.Map[Int, List[AirlineCashFlowItem]] = AirlineSource.loadCashFlowItems(cycle).groupBy { _.airlineId }
//purge the older transactions
@@ -44,7 +44,7 @@ object AirlineSimulation {
loungesByAirlineId.getOrElseUpdate(lounge.airline.id, ListBuffer[Lounge]()) += lounge
)

val shuttleServicesByAirlineId = AirlineSource.loadShuttleServiceByCriteria(List.empty).groupBy(_.airline.id)
//val shuttleServicesByAirlineId = AirlineSource.loadShuttleServiceByCriteria(List.empty).groupBy(_.airline.id)

val allIncomes = ListBuffer[AirlineIncome]()
val allCashFlows = ListBuffer[AirlineCashFlow]() //cash flow for accounting purpose
@@ -191,14 +191,14 @@ object AirlineSimulation {
othersSummary.put(OtherIncomeItemType.LOUNGE_INCOME, loungeIncome)


var shuttleCost = 0L
allShuttleLinksByAirlineId.get(airline.id).foreach { links =>
shuttleCost = links.map(_.upkeep).sum
}
shuttleCost += shuttleServicesByAirlineId.getOrElse(airline.id, List.empty).map(_.basicUpkeep).sum
othersSummary.put(OtherIncomeItemType.SHUTTLE_COST, -1 * shuttleCost)
// var shuttleCost = 0L
// allShuttleLinksByAirlineId.get(airline.id).foreach { links =>
// shuttleCost = links.map(_.upkeep).sum
// }
// shuttleCost += shuttleServicesByAirlineId.getOrElse(airline.id, List.empty).map(_.basicUpkeep).sum
// othersSummary.put(OtherIncomeItemType.SHUTTLE_COST, -1 * shuttleCost)

totalCashExpense += loungeUpkeep + loungeCost + shuttleCost
totalCashExpense += loungeUpkeep + loungeCost
totalCashRevenue += loungeIncome

//calculate extra cash flow due to difference in fuel cost
15 changes: 1 addition & 14 deletions airline-data/src/main/scala/com/patson/AirplaneSimulation.scala
Original file line number Diff line number Diff line change
@@ -103,9 +103,6 @@ object AirplaneSimulation {
val secondHandAirplanes = ListBuffer[Airplane]()
val fundsExhaustedAirlineIds = mutable.HashSet[Int]()

val discountsByAirlineId = ModelSource.loadAllAirlineDiscounts().view.mapValues(_.groupBy(_.modelId))
val discountsByModelId = ModelSource.loadAllModelDiscounts().groupBy(_.modelId)

val updatingAirplanes = airplanes //this contains airplanes from all airlines
.sortBy(_.condition) //lowest conditional airplane gets renewal first
.map { airplane =>
@@ -120,17 +117,7 @@ object AirplaneSimulation {

val originalModel = airplane.model

val discounts = ListBuffer[ModelDiscount]()
discountsByAirlineId.get(airlineId).foreach { airlineDiscountsByModelId => //airline specific discounts
airlineDiscountsByModelId.get(originalModel.id).foreach { airlineDiscounts =>
discounts.appendAll(airlineDiscounts)
}
}
discountsByModelId.get(originalModel.id).foreach { modelDiscounts =>
discounts.appendAll(modelDiscounts)
}

val adjustedModel = originalModel.applyDiscount(discounts.toList)
val adjustedModel = originalModel.applyDiscount(ModelDiscount.getCombinedDiscountsByModelId(airlineId, originalModel.id))
val renewCost = adjustedModel.price - sellValue
val newCost = existingCost + renewCost
val newBuyPlane = existingBuyPlane + adjustedModel.price
62 changes: 59 additions & 3 deletions airline-data/src/main/scala/com/patson/AirportSimulation.scala
Original file line number Diff line number Diff line change
@@ -3,10 +3,11 @@ package com.patson
import java.util.Random
import com.patson.data._
import com.patson.model._
import com.patson.util.{AirlineCache, AirportCache, ChampionUtil}
import com.patson.util.{AirlineCache, AirportCache, AirportChampionInfo, ChampionUtil}

import scala.collection.{MapView, immutable, mutable}
import scala.collection.mutable.{ListBuffer, Map, Set}
import scala.math.BigDecimal.RoundingMode

object AirportSimulation {
val AWARENESS_DECAY = 0.1
@@ -122,6 +123,56 @@ object AirportSimulation {
baseCycle + delta * LOYALIST_HISTORY_SAVE_INTERVAL
}

def processChampionInfoChanges(previousInfo : List[AirportChampionInfo], newInfo : List[AirportChampionInfo], currentCycle : Int) = {
val previousInfoByAirlineId : Predef.Map[Int, List[AirportChampionInfo]] = previousInfo.groupBy(_.loyalist.airline.id)
val newInfoByAirlineId : Predef.Map[Int, List[AirportChampionInfo]] = newInfo.groupBy(_.loyalist.airline.id)

val airlineIds = previousInfoByAirlineId.keySet ++ newInfoByAirlineId.keySet
val logs = ListBuffer[Log]()
airlineIds.foreach { airlineId =>
val changes = ListBuffer[ChampionInfoChange]()
previousInfoByAirlineId.get(airlineId) match {
case Some(previousRanks) =>
newInfoByAirlineId.get(airlineId) match {
case Some(newRanks) => //go from airport to airport
val previousInfoByAirport = previousRanks.groupBy(_.loyalist.airport).view.mapValues(_(0)) //should be exactly one entry
val newInfoByAirport = newRanks.groupBy(_.loyalist.airport).view.mapValues(_(0)) //should be exactly one entry
val airportIds = previousInfoByAirport.keySet ++ newInfoByAirport.keySet
airportIds.foreach { airportId =>
if (previousInfoByAirport.get(airportId).map(_.ranking).getOrElse(0) != newInfoByAirport.get(airportId).map(_.ranking).getOrElse(0)) {
changes.append(ChampionInfoChange(previousInfoByAirport.get(airportId), newInfoByAirport.get(airportId)))
}
}
case None => changes.appendAll(previousRanks.map(info => ChampionInfoChange(Some(info), None))) //lost all ranks
}
case None => changes.appendAll(newInfoByAirlineId(airlineId).map(info => ChampionInfoChange(None, Some(info)))) //all ranks are new
}
val airline = AirlineCache.getAirline(airlineId, false).getOrElse(Airline.fromId(airlineId))

logs.appendAll(changes.map {
case ChampionInfoChange(Some(previousRank), Some(newRank)) =>
val reputationChange = BigDecimal.valueOf(newRank.reputationBoost - previousRank.reputationBoost).setScale(2, RoundingMode.HALF_UP)
val displayChange =
if (reputationChange >= 0) {
"+" + reputationChange
} else {
reputationChange.toString
}
Log(airline, s"${newRank.loyalist.airport.displayText} ranking ${previousRank.ranking} -> ${newRank.ranking}. Reputation change $displayChange", LogCategory.AIRPORT_RANK_CHANGE, LogSeverity.INFO, currentCycle, immutable.Map("airportId" -> newRank.loyalist.airport.id.toString))
case ChampionInfoChange(None, Some(newRank)) =>
Log(airline, s"${newRank.loyalist.airport.displayText} new ranking ${newRank.ranking}. Reputation change +${BigDecimal.valueOf(newRank.reputationBoost).setScale(2, RoundingMode.HALF_UP)}", LogCategory.AIRPORT_RANK_CHANGE, LogSeverity.INFO, currentCycle, immutable.Map("airportId" -> newRank.loyalist.airport.id.toString))
case ChampionInfoChange(Some(previousRank), None) =>
Log(airline, s"${previousRank.loyalist.airport.displayText} lost ranking ${previousRank.ranking}. Reputation change -${BigDecimal.valueOf(previousRank.reputationBoost).setScale(2, RoundingMode.HALF_UP)}", LogCategory.AIRPORT_RANK_CHANGE, LogSeverity.INFO, currentCycle, immutable.Map("airportId" -> previousRank.loyalist.airport.id.toString))
case _ => //should not happen
Log(airline, s"Unknown rank change", LogCategory.AIRPORT_RANK_CHANGE, LogSeverity.INFO, currentCycle)
})
}
println(s"Ranking changes count : ${logs.size}")
LogSource.insertLogs(logs.toList)
}
case class ChampionInfoChange(previousRank : Option[AirportChampionInfo], newRank : Option[AirportChampionInfo])


def simulateLoyalists(allAirports : List[Airport], linkRidershipDetails : immutable.Map[(PassengerGroup, Airport, Route), Int], cycle : Int) = {
val existingLoyalistByAirportId : immutable.Map[Int, List[Loyalist]] = LoyalistSource.loadLoyalistsByCriteria(List.empty).groupBy(_.airport.id)
val (updatingLoyalists,deletingLoyalists) = computeLoyalists(allAirports, linkRidershipDetails, existingLoyalistByAirportId)
@@ -135,7 +186,12 @@ object AirportSimulation {
println(s"Computing loyalist info with ${allLoyalists.length} entries")

//compute champion info
ChampionUtil.updateAirportChampionInfo(allLoyalists)
val previousInfo = ChampionUtil.loadAirportChampionInfo()
val newInfo = ChampionUtil.computeAirportChampionInfo(allLoyalists)
processChampionInfoChanges(previousInfo, newInfo, cycle)
AirportSource.updateChampionInfo(newInfo)


println("Done computing champions")

if (cycle % LOYALIST_HISTORY_SAVE_INTERVAL == 0) {
@@ -278,7 +334,7 @@ object AirportSimulation {
println("Checking lounge status")
val passengersByAirport : MapView[Airport, MapView[Airline, Int]] = linkRidershipDetails.toList.flatMap {
case ((passengerGroup, airport, route), count) =>
route.links.flatMap { linkConsideration =>
route.links.filter(_.link.transportType == TransportType.FLIGHT).flatMap { linkConsideration =>
List((linkConsideration.link.airline, linkConsideration.from, count), (linkConsideration.link.airline, linkConsideration.to, count))
}

Original file line number Diff line number Diff line change
@@ -207,7 +207,7 @@ object DemandGenerator {
val income = fromAirport.income

val firstClassPercentage : Double =
if (flightType == LONG_HAUL_INTERNATIONAL || flightType == MEDIUM_HAUL_INTERCONTINENTAL || flightType == LONG_HAUL_INTERCONTINENTAL || flightType == ULTRA_LONG_HAUL_INTERCONTINENTAL || flightType == MEDIUM_HAUL_DOMESTIC || flightType == LONG_HAUL_DOMESTIC || flightType == SHORT_HAUL_INTERNATIONAL || flightType == MEDIUM_HAUL_INTERNATIONAL) {
if (flightType == LONG_HAUL_INTERNATIONAL || flightType == MEDIUM_HAUL_INTERCONTINENTAL || flightType == SHORT_HAUL_INTERCONTINENTAL || flightType == LONG_HAUL_INTERCONTINENTAL || flightType == ULTRA_LONG_HAUL_INTERCONTINENTAL || flightType == MEDIUM_HAUL_DOMESTIC || flightType == LONG_HAUL_DOMESTIC || flightType == SHORT_HAUL_INTERNATIONAL || flightType == MEDIUM_HAUL_INTERNATIONAL) {
if (income <= FIRST_CLASS_INCOME_MIN) {
0
} else if (income >= FIRST_CLASS_INCOME_MAX) {
Loading

0 comments on commit 31aea5c

Please sign in to comment.