Bläddra i källkod

d05 Добавление апгрейда и построек

SVI 2 år sedan
förälder
incheckning
ede474e240

+ 1 - 1
pkg/components/scene_net/netclient/netclient.go

@@ -49,7 +49,7 @@ func (сам *NetClient) Get(strLink string) (lstString []string, err error) {
 	сам.block.Lock()
 	defer сам.block.Unlock()
 	// if strLink == "https://wartank.ru/production/Mine" {
-		log.Printf("NetClient.Get(): link=%v\n", strLink)
+	log.Printf("NetClient.Get(): link=%v\n", strLink)
 	// }
 	ctxCancel, fnCancel := context.WithTimeout(сам.botNet.Кнт(), time.Second*10)
 	defer fnCancel()

+ 3 - 0
server/serv_bots/warbot/angar/base/arsenal/arsenal.go

@@ -425,6 +425,9 @@ func (сам *Оружейная) сделатьБронебойки() bool {
 	стрВых = lstArsenal[инд+10]
 	// Получить ссылку на бронебойные
 	lstArmor := strings.Split(стрВых, `<a class="simple-but border" href="`)
+	if len(lstArmor) == 0 {
+		return true // Считаем, что производство уже запущено
+	}
 	strLink := lstArmor[1]
 	lstArmor = strings.Split(strLink, `"><span><span>Начать производство</span></span></a>`)
 	strLink = "https://wartank.ru/production/" + lstArmor[0]

+ 106 - 1
server/serv_bots/warbot/angar/base/fuel/fuel.go

@@ -173,10 +173,115 @@ func (сам *СкладТоплива) уровеньОбновить() bool {
 		return false
 	}
 	сам.уровень.Уст(иУровень)
-	if иУровень == 0 { // склад топлива надо построить
+	switch иУровень {
+	case 0: // склад топлива надо построить
 		for !сам.построить() {
 		}
+	default: // Может можно проапгрейдить
+		счёт := 5
+		for !сам.проапгрейдить() {
+			счёт--
+			if счёт == 0 {
+				break
+			}
+		}
+	}
+
+	return true
+}
+
+// Пытается проапгрейдить топливный склад
+func (сам *СкладТоплива) проапгрейдить() bool {
+	time.Sleep(time.Millisecond * 1000)
+	var (
+		еслиНайти = false
+		списСтр   []string
+		стр       = ""
+		ош        error
+	)
+	фнКупить := func() bool {
+		defer time.Sleep(time.Millisecond * 1000)
+		списСтр, ош = сам.сеть.Клиент().Get("https://wartank.ru/building-upgrade/FuelStorage")
+		if ош != nil {
+			log.Printf("СкладТоплива.проапгрейдить().фнКупить(): при GET-команде 'купить постройку склада топлива', err=\n\t%v\n", ош)
+			return false
+		}
+		for _, стр = range списСтр {
+			// <a class="simple-but border mb5" href="FuelStorage?5-1.ILinkListener-upgradeLink-link">
+			if strings.Contains(стр, `ILinkListener-upgradeLink-link`) {
+				еслиНайти = true
+				break
+			}
+		}
+		if !еслиНайти {
+			return true
+		}
+		// Пробуем улучшить шахту
+		_стр := strings.TrimPrefix(стр, "<a class=\"simple-but border mb5\" href=\"")
+		_стр = strings.TrimSuffix(_стр, "\">")
+		// https://wartank.ru/building-upgrade/FuelStorage?4-1.ILinkListener-upgradeLink-link
+		// <a class="simple-but border mb5" href="FuelStorage?50-1.ILinkListener-upgradeLink-link">
+		ссылка := "https://wartank.ru/building-upgrade/" + _стр
+		списСтр, ош = сам.сеть.Клиент().Get(ссылка)
+		if ош != nil {
+			log.Printf("СкладТоплива.проапгрейдить().фнКупить(): при GET-команде 'купить постройку склада топлива', err=\n\t%v\n", ош)
+			return false
+		}
+		// Проверить, что постройка состоялась
+		for _, стр := range списСтр {
+			if strings.Contains(стр, "ILinkListener-upgradeLink-link") {
+				log.Printf("СкладТоплива.проапгрейдить().фнКупить(): покупка склада топлива не прошла\n\tlink=%v\n\tстр=\n\t%v\n", ссылка, стр)
+				return false // Покупка не оплачена
+			}
+		}
+		log.Printf("+++++СкладТоплива.проапгрейдить().фнКупить(): покупка склада топлива прошла\n")
+		return true
 	}
+
+	фнПодтверждение := func() bool {
+		for _, стр = range списСтр {
+			// <a class="simple-but border w50 mXa mb10" w:id="confirmLink" href="../wicket/page?7-1.ILinkListener-confirmLink"><span><span>да, подтверждаю</span></span></a>
+			if strings.Contains(стр, `ILinkListener-confirmLink`) {
+				еслиНайти = true
+				break
+			}
+		}
+		if !еслиНайти {
+			return true
+		}
+		// Пробуем построить шахту
+		_стр := strings.TrimPrefix(стр, `<a class="simple-but border w50 mXa mb10" w:id="confirmLink" href="..`)
+		_стр = strings.TrimSuffix(_стр, `"><span><span>да, подтверждаю</span></span></a>`)
+		// https://wartank.ru/wicket/page?6-1.ILinkListener-confirmLink
+		ссылка := "https://wartank.ru" + _стр
+		списСтр, ош = сам.сеть.Клиент().Get(ссылка)
+		if ош != nil {
+			log.Printf("СкладТоплива.проапгрейдить().фнПодтверждение(): при GET-команде 'подтвердить постройку склада топлива', err=\n\t%v\n", ош)
+			return false
+		}
+		// Проверить, что постройка состоялась
+		for _, стр := range списСтр {
+			if strings.Contains(стр, "<title>Вы сделали слишком большую паузу</title>") {
+				log.Printf("СкладТоплива.проапгрейдить().фнПодтверждение(): подтверждение покупка склада топлива не прошла\n\tlink=%v\n\tстр=\n\t%v\n", ссылка, стр)
+				return false // Покупка не оплачена
+			}
+		}
+		log.Printf("+++++СкладТоплива.проапгрейдить().фнПодтверждение(): подтверждение покупка склада топлива прошла\n")
+		return true
+	}
+
+	фнКомплекс := func() {
+		count := 5
+		for count > 0 {
+			if фнКупить() {
+				if фнПодтверждение() {
+					break
+				}
+			}
+			count--
+		}
+	}
+	фнКомплекс()
 	return true
 }
 

+ 281 - 13
server/serv_bots/warbot/angar/base/market/market.go

@@ -3,6 +3,7 @@ package market
 import (
 	"fmt"
 	"log"
+	"strconv"
 	"strings"
 	"time"
 
@@ -10,6 +11,7 @@ import (
 	"wartank/pkg/section"
 	"wartank/pkg/types"
 	"wartank/server/serv_bots/warbot/angar/base/market/marketnet"
+	"wartank/server/serv_bots/warbot/tank/tankstat/static_param"
 )
 
 /*
@@ -19,8 +21,9 @@ import (
 // Рынок -- объект рынка
 type Рынок struct {
 	*section.Секция
-	бот  types.ИБот
-	сеть *marketnet.MarketNet
+	бот     types.ИБот
+	сеть    *marketnet.MarketNet
+	уровень types.ИСтатПарам
 }
 
 // НовРынок -- возвращает новый рынок
@@ -29,9 +32,14 @@ func НовРынок(база types.ИБаза) (*Рынок, error) {
 	if err != nil {
 		return nil, fmt.Errorf("NewMarket(): in create *Section, err=\n\t%w", err)
 	}
+	уровень, ош := static_param.НовСтатПарам("уровень")
+	if ош != nil {
+		return nil, fmt.Errorf("НовРынок(): при создании статистики уровня, ош=\n\t%w", ош)
+	}
 	сам := &Рынок{
-		Секция: section,
-		бот:    база.Бот(),
+		Секция:  section,
+		бот:     база.Бот(),
+		уровень: уровень,
 	}
 	{ // Маркет
 		сам.сеть, err = marketnet.NewMarketNet(сам)
@@ -50,23 +58,283 @@ func (сам *Рынок) Пуск() error {
 
 // выполняет опрос рынка базы, должен работать как горутина
 func (сам *Рынок) пуск() {
-	time.Sleep(time.Second * 25)
+	time.Sleep(time.Second * 7)
+	фнРабота := func() {
+		defer time.Sleep(time.Minute * 30)
+		for !сам.уровеньОбновить() {
+		}
+		сам.ускорениеПровер()
+		сам.проверОжидание()
+		for сам.купитьЗолото() {
+		}
+	}
 	for {
 		select {
 		case <-сам.бот.Кнт().Done():
 			return
-		case <-сам.ВремяОстат().КаналСиг():
-			log.Printf("Market.run(): timeCount=%v\n", сам.ВремяОстат().ПолучМилСек())
-			_ = сам.купитьЗолото()
-			// Если золото не куплено -- обновить время ожидания
-			сам.Секция.ОбратВремяУст("02:00")
+		default:
+			фнРабота()
 		}
-		сам.проверОжидание()
-		for сам.купитьЗолото() {
+	}
+}
+
+// Проверяет ускорение строительства
+func (сам *Рынок) ускорениеПровер() {
+	списСтр, ош := сам.сеть.Клиент().Get("http://wartank.ru/buildings")
+	if ош != nil {
+		log.Printf("Рынок.ускорениеПровер(): in make request, err=\n\t%v\n", ош)
+		return
+	}
+	// <span class="green2">Склад топлива -
+	var (
+		еслиНайти = false
+		стр       = ""
+	)
+	for _, стр = range списСтр {
+		if strings.Contains(стр, `<span class="green2">Склад топлива - `) {
+			еслиНайти = true
+			break
+		}
+	}
+	if !еслиНайти {
+		return
+	}
+}
 
+// Обновляет текущий уровень рынка (может быть не построен)
+func (сам *Рынок) уровеньОбновить() bool {
+	списСтр, ош := сам.сеть.Клиент().Get("http://wartank.ru/buildings")
+	if ош != nil {
+		log.Printf("Рынок.уровеньОбновить(): in make request, err=\n\t%v\n", ош)
+		return false
+	}
+	// <span class="green2">Рынок -
+	var (
+		еслиНайти = false
+		стр       = ""
+	)
+	for _, стр = range списСтр {
+		if strings.Contains(стр, `<span class="green2">Рынок -`) {
+			еслиНайти = true
+			break
 		}
-		time.Sleep(time.Minute * 10)
 	}
+	if !еслиНайти {
+		return false
+	}
+	// <span class="green2">Рынок - 0</span><br/>
+	_стр := strings.TrimPrefix(стр, `<span class="green2">Рынок - `)
+	_стр = strings.TrimSuffix(_стр, `</span><br/>`)
+	иУровень, ош := strconv.Atoi(_стр)
+	if ош != nil {
+		log.Printf("Рынок.уровеньОбновить(): строка уровня сбойная, стр=%q, ош=\n\t%v\n", стр, ош)
+		return false
+	}
+	сам.уровень.Уст(иУровень)
+	switch иУровень {
+	case 0: // рынок надо построить
+		for !сам.построить() {
+		}
+	default: // Может можно проапгрейдить
+		счёт := 5
+		for !сам.проапгрейдить() {
+			счёт--
+			if счёт >= 0 {
+				break
+			}
+		}
+	}
+
+	return true
+}
+
+// Строит шахту при нулевом уровне
+func (сам *Рынок) построить() bool {
+	time.Sleep(time.Millisecond * 1000)
+	// <td style="width:50%;padding-left:1px;"><a class="simple-but border mb5" href="building-upgrade/Market"><span><span>Построить</span></span></a></td>
+	var (
+		еслиНайти = false
+		списСтр   []string
+		стр       = ""
+		ош        error
+	)
+	фнКупить := func() bool {
+		defer time.Sleep(time.Millisecond * 1000)
+		списСтр, ош = сам.сеть.Клиент().Get("https://wartank.ru/building-upgrade/Market")
+		if ош != nil {
+			log.Printf("Рынок.построить().фнКупить(): при GET-команде 'купить постройку склада топлива', err=\n\t%v\n", ош)
+			return false
+		}
+		for _, стр = range списСтр {
+			// <a class="simple-but border mb5" href="Market?19-1.ILinkListener-upgradeLink-link">
+			if strings.Contains(стр, `ILinkListener-upgradeLink-link`) {
+				еслиНайти = true
+				break
+			}
+		}
+		if !еслиНайти {
+			return true
+		}
+		// Пробуем построить шахту
+		_стр := strings.TrimPrefix(стр, "<a class=\"simple-but border mb5\" href=\"")
+		_стр = strings.TrimSuffix(_стр, "\">")
+		// https://wartank.ru/building-upgrade/Market?18-1.ILinkListener-upgradeLink-link
+		// <a class="simple-but border mb5" href="Market?19-1.ILinkListener-upgradeLink-link">
+		ссылка := "https://wartank.ru/building-upgrade/" + _стр
+		списСтр, ош = сам.сеть.Клиент().Get(ссылка)
+		if ош != nil {
+			log.Printf("Рынок.построить().фнКупить(): при GET-команде 'купить постройку склада топлива', err=\n\t%v\n", ош)
+			return false
+		}
+		// Проверить, что постройка состоялась
+		for _, стр := range списСтр {
+			if strings.Contains(стр, "ILinkListener-upgradeLink-link") {
+				log.Printf("Рынок.построить().фнКупить(): покупка склада топлива не прошла\n\tlink=%v\n\tстр=\n\t%v\n", ссылка, стр)
+				return false // Покупка не оплачена
+			}
+		}
+		log.Printf("+++++Рынок.построить().фнКупить(): покупка склада топлива прошла\n")
+		return true
+	}
+
+	фнПодтверждение := func() bool {
+		for _, стр = range списСтр {
+			// <a class="simple-but border w50 mXa mb10" w:id="confirmLink" href="../wicket/page?21-1.ILinkListener-confirmLink"><span><span>да, подтверждаю</span></span></a>
+			if strings.Contains(стр, `ILinkListener-confirmLink`) {
+				еслиНайти = true
+				break
+			}
+		}
+		if !еслиНайти {
+			return true
+		}
+		// Пробуем построить шахту
+		_стр := strings.TrimPrefix(стр, `<a class="simple-but border w50 mXa mb10" w:id="confirmLink" href="..`)
+		_стр = strings.TrimSuffix(_стр, `"><span><span>да, подтверждаю</span></span></a>`)
+		// https://wartank.ru/wicket/page?20-1.ILinkListener-confirmLink
+		ссылка := "https://wartank.ru" + _стр
+		списСтр, ош = сам.сеть.Клиент().Get(ссылка)
+		if ош != nil {
+			log.Printf("Рынок.построить().фнПодтверждение(): при GET-команде 'подтвердить постройку склада топлива', err=\n\t%v\n", ош)
+			return false
+		}
+		// Проверить, что постройка состоялась
+		for _, стр := range списСтр {
+			if strings.Contains(стр, "<title>Вы сделали слишком большую паузу</title>") {
+				log.Printf("Рынок.построить().фнПодтверждение(): подтверждение покупка склада топлива не прошла\n\tlink=%v\n\tстр=\n\t%v\n", ссылка, стр)
+				return false // Покупка не оплачена
+			}
+		}
+		log.Printf("+++++Рынок.построить().фнПодтверждение(): подтверждение покупка склада топлива прошла\n")
+		return true
+	}
+
+	фнКомплекс := func() {
+		for {
+			if фнКупить() {
+				if фнПодтверждение() {
+					break
+				}
+			}
+		}
+	}
+	фнКомплекс()
+	return true
+}
+
+// Пытается проапгрейдить топливный склад
+func (сам *Рынок) проапгрейдить() bool {
+	time.Sleep(time.Millisecond * 1000)
+	var (
+		еслиНайти = false
+		списСтр   []string
+		стр       = ""
+		ош        error
+	)
+	фнКупить := func() bool {
+		defer time.Sleep(time.Millisecond * 1000)
+		списСтр, ош = сам.сеть.Клиент().Get("https://wartank.ru/building-upgrade/Market")
+		if ош != nil {
+			log.Printf("Рынок.проапгрейдить().фнКупить(): при GET-команде 'купить постройку рынка', err=\n\t%v\n", ош)
+			return false
+		}
+		for _, стр = range списСтр {
+			// <a class="simple-but border mb5" href="Market?5-1.ILinkListener-upgradeLink-link">
+			if strings.Contains(стр, `ILinkListener-upgradeLink-link`) {
+				еслиНайти = true
+				break
+			}
+		}
+		if !еслиНайти {
+			return true
+		}
+		// Пробуем улучшить шахту
+		_стр := strings.TrimPrefix(стр, "<a class=\"simple-but border mb5\" href=\"")
+		_стр = strings.TrimSuffix(_стр, "\">")
+		// https://wartank.ru/building-upgrade/Market?4-1.ILinkListener-upgradeLink-link
+		// <a class="simple-but border mb5" href="Market?50-1.ILinkListener-upgradeLink-link">
+		ссылка := "https://wartank.ru/building-upgrade/" + _стр
+		списСтр, ош = сам.сеть.Клиент().Get(ссылка)
+		if ош != nil {
+			log.Printf("Рынок.проапгрейдить().фнКупить(): при GET-команде 'купить постройку рынка', err=\n\t%v\n", ош)
+			return false
+		}
+		// Проверить, что постройка состоялась
+		for _, стр := range списСтр {
+			if strings.Contains(стр, "ILinkListener-upgradeLink-link") {
+				log.Printf("Рынок.проапгрейдить().фнКупить(): покупка рынка не прошла\n\tlink=%v\n\tстр=\n\t%v\n", ссылка, стр)
+				return false // Покупка не оплачена
+			}
+		}
+		log.Printf("+++++Рынок.проапгрейдить().фнКупить(): покупка рынка прошла\n")
+		return true
+	}
+
+	фнПодтверждение := func() bool {
+		for _, стр = range списСтр {
+			// <a class="simple-but border w50 mXa mb10" w:id="confirmLink" href="../wicket/page?7-1.ILinkListener-confirmLink"><span><span>да, подтверждаю</span></span></a>
+			if strings.Contains(стр, `ILinkListener-confirmLink`) {
+				еслиНайти = true
+				break
+			}
+		}
+		if !еслиНайти {
+			return true
+		}
+		// Пробуем построить шахту
+		_стр := strings.TrimPrefix(стр, `<a class="simple-but border w50 mXa mb10" w:id="confirmLink" href="..`)
+		_стр = strings.TrimSuffix(_стр, `"><span><span>да, подтверждаю</span></span></a>`)
+		// https://wartank.ru/wicket/page?6-1.ILinkListener-confirmLink
+		ссылка := "https://wartank.ru" + _стр
+		списСтр, ош = сам.сеть.Клиент().Get(ссылка)
+		if ош != nil {
+			log.Printf("Рынок.проапгрейдить().фнПодтверждение(): при GET-команде 'подтвердить постройку рынка', err=\n\t%v\n", ош)
+			return false
+		}
+		// Проверить, что постройка состоялась
+		for _, стр := range списСтр {
+			if strings.Contains(стр, "<title>Вы сделали слишком большую паузу</title>") {
+				log.Printf("Рынок.проапгрейдить().фнПодтверждение(): подтверждение покупка рынка не прошла\n\tlink=%v\n\tстр=\n\t%v\n", ссылка, стр)
+				return false // Покупка не оплачена
+			}
+		}
+		log.Printf("+++++Рынок.проапгрейдить().фнПодтверждение(): подтверждение покупка склада топлива прошла\n")
+		return true
+	}
+
+	фнКомплекс := func() {
+		count := 5
+		for count > 0 {
+			if фнКупить() {
+				if фнПодтверждение() {
+					break
+				}
+			}
+			count--
+		}
+	}
+	фнКомплекс()
+	return true
 }
 
 // Проверяет  время ожидания рынка

+ 13 - 25
web/tmpl/add_bot.tmpl.html

@@ -1,31 +1,19 @@
 {{ define "add_bot" }}
 {{ template "header" . }}
 Страница добавления бота вартанк.
-<form action="/api/add_bot" method="POST">
-    <div class="container border rounded">
-        <div class="row border rounded">
-            <div class="col-3">
-                <label>Логин бота:</label>
-            </div>
-            <div class="col">
-                <input class="w-100" type="text" name="login_bot" placeholder="login_bot">
-            </div>
-        </div>
-        <div class="row border rounded">
-            <div class="col-3">
-                <label>Пароль бота:</label>
-            </div>
-            <div class="col">
-                <input class="w-100" type="text" name="password_bot" placeholder="password_bot">
-            </div>
-        </div>
-        <div class="row">
-            <div class="col-9">
-            </div>
-            <div class="col text-end">
-                <input class="btn btn-primary" type="submit" value="Добавить">
-            </div>
-        </div>
+<form action="/api/add_bot" method="POST" class="container border rounded">
+    <div class="row p-3">
+        <label for="login_bot" class="col-2 form-label text-right">Логин бота:</label>
+        <input class="col form-control" type="text" name="login_bot" id="login_bot" placeholder="login_bot">
+    </div>
+    <div class="row p-3">
+        <label for="password_bot" class="col-2 form-label text-right">Пароль бота:</label>
+        <input class="col form-control" type="password" name="password_bot" id="password_bot"
+            placeholder="password_bot">
+    </div>
+    <div class="row p-3">
+        <label class="col form-label text-right"></label>
+        <input class="col-2 btn btn-primary" type="submit" value="Добавить">
     </div>
 </form>
 {{ if .err }}

+ 15 - 7
web/tmpl/index.tmpl.html

@@ -3,18 +3,26 @@
 Стартовая страница игры вартанк.
 
 <!-- Форма логина -->
-<form action="/api/login" method="POST">
-    <label for="login">Логин:</label>
-    <input type="text" id="login" name="login"><br><br>
+<form action="/api/login" method="POST" class="container border rounded">
+    <div class="row p-3">
+        <label for="login" class="col-2 form-label text-right">Логин:</label>
+        <input type="text" id="login" name="login" id="login" class="col form-control" placeholder="admin"><br><br>
+    </div>
 
-    <label for="password">Пароль:</label>
-    <input type="password" id="password" name="password"><br><br>
+    <div class="row p-3">
+        <label for="password" class="col-2 form-label">Пароль:</label>
+        <input type="password" id="password" name="password" class="col form-control text-right"
+            placeholder="12345"><br><br>
+    </div>
 
-    <input type="submit" value="Вход">
+    <div class="row p-3">
+        <label class="col">:</label>
+        <input type="submit" class="col-2 btn btn-primary" value="Вход">
+    </div>
 </form>
 
 {{ if .err }}
-    <p>{{ .err }}</p>
+<p>{{ .err }}</p>
 {{ end }}
 
 {{ template "footer" . }}

+ 0 - 3
web/tmpl/list_bot.tmpl.html

@@ -2,9 +2,6 @@
 <!-- web/tmpl/list_bot.tmpl.html -->
 {{ template "header" . }}
 <h1>Страница списка ботов вартанк</h1>
-{{$lenBots:= len .bots}}
-{{printf "len %s" .lenBots}}<br>
-{{printf "bots: %s" .bots}}<br>
 {{ range $key, $name := .bots }}
 <div>
     <a href="/gui/bot/{{ $name }}/state">{{ $name }}</a><br><br>

+ 55 - 92
web/tmpl/state_bot.tmpl.html

@@ -2,112 +2,75 @@
 {{ template "header" . }}
 <h1>Страница состояния бота вартанк</h1>
 <p class="border rounded"><span class="badge bg-secondary">Имя:</span> {{.имя}}</p>
-<div class="container-fluid">
+<div class="container m-3 d-flex flex-wrap border rounded">
     <!-- глобальная статистика -->
-    <div class="row bg-success bg-gradient text-white  my-1">
-        <div class="col">
-            <span class="badge bg-dark border rounded">Золото:</span> {{.золото}}
+    <div class="card border-primary m-3">
+        <div class="card-header">
+            <h3>Статистика</h3>
         </div>
-        <div class="col">
-            <span class="badge bg-dark border rounded">Серебро:</span> {{.серебро}}
-        </div>
-        <div class="col">
-            <span class="badge bg-dark border rounded">Топливо:</span> {{.топливо}}
-        </div>
-        <div class="col">
-            <span class="badge bg-dark border rounded">Слава:</span> {{.слава}}
+        <div class="card-body">
+            <p class="card-text">Золото: {{.золото}}</p>
+            <p class="card-text">Серебро: {{.серебро}}</p>
+            <p class="card-text">Топливо: {{.топливо}}</p>
+            <p class="card-text">Слава: {{.слава}}</p>
         </div>
     </div>
     <!-- статистика силы танка -->
-    <div class="row bg-success bg-gradient text-white">
-        <div class="col">
-            <span class="badge bg-dark border rounded">Атака:</span> {{.атака}}
-        </div>
-        <div class="col">
-            <span class="badge bg-dark border rounded">Броня:</span> {{.броня}}
-        </div>
-        <div class="col">
-            <span class="badge bg-dark border rounded">Точность:</span> {{.точность}}
+    <div class="card border-primary m-3">
+        <div class="card-header">
+            <h3>Сила танка</h3>
         </div>
-        <div class="col">
-            <span class="badge bg-dark border rounded">Прочность:</span> {{.прочность}}
+        <div class="card-body">
+            <p class="card-text">Атака: {{.атака}}</p>
+            <p class="card-text">Броня: {{.броня}}</p>
+            <p class="card-text">Точность: {{.точность}}</p>
+            <p class="card-text">Прочность: {{.прочность}}</p>
         </div>
+        <div class="card-footer border-success">Танковая мощь: {{.мощь}}</div>
     </div>
-</div>
-<p class="border rounded"><span class="badge bg-secondary">Танковая мощь:</span> {{.мощь}}</p>
 
-<!-- статистика по шахте-->
-<div class="container-fluid bg-dark text-white rounded">
-    <h2>Шахта</h2>
-</div>
-<div class="container-fluid">
-    <div class="row bg-success bg-gradient text-white  my-1">
-        <div class="col">
-            <span class="badge bg-dark border rounded">Уровнеь:</span> {{.шахта_уровень}}
-        </div>
-        <div class="col">
-            <span class="badge bg-dark border rounded">Режим:</span> {{.шахта_режим}}
-        </div>
-        <div class="col">
-            <span class="badge bg-dark border rounded">Кол:</span> {{.шахта_сделать_кол}}
-        </div>
-        <div class="col">
-            <span class="badge bg-dark border rounded">Тип:</span> {{.шахта_сделать_назв}}
-        </div>
-        <div class="col">
-            <span class="badge bg-dark border rounded">Время:</span> {{.шахта_сделать_время}}
-        </div>
+    <!-- статистика по шахте-->
+    <div class="card border-primary m-3">
+        <div class="card-header">
+            <h3>Шахта</h3>
+        </div>
+        <div class="card-body">
+            <p class="card-text">Уровнеь: {{.шахта_уровень}}</p>
+            <p class="card-text">Режим: {{.шахта_режим}}</p>
+            <p class="card-text">Кол: {{.шахта_сделать_кол}}</p>
+            <p class="card-text">Тип: {{.шахта_сделать_назв}}</p>
+        </div>
+        <div class="card-footer border-success">Время: {{.шахта_сделать_время}}</div>
     </div>
-</div>
-
 
-<!-- статистика по полигону--><br>
-<div class="container-fluid bg-dark text-white rounded">
-    <h2>Полигон</h2>
-</div>
-<div class="container-fluid">
-    <div class="row bg-success bg-gradient text-white  my-1">
-        <div class="col">
-            <span class="badge bg-dark border rounded">Уровнеь:</span> {{.полигон_уровень}}
-        </div>
-        <div class="col">
-            <span class="badge bg-dark border rounded">Режим:</span> {{.полигон_режим}}
-        </div>
-        <div class="col">
-            <span class="badge bg-dark border rounded">Кол:</span> {{.полигон_сделать_кол}}
-        </div>
-        <div class="col">
-            <span class="badge bg-dark border rounded">Тип:</span> {{.полигон_сделать_назв}}
-        </div>
-        <div class="col">
-            <span class="badge bg-dark border rounded">Время:</span> {{.полигон_сделать_время}}
-        </div>
+    <!-- статистика по полигону-->
+    <div class="card border-primary m-3">
+        <div class="card-header">
+            <h3>Полигон</h3>
+        </div>
+        <div class="card-body">
+            <p class="card-text">Уровнеь: {{.полигон_уровень}}</p>
+            <p class="card-text">Режим: {{.полигон_режим}}</p>
+            <p class="card-text">Кол: {{.полигон_сделать_кол}}</p>
+            <p class="card-text">Тип: {{.полигон_сделать_назв}}</p>
+        </div>
+        <div class="card-footer border-success">Время: {{.полигон_сделать_время}}</div>
     </div>
-</div>
-
 
-<!-- статистика по оружейной--><br>
-<div class="container-fluid bg-dark text-white rounded">
-    <h2>Оружейная</h2>
-</div>
-<div class="container-fluid">
-    <div class="row bg-success bg-gradient text-white  my-1">
-        <div class="col">
-            <span class="badge bg-dark border rounded">Работа:</span> {{.оружейная_работа}}
-        </div>
-        <div class="col">
-            <span class="badge bg-dark border rounded">Режим:</span> {{.оружейная_режим}}
-        </div>
-        <div class="col">
-            <span class="badge bg-dark border rounded">Кумул:</span> {{.оружейная_кумул}}
-        </div>
-        <div class="col">
-            <span class="badge bg-dark border rounded">Ремки:</span> {{.оружейная_ремки}}
-        </div>
-        <div class="col">
-            <span class="badge bg-dark border rounded">Время:</span> {{.оружейная_время}}
-        </div>
+    <!-- статистика по оружейной-->
+    <div class="card border-primary m-3">
+        <div class="card-header">
+            <h3>Оружейная</h3>
+        </div>
+        <div class="card-body">
+            <p class="card-text">Работа: {{.оружейная_работа}}</p>
+            <p class="card-text">Режим: {{.оружейная_режим}}</p>
+            <p class="card-text">Кумул: {{.оружейная_кумул}}</p>
+            <p class="card-text">Ремки: {{.оружейная_ремки}}</p>
+        </div>
+        <div class="card-footer border-success">Время: {{.оружейная_время}}</div>
     </div>
 </div>
+
 {{ template "footer" . }}
 {{end}}