Skip to content
hajo4 edited this page Feb 23, 2014 · 3 revisions

Challenge-map TinyTown1, for testing AIs.

-- TinyTown1.lua - HaJo Gurt - 2014-02-23

local Prog="MapMaker-TinyTown1"
local dbg=1

--[[
Generate challenge-maps for trAInsported (maps for a single AI)

History:
2014-02-21      Original from: SmallTown5.lua
2014-02-22      first version - map 4x3
2014-02-23      some cleanup

For documentation see:
* http://trainsportedgame.no-ip.org/maps.php
* https://github.com/Germanunkol/trAInsported/blob/master/MakingMaps.md
]]--


function myPrint(dbgLevel, ...)
        if dbg >= dbgLevel then  print(...)  end
end


local ch = {}

--ch.name = "TinyTestTown-1"
ch.version = "4"                -- req. version of trAInsported

ch.maxTrains  =  1
ch.startMoney = 25      -- 1 train costs 25

-- ##### ##### ##### ##### ##### ##### ##### ##### #####

local mapAuthor = "hajo4  2014-02-22"
local mapDescr  = "TinyTown1 - small map 5x3 (quick rendering) for testing AIs."

ch.name = "TinyTestTown-1"
ch.maxTrains, ch.startMoney = 3, 25

--[[
local maxX, maxY = 5, 4
local _mapT1 =  
        "CSccc" ..
        "C.c--" ..
        "C.cHc" ..
        "CCCCC"

local _mapT2 =  
        "CCccc" ..
        "CScWH" ..
        "CCcHc" ..
        "CHcCC"
]]--

local maxX, maxY = 4, 3
local _mapT3 =  
        "CCCc" ..
        "CHCS" ..
        "CCCc"
        
local _map =    
        "cccC" ..
        "cScH" ..
        "cccC"
--       ....+....1....+....2

-- 5x3 map has 1 house, 1 hotspot, 1 loop, 2 deadends.
-- 6 passengers are created to allow 2 trains to operate.
-- The map can be done in less than 60s.

local passengersRemaining, passengersCreated  = 6, false
local maxTime = 120
maxTime = 100           -- Map with 6 passengers: can be done in less than 60s 

--[[ Times for some AIs:
 AI_Rechenknecht_v2: 55s / hardToBeat3: 55 / Stupid-Fixed: 56s / solAIr_rc31: 56 / winKI_v2: 56s / 
 Marvin2: 59s / czAI20: 59s / testAI3: 59s / Optimum_S: 60s / drAIsine_III: 61 / Vertrauter: 62s / 
 Optimax: 64-66s / Fiete_02: 67s / buerokrat_120: 69s / Quetzal1000: 77s / Dragon_09: 80s / 
 GarchaKing: 80s / taxiDriver: 85s / Geselle: 87s-89s / NinjAI_2: 94s / BigIron3: 98s-100s /

 Teilebahn-3: 57 / bernie3: 64s / BigIron2: 67s / Better_PF: 68s / PaziFist: 71s / schondoof: 71 / 
 mops: 72s / RUR: 73s / WybeJunior: 75s / agentOrange: 82s / WybeJungster: 82s / Cecelia: 83s / 
 AI2: 85s / UberLaser2060: 91s / sowiesodoof: 93s / Simple_PF: 94s / brAIndead/Cooper: 99s / 
 YUNOBringMeHome: 100s / Bethany: 103s / taxidrivingOverlord: loop / TestAI: loop / 

 Failed: derp_1: noStart /  CheapAIv3.1: loop / TrainBrain: loop / jfk2: 100s+ / MazeRunner_004: 111s /
]]--

local startupMessage = "Welcome to TinyTestTown!\n"..
        "Transport the people around in TinyTown.\n"..
        "You have " .. maxTime .. " seconds!"

-- ##### ##### ##### ##### ##### ##### ##### ##### #####

-- create a new, empty map with known dimensions:
ch.map = challenges.createEmptyMap(maxX, maxY)

-- fill in mapdata:

