• Here's a proposed solution. I've broken it up into stages using #temp tables which can be read for the purpose of verifying the results.

    IF OBJECT_ID('tempdb..#FirstChoice') IS NOT NULL DROP TABLE #FirstChoice;

    IF OBJECT_ID('tempdb..#SecondChoice') IS NOT NULL DROP TABLE #SecondChoice;

    IF OBJECT_ID('tempdb..#RemainingPitches') IS NOT NULL DROP TABLE #RemainingPitches;

    IF OBJECT_ID('tempdb..#RemainingPunters') IS NOT NULL DROP TABLE #RemainingPunters;

    IF OBJECT_ID('tempdb..#TheChosenOnes') IS NOT NULL DROP TABLE #TheChosenOnes

    -- Fill a small pot from a big table of hopefuls

    SELECT TOP(800)

    FirewoodLottery_id,

    Choice1,

    Choice2

    INTO #TheChosenOnes

    FROM [survey].[FirewoodLottery]

    ORDER BY NEWID()

    -- Allocate as many first choices as possible

    SELECT

    Choice = 1,

    t.FirewoodTowns_id,

    t.town,

    t.Permits,

    PermitsLeft = t.Permits - COUNT(*) OVER(PARTITION BY t.town),

    x.FirewoodLottery_id

    INTO #FirstChoice

    FROM survey.FirewoodTowns t

    CROSS APPLY ( -- randomly pick folks for available pitches

    SELECT TOP(t.Permits)

    l.FirewoodLottery_id

    FROM #TheChosenOnes l

    WHERE l.Choice1 = t.town -- first choice

    ORDER BY NEWID()

    ) x

    ORDER BY t.town;

    -- What pitches remain after first allocation?

    SELECT DISTINCT

    t.FirewoodTowns_id,

    t.town,

    t.Permits,

    PermitsLeft = ISNULL(PermitsLeft,t.Permits)

    INTO #RemainingPitches

    FROM survey.FirewoodTowns t

    LEFT JOIN #FirstChoice f ON f.FirewoodTowns_id = t.FirewoodTowns_id

    WHERE ISNULL(PermitsLeft,t.Permits) > 0

    -- What remains of the chosen ones after the first allocation?

    SELECT

    l.FirewoodLottery_id,

    l.Choice2

    INTO #RemainingPunters

    FROM #TheChosenOnes l

    WHERE NOT EXISTS (SELECT 1 FROM #FirstChoice f WHERE f.FirewoodLottery_id = l.FirewoodLottery_id)

    -- Allocate any remaining pitches as second choices

    SELECT

    Choice = 2,

    t.FirewoodTowns_id,

    t.town,

    Permits = t.Permits,

    PermitsLeft = t.PermitsLeft - COUNT(*) OVER(PARTITION BY t.town),

    x.FirewoodLottery_id

    INTO #SecondChoice

    FROM #RemainingPitches t

    CROSS APPLY ( -- randomly pick from remaining punters

    SELECT TOP(t.PermitsLeft)

    l.FirewoodLottery_id

    FROM #RemainingPunters l

    WHERE l.Choice2 = t.town -- second choice

    ORDER BY NEWID()

    ) x

    ORDER BY t.town;

    -- Results

    SELECT *

    FROM #FirstChoice

    UNION ALL

    SELECT *

    FROM #SecondChoice

    ORDER BY

    FirewoodTowns_ID,

    Choice,

    FirewoodLottery_id;

    “Write the query the simplest way. If through testing it becomes clear that the performance is inadequate, consider alternative query forms.” - Gail Shaw

    For fast, accurate and documented assistance in answering your questions, please read this article.
    Understanding and using APPLY, (I) and (II) Paul White
    Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden