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;
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