local x,y,b = 1,1,0
for p = 1, string.len(_map) do
        s = string.sub(_map, p,p)
        if s == "#" then s = "C" end
        if s == "c" then s = "C" end
        if s == "." then s = " " end
        if s == "-" then s = " " end
        if s == "_" then s = " " end

        -- 1x1 buildings: / see mapRenderPart.lua
        if s == "h" then s = "H" end
        if s == "M" then s = "CINEMA"     end
        if s == "W" then s = "STORE"      end
        if s == "B" then s = "BOOKSTORE"  end
        if s == "P" then s = "PIESTORE"   end
        if s == "p" then s = "PLAYGROUND" end

        -- 2x2 buildings:
        -- "SCHOOL" SCHOOL11,SCHOOL12,SCHOOL21,SCHOOL22 
        -- "HOSPITAL" 11,12, 21,22
        if s == "L" then s = "SCHOOL"     end
        if s == "+" then s = "HOSPITAL"   end

        -- 3x3 buildings:
        if s == "1" then s = "H" end
        if s == "X" then s = "HOUSE_1_LARGE_11" end
        if s == "x" then s = "HOUSE_1_LARGE_12" end

        if s == "Y" then s = "HOUSE_2_LARGE_11" end
        if s == "y" then s = "HOUSE_2_LARGE_12" end

        if s == "Z" then s = "HOUSE_3_LARGE_11" end
        if s == "z" then s = "HOUSE_3_LARGE_12" end
        if s == "3" then s = "HOUSE_3_LARGE_21" end

        if s == "Q" then s = "HOUSE_4_LARGE_11" end
        if s == "q" then s = "HOUSE_4_LARGE_12" end
        if s == "4" then s = "HOUSE_4_LARGE_21" end
        
        if s ~= " " then
                ch.map[x][y] = s
                b=b+1
        end
        if x >= maxX then
                x=1
                y=y+1
        else
                x=x+1
        end
end
myPrint(1,  "Map "..ch.name,  "ready:", maxX.."x"..maxY, b )
console.add("Map "..ch.name.." ready:"..maxX.."x"..maxY, colorGreen )

function directDistance(x1,y1, x2,y2)
        return math.sqrt( (x1-x2)^2 + (y1-y2)^2 )
end
function manhattanDistance(x1, y1, x2, y2)
        return math.abs(x1-x2) + math.abs(y1-y2)
end

function nearbyRail( x,y )
-- check where nearest rail is:
-- 0: tile at x,y is rail
-- 1: adjacent tile has rail (N,E,S,W)
-- 2: diagonally adjacent tile has rail (NE,NW,SE,SW)
-- 3: no rail in range

        if     ch.map[ x ][ y ] == "C" then return 0

        elseif ch.map[x+1][y  ] == "C" then return 1
        elseif ch.map[x-1][y  ] == "C" then return 1
        elseif ch.map[x  ][y+1] == "C" then return 1
        elseif ch.map[x  ][y-1] == "C" then return 1

        elseif ch.map[x+1][y+1] == "C" then return 2
        elseif ch.map[x+1][y-1] == "C" then return 2
        elseif ch.map[x-1][y+1] == "C" then return 2
        elseif ch.map[x-1][y-1] == "C" then return 2

        else return 3 end
end


function ch.start()
        challenges.setMessage(startupMessage)
        --clearConsole()
        --console.clear()
end


-- Colors for console-output:
local colorWhite = {r=255,g=255,b=255}
local colorGrey  = {r=128,g=128,b=128}
local colorGreen = {r=0,  g=255,b=0}

-- Watch the player:
function ch.newTrain(train)
        console.add("newTrain #"..train.ID, colorGreen )
        myPrint(1, "New train #"..train.ID.." created at:", train.x, train.y)
end

function ch.passengerBoarded(train, passenger)
        console.add("Train #"..train.ID.." picked up "..passenger.name, colorWhite )
        myPrint(1, "passengerBoarded:", train.ID)
end

function ch.passengerDroppedOff(train, psx)
        if train.tileX == psx.destX and train.tileY == psx.destY then           
                passengersRemaining = passengersRemaining - 1
                --console.add("passengersRemaining :"..passengersRemaining, {r=255,g=255,b=255})
                --myPrint(1, "passengersRemaining:", passengersRemaining)
        end
        console.add("Train #"..train.ID.." passengerDroppedOff ->"..passengersRemaining, colorWhite )
        myPrint(1, "passengerDroppedOff:", train.ID, psx.name, "->", passengersRemaining)

        challenges.removeMessage()      -- remove msgbox after first passenger is dropped off
