ui calculator

This commit is contained in:
Ilia Denisov
2026-03-30 19:38:24 +02:00
committed by GitHub
parent 17f366cd6b
commit a7793f5416
37 changed files with 2046 additions and 270 deletions
+3
View File
@@ -0,0 +1,3 @@
module galaxy/calc
go 1.26.0
+13
View File
@@ -0,0 +1,13 @@
package calc
func ShipProductionCost(shipEmptyMass float64) float64 {
return shipEmptyMass * 10.
}
func PlanetProduceShipMass(L, Mat, Res float64) float64 {
result := L / 10
if result <= Mat {
return result
}
return (L + Mat/Res) / (10 + 1/Res)
}
+85
View File
@@ -0,0 +1,85 @@
package calc
import "math"
// Эффективность двигателя -
// равна мощности Двигателей, умноженной на технологический уровень блока Двигателей
func DriveEffective(drive, driveTech float64) float64 {
return drive * driveTech
}
// Масса перевозимого груза -
// общее количество единиц груза, деленное на технологический уровень Грузоперевозок
func CarryingMass(load, cargoTech float64) float64 {
if load <= 0 {
return 0
}
return load / cargoTech
}
// Грузоподъёмность одного корабля
func CargoCapacity(cargo, cargoTech float64) float64 {
return cargoTech * (cargo + (cargo*cargo)/20)
}
// Корабли перемещаются за один ход на количество световых лет, равное
// эффективности двигателя, умноженной на 20 и деленной на "Полную массу" корабля
func Speed(driveEffective, fullMass float64) float64 {
if fullMass <= 0 {
return 0
}
return driveEffective * 20 / fullMass
}
// Полная масса -
// массу корабля самого по себе плюс масса перевозимого груза
func FullMass(emptyMass, carryingMass float64) float64 {
return emptyMass + carryingMass
}
func EmptyMass(drive, weapons float64, armament uint, shields, cargo float64) (float64, bool) {
wm, ok := WeaponsBlockMass(weapons, armament)
if !ok {
return 0, false
}
return drive + shields + cargo + wm, true
}
func WeaponsBlockMass(weapons float64, armament uint) (float64, bool) {
if (armament == 0 && weapons != 0) || (armament != 0 && weapons == 0) {
return 0, false
}
return float64(armament+1) * (weapons / 2), true
}
func DestructionProbability(
attackingWeapons,
attackingWeaponsTech,
defendingShields,
defendingShiledsTech,
defendingFullMass float64,
) float64 {
return DestructionProbabilityEffective(
EffectiveAttack(attackingWeapons, attackingWeaponsTech),
EffectiveDefence(defendingShields, defendingShiledsTech, defendingFullMass),
)
}
func DestructionProbabilityEffective(effectiveAttack, effectiveDefence float64) float64 {
return (math.Log10(effectiveAttack/effectiveDefence)/math.Log10(4) + 1) / 2
}
func EffectiveAttack(weapons, weaponsTech float64) float64 {
return weapons * weaponsTech
}
func EffectiveDefence(
defendingShields,
defendingShiledsTech,
defendingFullMass float64,
) float64 {
if defendingFullMass <= 0 {
return 0
}
return defendingShields * defendingShiledsTech / math.Pow(defendingFullMass, 1./3.) * math.Pow(30., 1./3.)
}
+34
View File
@@ -0,0 +1,34 @@
package calc
import (
e "galaxy/error"
)
func ValidateShipTypeValues(d float64, a int, w, s, c float64) error {
if !CheckShipTypeValueDWSC(d) {
return e.NewDriveValueError(d)
}
if !CheckShipTypeValueDWSC(w) {
return e.NewWeaponsValueError(w)
}
if !CheckShipTypeValueDWSC(s) {
return e.NewShieldsValueError(s)
}
if !CheckShipTypeValueDWSC(c) {
return e.NewCargoValueError(s)
}
if a < 0 {
return e.NewShipTypeArmamentValueError(a)
}
if (w == 0 && a > 0) || (a == 0 && w > 0) {
return e.NewShipTypeArmamentAndWeaponsValueError("A=%d W=%.0f", a, w)
}
if d == 0 && w == 0 && s == 0 && c == 0 && a == 0 {
return e.NewShipTypeShipTypeZeroValuesError()
}
return nil
}
func CheckShipTypeValueDWSC(v float64) bool {
return v == 0 || v >= 1
}
+7
View File
@@ -41,6 +41,13 @@ type State struct {
ClientNextVersion *string `json:"clientNextVersion,omitempty"`
GameState []GameState `json:"gameState,omitempty"`
ActiveGameID *GameID `json:"activeGameId,omitempty"`
CameraZoom float64 `json:"cameraZoom"`
CameraXFp int `json:"cameraXFp"`
CameraYFp int `json:"cameraYFp"`
MapSplitterOffset float64 `json:"mapSplitterOffset"`
AccordionInfoOpen bool `json:"accInfoOpen"`
AccordionCalcOpen bool `json:"accCalcOpen"`
}
type GameState struct {
+23
View File
@@ -128,6 +128,15 @@ func (s *fsStorage) SaveStateAsync(state client.State, callback func(error)) {
}()
}
func (s *fsStorage) ReportExistsAsync(id client.GameID, turn uint, callback func(bool, error)) {
go func() {
exists, err := s.gameDataExistsSync(id, turn)
if callback != nil {
callback(exists, err)
}
}()
}
func (s *fsStorage) LoadReportAsync(id client.GameID, turn uint, callback func(report.Report, error)) {
go func() {
rep, err := s.loadReportSync(id, turn)
@@ -343,6 +352,20 @@ func (s *fsStorage) saveOrderSync(id client.GameID, turn uint, o order.Order) er
}))
}
func (s *fsStorage) gameDataExistsSync(id client.GameID, turn uint) (bool, error) {
absPath, err := s.resolvePath(gameTurnFilePath(id, turn))
if err != nil {
return false, classifyStorageError(err)
}
exists, err := s.fileExistsUnlocked(absPath)
if err != nil {
return false, classifyStorageError(err)
}
return exists, nil
}
func (s *fsStorage) loadGameDataSync(id client.GameID, turn uint) (client.GameData, error) {
absPath, err := s.resolvePath(gameTurnFilePath(id, turn))
if err != nil {
+5
View File
@@ -36,6 +36,11 @@ type UIStorage interface {
// I/O or encoding error may occur, it that case callback func will be called with non-nil error.
SaveStateAsync(client.State, func(error))
// ReportExistsAsync asynchronously checks whether given [model.GameID] and turn number exists in the Storage.
// Passed callback func will will accept non-nil error in case of I/O or decoding errors occuried,
// otherwise callback func accepts boolean result.
ReportExistsAsync(client.GameID, uint, func(bool, error))
// LoadReportAsync loads a [report.Report] for a given [model.GameID] and turn number from filesystem asynchronously.
// Passed callback func will will accept non-nil error in case of I/O or decoding errors occuried,
// otherwise callback func accepts loaded [report.Report].