sjasogun1 schreef: ↑di 11 sep 2012, 19:03
Deze 10 teams spelen 10 spellen tegen elkaar, dus er staan 2 teams per spel. De helft van de spellen blijft dus altijd onbezet.
Code: Selecteer alles
import qualified Data.Map as Map
import Data.List
-- size of the grid
size = 10
-- get a solution from the solutionTree. Due to laziness of Haskell this will not construct the entire tree (only the part that is required for a solution).
solution = getSolution solutionTree
-- create a map that represents the start of the solution. This start calls the first game that player 1 plays game 1, the second game 2, etc.
-- The opponent that player 1 plays in round 2 and on is called player n where n is the round number. Player 1 plays against player 2 twice.
startMap :: (Map.Map (Integer, Integer) Integer)
startMap = Map.fromList (((2,1),1) :( [((k,k),k)| k <- [1..size]] ++ [((1,k),k)| k <- [1..size]]))
-- create a tree to hold all possible solutions
data Tree = Node (Map.Map (Integer, Integer) Integer) [Tree]
deriving (Eq, Show)
solutionTree = Node startMap (createSubNodes startMap)
-- At each node, for the grid generated so far, find the first empty space (start at the top left, search row by row). For that empty space generate
-- all possible branches. An possibility always has two empty spaces: the current empty space and one for the opponent.
createSubNodes m | fullMap m = []
| otherwise = filter validNode [Node nm cs | a <- options m r c, let nm = insertOptions m a, let cs = (createSubNodes nm)]
where
(r,c) = firstEmptySpace m
insertOptions m (r,c,a,v) = Map.insert (a,c) v (Map.insert (r,c) v m) -- insert the options into the grid
firstEmptySpace m = fes m 2 3
where
fes m r c | c > size = fes m (r+1) 1
| r > size = (r, c)
| Map.lookup (r,c) m == Nothing = (r,c)
| otherwise = fes m r (c+1)
-- an option contains the empty space at (r,c) and another empty space (a,c) below it.
-- a possible pair is not an option if:
-- * space (r,c) and (a,c) cannot have the same value.
-- * player r and/or player a already plays against some player twice and this option would also make player r play player a twice.
options m r c = [(r,c,a,v) | a <- ((rowsOfEmpties m c) \\ [r]), v <- (intersect (validValue m r c) (validValue m a c)), ((matchesInRows m r a) == 0) || (((matchesInRows m r a) == 1) && (isAllowed m r a))]
where
isAllowed m r a = ((length (filter (>1) (matchesWithOther m r))) == 0) && ((length (filter (>1) (matchesWithOther m a))) == 0) -- check whether player r and/or player a already plays another player twice.
where
matchesWithOther m r = [matchesInRows m r a | a <- [1..size], r /= a]
-- Return all values that are possible for (r,c) in m. A value is not possible if:
-- * (r,c) already contains a value.
-- * it is equal to any number that is in the row r
-- * it is equal to any number that is in the column c
-- * it is in the rows of all empty spaces in column c
validValue m r c | lu == Nothing = (([1..size] \\ (rowNumbers m r)) \\ (columnNumbers m c)) \\ (foldl1 (intersect) (map (\a -> rowNumbers m a) ((rowsOfEmpties m c) \\ [r])))
| otherwise = []
where
lu = Map.lookup (r,c) m
rowNumbers m r = filter (/= 0) $ map (\c -> replaceMaybe (Map.lookup (r,c) m)) [1..size] -- get all (nonzero) numbers already entered in row r.
columnNumbers m c = filter (/= 0) $ map (\r -> replaceMaybe (Map.lookup (r,c) m)) [1..size] -- get all (nonzero) numbers already entered in column c
-- get all rows that have no number entered in column c
rowsOfEmpties m c = filter (\a -> Nothing == Map.lookup (a,c) m) [1..size]
-- Count how often row r1 and r2 match.
matchesInRows m r1 r2 = mir q w
where
q = map (\a -> replaceMaybe (Map.lookup (r1,a) m)) [1..size]
w = map (\a -> replaceMaybe (Map.lookup (r2,a) m)) [1..size]
mir [] [] = 0
mir (q:qs) (w:ws) | (q == w) && (q /= 0) = 1 + (mir qs ws)
| otherwise = mir qs ws
-- a Node is valid if
-- it has a full map (which must be valid due to inserting rules)
-- or it has (valid) Nodes in its Node List.
validNode (Node m ts) = (fullMap m) || ([] /= ts)
fullMap m = (size*size) == (fromIntegral $ Map.size m)
-- convert the map with the grid to a list.
extractFromMap m = [map (\a -> replaceMaybe (Map.lookup (r,a) m)) [1..size] | r <- [1..size]]
-- extract the (most left) solution which is under the given Node.
getSolution (Node m ts) | fullMap m = extractFromMap m
| ts == [] = []
| otherwise = getSolution' (head ts)
where
getSolution' (Node m ts) | ts == [] = extractFromMap m
| otherwise = getSolution' (head ts)
-- just a function to get rid of the Maybe from Map.lookup
replaceMaybe k | k == Nothing = 0
| otherwise = n
where
Just n = k