end


function createPassengers()
--Todo: 
--provide several alternatives for creating passengers
--make some VIPs

        local psx, d,r, x,y, x1,y2, x1,y2, destX,destY, s

        myPrint(3,"# update: create passengers")
end

function ch.update(time)
-- This gets called every frame. 
-- Update the messagebox for remaining time, passengers etc.
-- and keep track of / generate passengers.

local psx, d,r, x,y, x1,y2, x1,y2, destX,destY
local s, timeLeft 

        if time > 3 and not passengersCreated then
                psx=0
--[[
                createPassengers()
                -- destX = 9    -- Location of warehouse as destination
                -- destY = 2
                -- passenger.new( x, y, destX, destY )
                -- passenger.new( 1, math.random(4) , 10, math.random(4) + 3 )

                -- put some psx at selected locations:

                --x1,y1       =  1, 1   -- fixed start-location of passenger
                --destX,destY =  6, 9   -- Location of destination (e.g. a store)

                x1,y1       = 10, 3     -- fixed start-location of passenger
                destX,destY =  3, 6     -- Location of destination (e.g. a store)

                r = 9
                while r>0 do
                        x2 = math.random(destX-1,destX+1)  -- area around destination
                        y2 = math.random(destY-1,destY+1)
                        r = nearbyRail( x2,y2 )
                        myPrint(5, "# nearbyRail: "..x2,y2, r )
                end
                psx=psx+1
                passenger.new( x1,y1, x2,y2 )
                myPrint(3, "### New passenger #".. psx..":", x1.."/"..y1, x2.."/"..y2 )
]]--
                -- fill up with psx from anywhere to anywhere
                while psx < passengersRemaining do
                        r = 9
                        while r>0 do
                                x = math.random(maxX)           -- whole map
                                y = math.random(maxY)
                                --x = math.random(2,maxX-1)     -- no destinations on outer ring
                                --y = math.random(2,maxY-1)

                                r = nearbyRail( x,y )
                                myPrint(5, "# nearbyRail: "..x,y, r )
                        end
                        x2,y2 = x,y

                        d,r = 0,9
                        while (d<1.4) or (r>0) do       -- ensure both spots are near rails,
                                                        -- and some minimum travel-distance apart
                                x = math.random(maxX)
                                y = math.random(maxY)
                                d = directDistance( x,y, x2,y2 )
                                r = nearbyRail( x,y )
                                myPrint(5, "## nearbyRail: "..x,y, r,d )
                        end
                        x1,y1 = x,y
                        psx=psx+1
                        passenger.new( x1,y1, x2,y2 )
                        myPrint(3, "### New passenger #".. psx..":", x1.."/"..y1, x2.."/"..y2 )
                end
                passengersCreated = true

        end

        timeLeft = math.floor(maxTime-time)
        challenges.setStatus("Map "..ch.name.." by "..mapAuthor.."\n" ..
                timeLeft .. " seconds remaining.\n" ..
                passengersRemaining .." passengers remaining.")

        if time > maxTime then
                console.add("game over: lost", colorGreen )
                myPrint(1, "# Game over: lost")
                return "lost", "Some passengers are still missing :-("
        end
        if passengersRemaining == 0 then
                --console.add("game over: won", colorGreen )            --??
                console.add("game over: won", {r=44,g=255,b=44} )
                myPrint(1, "# Game over: won")
                s = "ok"
                if     timeLeft > (maxTime*0.60) then s = "Incredible !"
                elseif timeLeft > (maxTime*0.50) then s = "Impressive !"
                elseif timeLeft > (maxTime*0.40) then s = "Excellent !"
                elseif timeLeft > (maxTime*0.30) then s = "Very good !"
                elseif timeLeft > (maxTime*0.20) then s = "Good !"
                elseif timeLeft > (maxTime*0.10) then s = "Well done !"
                elseif timeLeft > (maxTime*0.05) then s = "Just in time !"
                else                                  
                        s = "In the nick of time !"
                end
                --return "won", s       -- .."\n"..time.." / "..timeLeft.." / "..maxTime
                return "won", "Solved in "..time.."s of "..maxTime.."s\n"..s
        end

end

return ch

--.
Clone this wiki locally